diff --git a/src/compiler/spirv/spirv_to_nir.c b/src/compiler/spirv/spirv_to_nir.c index 264acbcfc65..37d4e41a2c4 100644 --- a/src/compiler/spirv/spirv_to_nir.c +++ b/src/compiler/spirv/spirv_to_nir.c @@ -2094,9 +2094,16 @@ vtn_handle_constant(struct vtn_builder *b, SpvOp opcode, bit_size = glsl_get_bit_size(val->type->type); }; - nir_op op = vtn_nir_alu_op_for_spirv_opcode(b, opcode, &swap, + bool exact; + nir_op op = vtn_nir_alu_op_for_spirv_opcode(b, opcode, &swap, &exact, nir_alu_type_get_type_size(src_alu_type), nir_alu_type_get_type_size(dst_alu_type)); + + /* No SPIR-V opcodes handled through this path should set exact. + * Since it is ignored, assert on it. + */ + assert(!exact); + nir_const_value src[3][NIR_MAX_VEC_COMPONENTS]; for (unsigned i = 0; i < count - 4; i++) { diff --git a/src/compiler/spirv/vtn_alu.c b/src/compiler/spirv/vtn_alu.c index 7bb114408f8..aaed36bb90e 100644 --- a/src/compiler/spirv/vtn_alu.c +++ b/src/compiler/spirv/vtn_alu.c @@ -254,7 +254,7 @@ convert_op_dst_type(SpvOp opcode) nir_op vtn_nir_alu_op_for_spirv_opcode(struct vtn_builder *b, - SpvOp opcode, bool *swap, + SpvOp opcode, bool *swap, bool *exact, unsigned src_bit_size, unsigned dst_bit_size) { /* Indicates that the first two arguments should be swapped. This is @@ -262,6 +262,8 @@ vtn_nir_alu_op_for_spirv_opcode(struct vtn_builder *b, */ *swap = false; + *exact = false; + switch (opcode) { case SpvOpSNegate: return nir_op_ineg; case SpvOpFNegate: return nir_op_fneg; @@ -319,28 +321,28 @@ vtn_nir_alu_op_for_spirv_opcode(struct vtn_builder *b, * the logical operator to use since they also need to check if operands are * ordered. */ - case SpvOpFOrdEqual: return nir_op_feq; - case SpvOpFUnordEqual: return nir_op_feq; - case SpvOpINotEqual: return nir_op_ine; + case SpvOpFOrdEqual: *exact = true; return nir_op_feq; + case SpvOpFUnordEqual: *exact = true; return nir_op_feq; + case SpvOpINotEqual: return nir_op_ine; case SpvOpLessOrGreater: /* Deprecated, use OrdNotEqual */ - case SpvOpFOrdNotEqual: return nir_op_fneu; - case SpvOpFUnordNotEqual: return nir_op_fneu; - case SpvOpULessThan: return nir_op_ult; - case SpvOpSLessThan: return nir_op_ilt; - case SpvOpFOrdLessThan: return nir_op_flt; - case SpvOpFUnordLessThan: return nir_op_flt; - case SpvOpUGreaterThan: *swap = true; return nir_op_ult; - case SpvOpSGreaterThan: *swap = true; return nir_op_ilt; - case SpvOpFOrdGreaterThan: *swap = true; return nir_op_flt; - case SpvOpFUnordGreaterThan: *swap = true; return nir_op_flt; - case SpvOpULessThanEqual: *swap = true; return nir_op_uge; - case SpvOpSLessThanEqual: *swap = true; return nir_op_ige; - case SpvOpFOrdLessThanEqual: *swap = true; return nir_op_fge; - case SpvOpFUnordLessThanEqual: *swap = true; return nir_op_fge; - case SpvOpUGreaterThanEqual: return nir_op_uge; - case SpvOpSGreaterThanEqual: return nir_op_ige; - case SpvOpFOrdGreaterThanEqual: return nir_op_fge; - case SpvOpFUnordGreaterThanEqual: return nir_op_fge; + case SpvOpFOrdNotEqual: *exact = true; return nir_op_fneu; + case SpvOpFUnordNotEqual: *exact = true; return nir_op_fneu; + case SpvOpULessThan: return nir_op_ult; + case SpvOpSLessThan: return nir_op_ilt; + case SpvOpFOrdLessThan: *exact = true; return nir_op_flt; + case SpvOpFUnordLessThan: *exact = true; return nir_op_flt; + case SpvOpUGreaterThan: *swap = true; return nir_op_ult; + case SpvOpSGreaterThan: *swap = true; return nir_op_ilt; + case SpvOpFOrdGreaterThan: *swap = true; *exact = true; return nir_op_flt; + case SpvOpFUnordGreaterThan: *swap = true; *exact = true; return nir_op_flt; + case SpvOpULessThanEqual: *swap = true; return nir_op_uge; + case SpvOpSLessThanEqual: *swap = true; return nir_op_ige; + case SpvOpFOrdLessThanEqual: *swap = true; *exact = true; return nir_op_fge; + case SpvOpFUnordLessThanEqual: *swap = true; *exact = true; return nir_op_fge; + case SpvOpUGreaterThanEqual: return nir_op_uge; + case SpvOpSGreaterThanEqual: return nir_op_ige; + case SpvOpFOrdGreaterThanEqual: *exact = true; return nir_op_fge; + case SpvOpFUnordGreaterThanEqual: *exact = true; return nir_op_fge; /* Conversions: */ case SpvOpQuantizeToF16: return nir_op_fquantize2f16; @@ -554,19 +556,34 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode, dest->def = nir_fmul(&b->nb, src[0], src[1]); break; - case SpvOpIsNan: - dest->def = nir_fneu(&b->nb, src[0], src[0]); - break; + case SpvOpIsNan: { + const bool save_exact = b->nb.exact; - case SpvOpOrdered: + b->nb.exact = true; + dest->def = nir_fneu(&b->nb, src[0], src[0]); + b->nb.exact = save_exact; + break; + } + + case SpvOpOrdered: { + const bool save_exact = b->nb.exact; + + b->nb.exact = true; dest->def = nir_iand(&b->nb, nir_feq(&b->nb, src[0], src[0]), nir_feq(&b->nb, src[1], src[1])); + b->nb.exact = save_exact; break; + } - case SpvOpUnordered: + case SpvOpUnordered: { + const bool save_exact = b->nb.exact; + + b->nb.exact = true; dest->def = nir_ior(&b->nb, nir_fneu(&b->nb, src[0], src[0]), nir_fneu(&b->nb, src[1], src[1])); + b->nb.exact = save_exact; break; + } case SpvOpIsInf: { nir_ssa_def *inf = nir_imm_floatN_t(&b->nb, INFINITY, src[0]->bit_size); @@ -581,9 +598,11 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode, case SpvOpFUnordLessThanEqual: case SpvOpFUnordGreaterThanEqual: { bool swap; + bool unused_exact; unsigned src_bit_size = glsl_get_bit_size(vtn_src[0]->type); unsigned dst_bit_size = glsl_get_bit_size(dest_type); nir_op op = vtn_nir_alu_op_for_spirv_opcode(b, opcode, &swap, + &unused_exact, src_bit_size, dst_bit_size); if (swap) { @@ -592,12 +611,18 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode, src[1] = tmp; } + const bool save_exact = b->nb.exact; + + b->nb.exact = true; + dest->def = nir_ior(&b->nb, nir_build_alu(&b->nb, op, src[0], src[1], NULL, NULL), nir_ior(&b->nb, nir_fneu(&b->nb, src[0], src[0]), nir_fneu(&b->nb, src[1], src[1]))); + + b->nb.exact = save_exact; break; } @@ -608,12 +633,18 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode, * ordered so we don’t need to handle it specially. */ bool swap; + bool exact; unsigned src_bit_size = glsl_get_bit_size(vtn_src[0]->type); unsigned dst_bit_size = glsl_get_bit_size(dest_type); - nir_op op = vtn_nir_alu_op_for_spirv_opcode(b, opcode, &swap, + nir_op op = vtn_nir_alu_op_for_spirv_opcode(b, opcode, &swap, &exact, src_bit_size, dst_bit_size); assert(!swap); + assert(exact); + + const bool save_exact = b->nb.exact; + + b->nb.exact = true; dest->def = nir_iand(&b->nb, @@ -621,6 +652,8 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode, nir_iand(&b->nb, nir_feq(&b->nb, src[0], src[0]), nir_feq(&b->nb, src[1], src[1]))); + + b->nb.exact = save_exact; break; } @@ -676,11 +709,14 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode, case SpvOpShiftRightArithmetic: case SpvOpShiftRightLogical: { bool swap; + bool exact; unsigned src0_bit_size = glsl_get_bit_size(vtn_src[0]->type); unsigned dst_bit_size = glsl_get_bit_size(dest_type); - nir_op op = vtn_nir_alu_op_for_spirv_opcode(b, opcode, &swap, + nir_op op = vtn_nir_alu_op_for_spirv_opcode(b, opcode, &swap, &exact, src0_bit_size, dst_bit_size); + assert(!exact); + assert (op == nir_op_ushr || op == nir_op_ishr || op == nir_op_ishl || op == nir_op_bitfield_insert || op == nir_op_ubitfield_extract || op == nir_op_ibitfield_extract); @@ -725,9 +761,11 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode, default: { bool swap; + bool exact; unsigned src_bit_size = glsl_get_bit_size(vtn_src[0]->type); unsigned dst_bit_size = glsl_get_bit_size(dest_type); nir_op op = vtn_nir_alu_op_for_spirv_opcode(b, opcode, &swap, + &exact, src_bit_size, dst_bit_size); if (swap) { @@ -747,7 +785,14 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode, break; } + const bool save_exact = b->nb.exact; + + if (exact) + b->nb.exact = true; + dest->def = nir_build_alu(&b->nb, op, src[0], src[1], src[2], src[3]); + + b->nb.exact = save_exact; break; } /* default */ } diff --git a/src/compiler/spirv/vtn_private.h b/src/compiler/spirv/vtn_private.h index 5c9c1d7e9b8..11b95b60f4e 100644 --- a/src/compiler/spirv/vtn_private.h +++ b/src/compiler/spirv/vtn_private.h @@ -907,7 +907,7 @@ void vtn_foreach_execution_mode(struct vtn_builder *b, struct vtn_value *value, vtn_execution_mode_foreach_cb cb, void *data); nir_op vtn_nir_alu_op_for_spirv_opcode(struct vtn_builder *b, - SpvOp opcode, bool *swap, + SpvOp opcode, bool *swap, bool *exact, unsigned src_bit_size, unsigned dst_bit_size); void vtn_handle_alu(struct vtn_builder *b, SpvOp opcode,