From 1a57c7562002c4700867dee850eabfb58af66aa8 Mon Sep 17 00:00:00 2001 From: SoroushIMG Date: Mon, 15 Aug 2022 23:17:09 +0100 Subject: [PATCH] zink: Fix incorrect emission of SPIR-V shift ops SPIR-V shift ops unlike NIR have undefined behavior if shift count larger than or equalt to bitwidth. This means that true translation of NIR ishl/ishr/ushr to SPIR-V requires masking like that done in gallivm. This was seen in the case of soft fp64 in cts case KHR-GL46.gpu_shader_fp64.builtin.ceil_double. Cc: mesa-stable Reviewed-by: Georg Lehmann Part-of: (cherry picked from commit b386df918fd3274b3814c639ad7297f5b07cc48a) --- .pick_status.json | 2 +- .../drivers/zink/nir_to_spirv/nir_to_spirv.c | 20 ++++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/.pick_status.json b/.pick_status.json index 48e3c793cea..5494eb99e29 100644 --- a/.pick_status.json +++ b/.pick_status.json @@ -130,7 +130,7 @@ "description": "zink: Fix incorrect emission of SPIR-V shift ops", "nominated": true, "nomination_type": 0, - "resolution": 0, + "resolution": 1, "main_sha": null, "because_sha": null }, diff --git a/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c b/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c index 65f9c8c3b5d..71bae40cc76 100644 --- a/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c +++ b/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c @@ -2124,9 +2124,6 @@ emit_alu(struct ntv_context *ctx, nir_alu_instr *alu) BINOP(nir_op_fge, SpvOpFOrdGreaterThanEqual) BINOP(nir_op_feq, SpvOpFOrdEqual) BINOP(nir_op_fneu, SpvOpFUnordNotEqual) - BINOP(nir_op_ishl, SpvOpShiftLeftLogical) - BINOP(nir_op_ishr, SpvOpShiftRightArithmetic) - BINOP(nir_op_ushr, SpvOpShiftRightLogical) BINOP(nir_op_frem, SpvOpFRem) #undef BINOP @@ -2146,6 +2143,23 @@ emit_alu(struct ntv_context *ctx, nir_alu_instr *alu) BINOP_LOG(nir_op_ixor, SpvOpBitwiseXor, SpvOpLogicalNotEqual) #undef BINOP_LOG +#define BINOP_SHIFT(nir_op, spirv_op) \ + case nir_op: { \ + assert(nir_op_infos[alu->op].num_inputs == 2); \ + int shift_bit_size = nir_src_bit_size(alu->src[1].src); \ + nir_alu_type shift_nir_type = nir_alu_type_get_base_type(nir_op_infos[alu->op].input_types[1]); \ + SpvId shift_type = get_alu_type(ctx, shift_nir_type, num_components, shift_bit_size); \ + SpvId shift_mask = get_ivec_constant(ctx, shift_bit_size, num_components, bit_size - 1); \ + SpvId shift_count = emit_binop(ctx, SpvOpBitwiseAnd, shift_type, src[1], shift_mask); \ + result = emit_binop(ctx, spirv_op, dest_type, src[0], shift_count); \ + break; \ + } + + BINOP_SHIFT(nir_op_ishl, SpvOpShiftLeftLogical) + BINOP_SHIFT(nir_op_ishr, SpvOpShiftRightArithmetic) + BINOP_SHIFT(nir_op_ushr, SpvOpShiftRightLogical) +#undef BINOP_SHIFT + #define BUILTIN_BINOP(nir_op, spirv_op) \ case nir_op: \ assert(nir_op_infos[alu->op].num_inputs == 2); \