From 9f49ac8249ffde7d27fd59450dc967e43191e7c0 Mon Sep 17 00:00:00 2001 From: nmzik Date: Tue, 8 Sep 2026 13:33:18 +0400 Subject: [PATCH] shader: reuse SPIR-V helpers and memory resources --- .../backend/spirv/spirvEmitterAlu.cpp | 199 ++++++++---------- .../backend/spirv/spirvEmitterAluHelpers.cpp | 8 +- .../backend/spirv/spirvEmitterImage.cpp | 12 -- .../backend/spirv/spirvEmitterInternal.h | 24 ++- .../backend/spirv/spirvEmitterMemory.cpp | 64 ++---- .../spirv/spirvEmitterMemoryHelpers.cpp | 14 +- .../backend/spirv/spirvEmitterProgram.cpp | 13 +- 7 files changed, 139 insertions(+), 195 deletions(-) diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAlu.cpp b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAlu.cpp index bb32d3b53..250b122cb 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAlu.cpp +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAlu.cpp @@ -10,26 +10,6 @@ struct Pair { uint32_t high = 0; }; -uint32_t NewUnary(EmitterState& state, uint32_t opcode, uint32_t type, uint32_t value) { - const auto result = state.builder.AllocateId(); - state.builder.AddFunction({opcode, type, result, value}); - return result; -} - -uint32_t NewBinary(EmitterState& state, uint32_t opcode, uint32_t type, uint32_t lhs, - uint32_t rhs) { - const auto result = state.builder.AllocateId(); - state.builder.AddFunction({opcode, type, result, lhs, rhs}); - return result; -} - -uint32_t NewSelect(EmitterState& state, uint32_t type, uint32_t condition, uint32_t true_value, - uint32_t false_value) { - const auto result = state.builder.AllocateId(); - state.builder.AddFunction({OpSelect, type, result, condition, true_value, false_value}); - return result; -} - Pair ExtractPair(EmitterState& state, uint32_t value) { Pair result {state.builder.AllocateId(), state.builder.AllocateId()}; state.builder.AddFunction({OpCompositeExtract, TypeU32(state), result.low, value, 0}); @@ -45,20 +25,20 @@ uint32_t MakePair(EmitterState& state, uint32_t low, uint32_t high) { uint32_t CompareEqual64(EmitterState& state, uint32_t lhs_value, uint32_t rhs_value, bool not_equal) { - const auto compare = NewBinary(state, not_equal ? OpINotEqual : OpIEqual, + const auto compare = Binary(state, not_equal ? OpINotEqual : OpIEqual, TypeBoolVector(state, 2), lhs_value, rhs_value); - return NewUnary(state, not_equal ? OpAny : OpAll, TypeBool(state), compare); + return Unary(state, not_equal ? OpAny : OpAll, TypeBool(state), compare); } uint32_t CompareOrdered64(EmitterState& state, uint32_t lhs_value, uint32_t rhs_value, uint32_t high_compare, uint32_t low_compare) { const auto lhs = ExtractPair(state, lhs_value); const auto rhs = ExtractPair(state, rhs_value); - const auto high_equal = NewBinary(state, OpIEqual, TypeBool(state), lhs.high, rhs.high); - const auto high_result = NewBinary(state, high_compare, TypeBool(state), lhs.high, rhs.high); - const auto low_result = NewBinary(state, low_compare, TypeBool(state), lhs.low, rhs.low); - const auto low_path = NewBinary(state, OpLogicalAnd, TypeBool(state), high_equal, low_result); - return NewBinary(state, OpLogicalOr, TypeBool(state), high_result, low_path); + const auto high_equal = Binary(state, OpIEqual, TypeBool(state), lhs.high, rhs.high); + const auto high_result = Binary(state, high_compare, TypeBool(state), lhs.high, rhs.high); + const auto low_result = Binary(state, low_compare, TypeBool(state), lhs.low, rhs.low); + const auto low_path = Binary(state, OpLogicalAnd, TypeBool(state), high_equal, low_result); + return Binary(state, OpLogicalOr, TypeBool(state), high_result, low_path); } uint32_t EmitAdd64(EmitterState& state, uint32_t lhs_value, uint32_t rhs_value) { @@ -70,20 +50,20 @@ uint32_t EmitAdd64(EmitterState& state, uint32_t lhs_value, uint32_t rhs_value) state.builder.AddFunction({OpIAddCarry, TypeU32Pair(state), low_pair, lhs.low, rhs.low}); state.builder.AddFunction({OpCompositeExtract, TypeU32(state), low, low_pair, 0}); state.builder.AddFunction({OpCompositeExtract, TypeU32(state), carry, low_pair, 1}); - const auto high0 = NewBinary(state, OpIAdd, TypeU32(state), lhs.high, rhs.high); - const auto high = NewBinary(state, OpIAdd, TypeU32(state), high0, carry); + const auto high0 = Binary(state, OpIAdd, TypeU32(state), lhs.high, rhs.high); + const auto high = Binary(state, OpIAdd, TypeU32(state), high0, carry); return MakePair(state, low, high); } uint32_t EmitSub64(EmitterState& state, uint32_t lhs_value, uint32_t rhs_value) { const auto lhs = ExtractPair(state, lhs_value); const auto rhs = ExtractPair(state, rhs_value); - const auto low = NewBinary(state, OpISub, TypeU32(state), lhs.low, rhs.low); - const auto borrow = NewBinary(state, OpULessThan, TypeBool(state), lhs.low, rhs.low); + const auto low = Binary(state, OpISub, TypeU32(state), lhs.low, rhs.low); + const auto borrow = Binary(state, OpULessThan, TypeBool(state), lhs.low, rhs.low); const auto borrow_u32 = - NewSelect(state, TypeU32(state), borrow, ConstantU32(state, 1), ConstantU32(state, 0)); - const auto high0 = NewBinary(state, OpISub, TypeU32(state), lhs.high, rhs.high); - const auto high = NewBinary(state, OpISub, TypeU32(state), high0, borrow_u32); + Select(state, TypeU32(state), borrow, ConstantU32(state, 1), ConstantU32(state, 0)); + const auto high0 = Binary(state, OpISub, TypeU32(state), lhs.high, rhs.high); + const auto high = Binary(state, OpISub, TypeU32(state), high0, borrow_u32); return MakePair(state, low, high); } @@ -93,27 +73,27 @@ uint32_t EmitMulHigh(EmitterState& state, uint32_t lhs, uint32_t rhs, bool signe uint32_t lhs_operand = lhs; uint32_t rhs_operand = rhs; if (signed_value) { - lhs_operand = NewUnary(state, OpBitcast, TypeI32(state), lhs); - rhs_operand = NewUnary(state, OpBitcast, TypeI32(state), rhs); + lhs_operand = Unary(state, OpBitcast, TypeI32(state), lhs); + rhs_operand = Unary(state, OpBitcast, TypeI32(state), rhs); } const auto extended = state.builder.AllocateId(); state.builder.AddFunction({signed_value ? OpSMulExtended : OpUMulExtended, pair_type, extended, lhs_operand, rhs_operand}); const auto high = state.builder.AllocateId(); state.builder.AddFunction({OpCompositeExtract, operand_type, high, extended, 1}); - return signed_value ? NewUnary(state, OpBitcast, TypeU32(state), high) : high; + return signed_value ? Unary(state, OpBitcast, TypeU32(state), high) : high; } uint32_t EmitMul64(EmitterState& state, uint32_t lhs_value, uint32_t rhs_value) { const auto lhs = ExtractPair(state, lhs_value); const auto rhs = ExtractPair(state, rhs_value); - const auto low = NewBinary(state, OpIMul, TypeU32(state), lhs.low, rhs.low); + const auto low = Binary(state, OpIMul, TypeU32(state), lhs.low, rhs.low); const auto high0 = EmitMulHigh(state, lhs.low, rhs.low, false); - const auto high1 = NewBinary(state, OpIMul, TypeU32(state), lhs.low, rhs.high); - const auto high2 = NewBinary(state, OpIMul, TypeU32(state), lhs.high, rhs.low); + const auto high1 = Binary(state, OpIMul, TypeU32(state), lhs.low, rhs.high); + const auto high2 = Binary(state, OpIMul, TypeU32(state), lhs.high, rhs.low); return MakePair(state, low, - NewBinary(state, OpIAdd, TypeU32(state), - NewBinary(state, OpIAdd, TypeU32(state), high0, high1), high2)); + Binary(state, OpIAdd, TypeU32(state), + Binary(state, OpIAdd, TypeU32(state), high0, high1), high2)); } uint32_t EmitShift64(EmitterState& state, uint32_t opcode, uint32_t value, uint32_t shift) { @@ -126,33 +106,33 @@ uint32_t EmitShift64(EmitterState& state, uint32_t opcode, uint32_t value, uint3 EmitShiftRightLogicalU64Values(state, pair.low, pair.high, shift, low, high); } else { const auto amount = - NewBinary(state, OpBitwiseAnd, TypeU32(state), shift, ConstantU32(state, 63)); + Binary(state, OpBitwiseAnd, TypeU32(state), shift, ConstantU32(state, 63)); const auto word_shift = - NewBinary(state, OpBitwiseAnd, TypeU32(state), amount, ConstantU32(state, 31)); + Binary(state, OpBitwiseAnd, TypeU32(state), amount, ConstantU32(state, 31)); const auto at_least_32 = - NewBinary(state, OpUGreaterThanEqual, TypeBool(state), amount, ConstantU32(state, 32)); + Binary(state, OpUGreaterThanEqual, TypeBool(state), amount, ConstantU32(state, 32)); const auto nonzero = - NewBinary(state, OpINotEqual, TypeBool(state), amount, ConstantU32(state, 0)); + Binary(state, OpINotEqual, TypeBool(state), amount, ConstantU32(state, 0)); const auto high_shifted = - NewBinary(state, OpShiftRightArithmetic, TypeU32(state), pair.high, word_shift); + Binary(state, OpShiftRightArithmetic, TypeU32(state), pair.high, word_shift); const auto low_shifted = - NewBinary(state, OpShiftRightLogical, TypeU32(state), pair.low, word_shift); + Binary(state, OpShiftRightLogical, TypeU32(state), pair.low, word_shift); const auto carry_count = - NewBinary(state, OpBitwiseAnd, TypeU32(state), - NewBinary(state, OpISub, TypeU32(state), ConstantU32(state, 32), word_shift), + Binary(state, OpBitwiseAnd, TypeU32(state), + Binary(state, OpISub, TypeU32(state), ConstantU32(state, 32), word_shift), ConstantU32(state, 31)); const auto carry = - NewSelect(state, TypeU32(state), nonzero, - NewBinary(state, OpShiftLeftLogical, TypeU32(state), pair.high, carry_count), + Select(state, TypeU32(state), nonzero, + Binary(state, OpShiftLeftLogical, TypeU32(state), pair.high, carry_count), ConstantU32(state, 0)); - const auto low_below_32 = NewBinary(state, OpBitwiseOr, TypeU32(state), low_shifted, carry); + const auto low_below_32 = Binary(state, OpBitwiseOr, TypeU32(state), low_shifted, carry); const auto negative = - NewBinary(state, OpSLessThan, TypeBool(state), pair.high, ConstantU32(state, 0)); - const auto sign_fill = NewSelect(state, TypeU32(state), negative, + Binary(state, OpSLessThan, TypeBool(state), pair.high, ConstantU32(state, 0)); + const auto sign_fill = Select(state, TypeU32(state), negative, ConstantU32(state, 0xffffffffu), ConstantU32(state, 0)); return MakePair(state, - NewSelect(state, TypeU32(state), at_least_32, high_shifted, low_below_32), - NewSelect(state, TypeU32(state), at_least_32, sign_fill, high_shifted)); + Select(state, TypeU32(state), at_least_32, high_shifted, low_below_32), + Select(state, TypeU32(state), at_least_32, sign_fill, high_shifted)); } return MakePair(state, low, high); } @@ -165,36 +145,36 @@ uint32_t EmitConstantShift64(EmitterState& state, uint32_t opcode, uint32_t valu const auto pair = ExtractPair(state, value); if (opcode == OpShiftLeftLogical) { if (shift < 32u) { - const auto low = NewBinary(state, OpShiftLeftLogical, TypeU32(state), pair.low, + const auto low = Binary(state, OpShiftLeftLogical, TypeU32(state), pair.low, ConstantU32(state, shift)); - const auto high = NewBinary(state, OpBitwiseOr, TypeU32(state), - NewBinary(state, OpShiftLeftLogical, TypeU32(state), + const auto high = Binary(state, OpBitwiseOr, TypeU32(state), + Binary(state, OpShiftLeftLogical, TypeU32(state), pair.high, ConstantU32(state, shift)), - NewBinary(state, OpShiftRightLogical, TypeU32(state), + Binary(state, OpShiftRightLogical, TypeU32(state), pair.low, ConstantU32(state, 32u - shift))); return MakePair(state, low, high); } return MakePair(state, ConstantU32(state, 0), shift == 32u ? pair.low - : NewBinary(state, OpShiftLeftLogical, TypeU32(state), + : Binary(state, OpShiftLeftLogical, TypeU32(state), pair.low, ConstantU32(state, shift - 32u))); } if (shift < 32u) { - const auto low = NewBinary(state, OpBitwiseOr, TypeU32(state), - NewBinary(state, OpShiftRightLogical, TypeU32(state), pair.low, + const auto low = Binary(state, OpBitwiseOr, TypeU32(state), + Binary(state, OpShiftRightLogical, TypeU32(state), pair.low, ConstantU32(state, shift)), - NewBinary(state, OpShiftLeftLogical, TypeU32(state), pair.high, + Binary(state, OpShiftLeftLogical, TypeU32(state), pair.high, ConstantU32(state, 32u - shift))); const auto high = - NewBinary(state, opcode, TypeU32(state), pair.high, ConstantU32(state, shift)); + Binary(state, opcode, TypeU32(state), pair.high, ConstantU32(state, shift)); return MakePair(state, low, high); } const auto high = opcode == OpShiftRightArithmetic - ? NewBinary(state, OpShiftRightArithmetic, TypeU32(state), pair.high, + ? Binary(state, OpShiftRightArithmetic, TypeU32(state), pair.high, ConstantU32(state, 31u)) : ConstantU32(state, 0); const auto low = shift == 32u ? pair.high - : NewBinary(state, opcode, TypeU32(state), pair.high, + : Binary(state, opcode, TypeU32(state), pair.high, ConstantU32(state, shift - 32u)); return MakePair(state, low, high); } @@ -207,12 +187,12 @@ uint32_t EmitFindMsb64(EmitterState& state, uint32_t value) { {OpExtInst, TypeI32(state), high_i, GlslStd450(state), GlslFindUMsb, pair.high}); state.builder.AddFunction( {OpExtInst, TypeI32(state), low_i, GlslStd450(state), GlslFindUMsb, pair.low}); - const auto high = NewUnary(state, OpBitcast, TypeU32(state), high_i); - const auto low = NewUnary(state, OpBitcast, TypeU32(state), low_i); + const auto high = Unary(state, OpBitcast, TypeU32(state), high_i); + const auto low = Unary(state, OpBitcast, TypeU32(state), low_i); const auto high_nonzero = - NewBinary(state, OpINotEqual, TypeBool(state), pair.high, ConstantU32(state, 0)); - return NewSelect(state, TypeU32(state), high_nonzero, - NewBinary(state, OpIAdd, TypeU32(state), high, ConstantU32(state, 32)), low); + Binary(state, OpINotEqual, TypeBool(state), pair.high, ConstantU32(state, 0)); + return Select(state, TypeU32(state), high_nonzero, + Binary(state, OpIAdd, TypeU32(state), high, ConstantU32(state, 32)), low); } uint32_t EmitMinMax3(EmitterState& state, uint32_t a, uint32_t b, uint32_t c, bool signed_value, @@ -226,10 +206,10 @@ uint32_t EmitMinMax3(EmitterState& state, uint32_t a, uint32_t b, uint32_t c, bo uint32_t EmitMed3(EmitterState& state, uint32_t a, uint32_t b, uint32_t c, bool signed_value) { const auto minimum = EmitMinMax3(state, a, b, c, signed_value, false); const auto maximum = EmitMinMax3(state, a, b, c, signed_value, true); - const auto ab = NewBinary(state, OpIAdd, TypeU32(state), a, b); - const auto abc = NewBinary(state, OpIAdd, TypeU32(state), ab, c); - return NewBinary(state, OpISub, TypeU32(state), - NewBinary(state, OpISub, TypeU32(state), abc, minimum), maximum); + const auto ab = Binary(state, OpIAdd, TypeU32(state), a, b); + const auto abc = Binary(state, OpIAdd, TypeU32(state), ab, c); + return Binary(state, OpISub, TypeU32(state), + Binary(state, OpISub, TypeU32(state), abc, minimum), maximum); } uint32_t EmitFMinMax3(EmitterState& state, uint32_t a, uint32_t b, uint32_t c, bool max_value) { @@ -242,11 +222,11 @@ uint32_t EmitFMed3(EmitterState& state, uint32_t a, uint32_t b, uint32_t c) { const auto max_ab = EmitMinMaxF32Value(state, a, b, true); const auto high_min = EmitMinMaxF32Value(state, max_ab, c, false); const auto median = EmitMinMaxF32Value(state, min_ab, high_min, true); - const auto nan_ab = NewBinary(state, OpLogicalOr, TypeBool(state), + const auto nan_ab = Binary(state, OpLogicalOr, TypeBool(state), EmitClassifyF32(state, a).nan, EmitClassifyF32(state, b).nan); const auto any_nan = - NewBinary(state, OpLogicalOr, TypeBool(state), nan_ab, EmitClassifyF32(state, c).nan); - return NewSelect(state, TypeF32(state), any_nan, min3, median); + Binary(state, OpLogicalOr, TypeBool(state), nan_ab, EmitClassifyF32(state, c).nan); + return Select(state, TypeF32(state), any_nan, min3, median); } uint32_t EmitExt(EmitterState& state, uint32_t type, uint32_t opcode, @@ -270,37 +250,30 @@ uint32_t EmitF32ToU32(EmitterState& state, uint32_t src, bool signed_value) { } const auto nan = EmitClassifyF32(state, src).nan; if (signed_value) { - const auto below = NewBinary(state, OpFOrdLessThanEqual, TypeBool(state), src, + const auto below = Binary(state, OpFOrdLessThanEqual, TypeBool(state), src, ConstantF32(state, 0xcf000000u)); - const auto above = NewBinary(state, OpFOrdGreaterThanEqual, TypeBool(state), src, + const auto above = Binary(state, OpFOrdGreaterThanEqual, TypeBool(state), src, ConstantF32(state, 0x4f000000u)); const auto high = - NewSelect(state, TypeU32(state), above, ConstantU32(state, 0x7fffffffu), converted_raw); + Select(state, TypeU32(state), above, ConstantU32(state, 0x7fffffffu), converted_raw); const auto low = - NewSelect(state, TypeU32(state), below, ConstantU32(state, 0x80000000u), high); - return NewSelect(state, TypeU32(state), nan, ConstantU32(state, 0), low); + Select(state, TypeU32(state), below, ConstantU32(state, 0x80000000u), high); + return Select(state, TypeU32(state), nan, ConstantU32(state, 0), low); } const auto below = - NewBinary(state, OpFOrdLessThanEqual, TypeBool(state), src, ConstantF32(state, 0)); - const auto above = NewBinary(state, OpFOrdGreaterThanEqual, TypeBool(state), src, + Binary(state, OpFOrdLessThanEqual, TypeBool(state), src, ConstantF32(state, 0)); + const auto above = Binary(state, OpFOrdGreaterThanEqual, TypeBool(state), src, ConstantF32(state, 0x4f800000u)); - const auto zero = NewBinary(state, OpLogicalOr, TypeBool(state), nan, below); + const auto zero = Binary(state, OpLogicalOr, TypeBool(state), nan, below); const auto high = - NewSelect(state, TypeU32(state), above, ConstantU32(state, 0xffffffffu), converted_raw); - return NewSelect(state, TypeU32(state), zero, ConstantU32(state, 0), high); + Select(state, TypeU32(state), above, ConstantU32(state, 0xffffffffu), converted_raw); + return Select(state, TypeU32(state), zero, ConstantU32(state, 0), high); } uint32_t EmitPackHalf(EmitterState& state, uint32_t src) { return EmitExt(state, TypeU32(state), GlslPackHalf2x16, {src}); } -uint32_t EmitUnpackHalf(EmitterState& state, uint32_t bits) { - const auto pair = EmitExt(state, TypeF32Vector(state, 2), GlslUnpackHalf2x16, {bits}); - const auto result = state.builder.AllocateId(); - state.builder.AddFunction({OpCompositeExtract, TypeF32(state), result, pair, 0}); - return result; -} - } // namespace bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) { @@ -341,7 +314,7 @@ bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) { return true; } case IR::ValueOpcode::ConvertF32F16: - ctx.Define(inst, EmitUnpackHalf(state, ctx.Arg(inst, 0))); + ctx.Define(inst, EmitF16BitsToF32(state, ctx.Arg(inst, 0))); return true; case IR::ValueOpcode::ConvertS32F32: ctx.Define(inst, EmitF32ToU32(state, ctx.Arg(inst, 0), true)); @@ -350,7 +323,7 @@ bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) { ctx.Define(inst, EmitF32ToU32(state, ctx.Arg(inst, 0), false)); return true; case IR::ValueOpcode::ConvertF32S32: { - const auto signed_value = NewUnary(state, OpBitcast, TypeI32(state), ctx.Arg(inst, 0)); + const auto signed_value = Unary(state, OpBitcast, TypeI32(state), ctx.Arg(inst, 0)); ctx.Emit(inst, OpConvertSToF, IR::Type::F32, {signed_value}); return true; } @@ -394,9 +367,9 @@ bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) { case IR::ValueOpcode::PackFloat2x16Rtz: { const auto low = EmitF32ToF16RtzBits(state, ctx.Arg(inst, 0)); const auto high = - NewBinary(state, OpShiftLeftLogical, TypeU32(state), + Binary(state, OpShiftLeftLogical, TypeU32(state), EmitF32ToF16RtzBits(state, ctx.Arg(inst, 1)), ConstantU32(state, 16)); - ctx.Define(inst, NewBinary(state, OpBitwiseOr, TypeU32(state), low, high)); + ctx.Define(inst, Binary(state, OpBitwiseOr, TypeU32(state), low, high)); return true; } case IR::ValueOpcode::FPAbs32: @@ -458,10 +431,10 @@ bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) { return true; case IR::ValueOpcode::IAbs32: { const auto value = ctx.Arg(inst, 0); - const auto neg = NewUnary(state, OpSNegate, TypeU32(state), value); + const auto neg = Unary(state, OpSNegate, TypeU32(state), value); const auto negative = - NewBinary(state, OpSLessThan, TypeBool(state), value, ConstantU32(state, 0)); - ctx.Define(inst, NewSelect(state, TypeU32(state), negative, neg, value)); + Binary(state, OpSLessThan, TypeBool(state), value, ConstantU32(state, 0)); + ctx.Define(inst, Select(state, TypeU32(state), negative, neg, value)); return true; } case IR::ValueOpcode::ShiftLeftLogical32: return binary(OpShiftLeftLogical, IR::Type::U32); @@ -496,25 +469,25 @@ bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) { case IR::ValueOpcode::BitwiseXor32: return binary(OpBitwiseXor, IR::Type::U32); case IR::ValueOpcode::BitwiseNot32: return unary(OpNot, IR::Type::U32); case IR::ValueOpcode::BitwiseAnd64: - ctx.Define(inst, NewBinary(state, OpBitwiseAnd, TypeU64(state), ctx.Arg(inst, 0), + ctx.Define(inst, Binary(state, OpBitwiseAnd, TypeU64(state), ctx.Arg(inst, 0), ctx.Arg(inst, 1))); return true; case IR::ValueOpcode::BitReverse32: return unary(OpBitReverse, IR::Type::U32); case IR::ValueOpcode::BitCount32: return unary(OpBitCount, IR::Type::U32); case IR::ValueOpcode::BitCount64: { const auto pair = - ExtractPair(state, NewUnary(state, OpBitCount, TypeU64(state), ctx.Arg(inst, 0))); - ctx.Define(inst, NewBinary(state, OpIAdd, TypeU32(state), pair.low, pair.high)); + ExtractPair(state, Unary(state, OpBitCount, TypeU64(state), ctx.Arg(inst, 0))); + ctx.Define(inst, Binary(state, OpIAdd, TypeU32(state), pair.low, pair.high)); return true; } case IR::ValueOpcode::FindILsb32: { const auto value = EmitExt(state, TypeI32(state), GlslFindILsb, {ctx.Arg(inst, 0)}); - ctx.Define(inst, NewUnary(state, OpBitcast, TypeU32(state), value)); + ctx.Define(inst, Unary(state, OpBitcast, TypeU32(state), value)); return true; } case IR::ValueOpcode::FindUMsb32: { const auto value = EmitExt(state, TypeI32(state), GlslFindUMsb, {ctx.Arg(inst, 0)}); - ctx.Define(inst, NewUnary(state, OpBitcast, TypeU32(state), value)); + ctx.Define(inst, Unary(state, OpBitcast, TypeU32(state), value)); return true; } case IR::ValueOpcode::FindUMsb64: @@ -638,13 +611,13 @@ bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) { return true; case IR::ValueOpcode::FPRecip32: { const auto source = EmitFlushF32DenormToSignedZero(state, ctx.Arg(inst, 0)); - ctx.Define(inst, NewBinary(state, OpFDiv, TypeF32(state), + ctx.Define(inst, Binary(state, OpFDiv, TypeF32(state), ConstantF32(state, 0x3f800000u), source)); return true; } case IR::ValueOpcode::FPRecipIFlag32: // Integer-to-float inputs used by IFLAG cannot be denormal. - ctx.Define(inst, NewBinary(state, OpFDiv, TypeF32(state), + ctx.Define(inst, Binary(state, OpFDiv, TypeF32(state), ConstantF32(state, 0x3f800000u), ctx.Arg(inst, 0))); return true; case IR::ValueOpcode::FPRecipSqrt32: @@ -659,7 +632,7 @@ bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) { case IR::ValueOpcode::FPCos: { auto source = EmitTrigCycleF32(state, ctx.Arg(inst, 0), op == IR::ValueOpcode::FPSin); source = - NewBinary(state, OpFMul, TypeF32(state), source, ConstantF32(state, 0x40c90fdbu)); + Binary(state, OpFMul, TypeF32(state), source, ConstantF32(state, 0x40c90fdbu)); ctx.Define(inst, EmitExt(state, TypeF32(state), op == IR::ValueOpcode::FPSin ? GlslSin : GlslCos, {source})); return true; @@ -673,7 +646,7 @@ bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) { {EmitFlushF32DenormToSignedZero(state, ctx.Arg(inst, 0))})); return true; case IR::ValueOpcode::FPLdexp: { - const auto exponent = NewUnary(state, OpBitcast, TypeI32(state), ctx.Arg(inst, 1)); + const auto exponent = Unary(state, OpBitcast, TypeI32(state), ctx.Arg(inst, 1)); ctx.Define(inst, EmitExt(state, TypeF32(state), GlslLdexp, {ctx.Arg(inst, 0), exponent})); return true; diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAluHelpers.cpp b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAluHelpers.cpp index ce2b8edc4..543ca78fb 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAluHelpers.cpp +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAluHelpers.cpp @@ -215,9 +215,9 @@ uint32_t EmitLogicalNotBool(EmitterState& state, uint32_t value) { return ret; } -F32Class EmitClassifyF32(EmitterState& state, uint32_t value) { +F32Class EmitClassifyF32Bits(EmitterState& state, uint32_t bits) { F32Class cls; - cls.bits = EmitBitcastF32ToU32(state, value); + cls.bits = bits; const auto abs_bits = EmitAndConstant(state, cls.bits, 0x7fffffffu); const auto exponent_bits = EmitAndConstant(state, abs_bits, 0x7f800000u); const auto mantissa_bits = EmitAndConstant(state, abs_bits, 0x007fffffu); @@ -228,6 +228,10 @@ F32Class EmitClassifyF32(EmitterState& state, uint32_t value) { return cls; } +F32Class EmitClassifyF32(EmitterState& state, uint32_t value) { + return EmitClassifyF32Bits(state, EmitBitcastF32ToU32(state, value)); +} + uint32_t EmitClassMaskBitMatch(EmitterState& state, uint32_t mask, uint32_t bit, uint32_t class_match) { const auto selected = diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterImage.cpp b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterImage.cpp index 3371caf21..92662e120 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterImage.cpp +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterImage.cpp @@ -32,18 +32,6 @@ uint32_t ImageGatherComponent(uint32_t dmask) { } } -uint32_t Unary(EmitterState& state, uint32_t opcode, uint32_t type, uint32_t value) { - const auto result = state.builder.AllocateId(); - state.builder.AddFunction({opcode, type, result, value}); - return result; -} - -uint32_t Binary(EmitterState& state, uint32_t opcode, uint32_t type, uint32_t lhs, uint32_t rhs) { - const auto result = state.builder.AllocateId(); - state.builder.AddFunction({opcode, type, result, lhs, rhs}); - return result; -} - bool HasFlag(const IR::MemoryInfo& mem, uint32_t flag) { return (mem.image_sample_flags & flag) != 0u; } diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInternal.h b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInternal.h index ac248f8ed..2d8e07262 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInternal.h +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInternal.h @@ -437,6 +437,26 @@ inline void EmitLabel(EmitterState& state, uint32_t label) { state.builder.AddFunction({OpLabel, label}); } +inline uint32_t Unary(EmitterState& state, uint32_t opcode, uint32_t type, uint32_t value) { + const auto result = state.builder.AllocateId(); + state.builder.AddFunction({opcode, type, result, value}); + return result; +} + +inline uint32_t Binary(EmitterState& state, uint32_t opcode, uint32_t type, uint32_t lhs, + uint32_t rhs) { + const auto result = state.builder.AllocateId(); + state.builder.AddFunction({opcode, type, result, lhs, rhs}); + return result; +} + +inline uint32_t Select(EmitterState& state, uint32_t type, uint32_t condition, + uint32_t true_value, uint32_t false_value) { + const auto result = state.builder.AllocateId(); + state.builder.AddFunction({OpSelect, type, result, condition, true_value, false_value}); + return result; +} + struct ValueEmitContext { explicit ValueEmitContext(EmitterState& state_): state(state_) {} @@ -672,8 +692,6 @@ uint32_t EmitTBufferSelectF32(EmitterState& state, uint32_t condition, uint32_t bool IsSignedFormatComponent(Format::ComponentType type); -uint32_t EmitHalfToF32Bits(EmitterState& state, uint32_t raw); - uint32_t EmitUFloatToF32Bits(EmitterState& state, uint32_t raw, uint32_t bits); uint32_t NormalizeFormatComponent(EmitterState& state, const Format::BufferFormatInfo& info, @@ -724,6 +742,8 @@ uint32_t EmitLogicalOrBool(EmitterState& state, uint32_t lhs, uint32_t rhs); uint32_t EmitLogicalNotBool(EmitterState& state, uint32_t value); +F32Class EmitClassifyF32Bits(EmitterState& state, uint32_t bits); + F32Class EmitClassifyF32(EmitterState& state, uint32_t value); uint32_t EmitClassMaskBitMatch(EmitterState& state, uint32_t mask, uint32_t bit, diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterMemory.cpp b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterMemory.cpp index c2b656946..08d67b09a 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterMemory.cpp +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterMemory.cpp @@ -7,25 +7,6 @@ namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter { namespace { -uint32_t Unary(EmitterState& state, uint32_t opcode, uint32_t type, uint32_t value) { - const auto result = state.builder.AllocateId(); - state.builder.AddFunction({opcode, type, result, value}); - return result; -} - -uint32_t Binary(EmitterState& state, uint32_t opcode, uint32_t type, uint32_t lhs, uint32_t rhs) { - const auto result = state.builder.AllocateId(); - state.builder.AddFunction({opcode, type, result, lhs, rhs}); - return result; -} - -uint32_t Select(EmitterState& state, uint32_t type, uint32_t condition, uint32_t true_value, - uint32_t false_value) { - const auto result = state.builder.AllocateId(); - state.builder.AddFunction({OpSelect, type, result, condition, true_value, false_value}); - return result; -} - uint32_t AndCondition(EmitterState& state, uint32_t lhs, uint32_t rhs) { return Binary(state, OpLogicalAnd, TypeBool(state), lhs, rhs); } @@ -290,12 +271,6 @@ PreparedMemoryElement PrepareMemoryElement(ValueEmitContext& ctx, const IR::Memo return {.resource = resource, .index = index}; } -PreparedMemoryElement PrepareMemoryElement(ValueEmitContext& ctx, const IR::MemoryInfo& mem, - const MemoryResourceAccess& resource, - uint32_t raw_index) { - return {.resource = resource, .index = EmitMemoryElementIndex(ctx.state, resource, raw_index)}; -} - uint32_t LoadWordInBounds(ValueEmitContext& ctx, const MemoryResourceAccess& resource, uint32_t index); @@ -304,10 +279,10 @@ uint32_t LoadSubwordInBounds(ValueEmitContext& ctx, const MemoryResourceAccess& uint32_t LoadWordPrepared(ValueEmitContext& ctx, const IR::Inst& inst, const IR::MemoryInfo& mem, const MemoryResourceAccess& resource) { - const auto access = PrepareMemoryElement(ctx, mem, resource, DwordIndex(ctx, inst, mem)); + const auto index = EmitMemoryElementIndex(ctx.state, resource, DwordIndex(ctx, inst, mem)); return EmitValueOrZeroIfCondition( - ctx.state, EmitMemoryElementInBounds(ctx.state, access.resource, access.index), - [&]() { return LoadWordInBounds(ctx, access.resource, access.index); }); + ctx.state, EmitMemoryElementInBounds(ctx.state, resource, index), + [&]() { return LoadWordInBounds(ctx, resource, index); }); } uint32_t LoadWord(ValueEmitContext& ctx, const IR::Inst& inst, IR::MemoryInfo mem) { @@ -323,11 +298,10 @@ uint32_t LoadSubwordPrepared(ValueEmitContext& ctx, const IR::Inst& inst, const const auto address = ByteAddress(ctx, inst, mem); const auto raw_index = Binary(ctx.state, OpShiftRightLogical, TypeU32(ctx.state), address, ConstantU32(ctx.state, 2)); - const auto access = PrepareMemoryElement(ctx, mem, resource, raw_index); + const auto index = EmitMemoryElementIndex(ctx.state, resource, raw_index); return EmitValueOrZeroIfCondition( - ctx.state, EmitMemoryElementInBounds(ctx.state, access.resource, access.index), [&]() { - return LoadSubwordInBounds(ctx, access.resource, address, access.index, bits, - sign_extend); + ctx.state, EmitMemoryElementInBounds(ctx.state, resource, index), [&]() { + return LoadSubwordInBounds(ctx, resource, address, index, bits, sign_extend); }); } @@ -505,10 +479,10 @@ void StoreSubwordPrepared(ValueEmitContext& ctx, const IR::Inst& inst, const IR: const auto address = ByteAddress(ctx, inst, mem); const auto raw_index = Binary(ctx.state, OpShiftRightLogical, TypeU32(ctx.state), address, ConstantU32(ctx.state, 2)); - const auto access = PrepareMemoryElement(ctx, mem, resource, raw_index); + const auto index = EmitMemoryElementIndex(ctx.state, resource, raw_index); EmitIfCondition( - ctx.state, EmitMemoryElementInBounds(ctx.state, access.resource, access.index), [&]() { - StoreSubwordInBounds(ctx, mem, access.resource, address, access.index, bits, data); + ctx.state, EmitMemoryElementInBounds(ctx.state, resource, index), [&]() { + StoreSubwordInBounds(ctx, mem, resource, address, index, bits, data); }); } @@ -521,12 +495,11 @@ void StoreSubword(ValueEmitContext& ctx, const IR::Inst& inst, IR::MemoryInfo me void StoreWordPrepared(ValueEmitContext& ctx, const IR::Inst& inst, const IR::MemoryInfo& mem, const MemoryResourceAccess& resource, uint32_t data) { - const auto access = PrepareMemoryElement(ctx, mem, resource, DwordIndex(ctx, inst, mem)); + const auto index = EmitMemoryElementIndex(ctx.state, resource, DwordIndex(ctx, inst, mem)); EmitIfCondition( - ctx.state, EmitMemoryElementInBounds(ctx.state, access.resource, access.index), [&]() { + ctx.state, EmitMemoryElementInBounds(ctx.state, resource, index), [&]() { ctx.state.builder.AddFunction( - {OpStore, EmitMemoryElementPointer(ctx.state, access.resource, access.index), - data}); + {OpStore, EmitMemoryElementPointer(ctx.state, resource, index), data}); }); } @@ -963,10 +936,10 @@ uint32_t LoadWideShared(ValueEmitContext& ctx, const IR::Inst& inst, uint32_t co ConstantU32(state, component * 4u)); const auto raw_index = Binary(state, OpShiftRightLogical, TypeU32(state), address, ConstantU32(state, 2)); - const auto access = PrepareMemoryElement(ctx, mem, resource, raw_index); + const auto index = EmitMemoryElementIndex(state, resource, raw_index); values[component] = EmitValueOrZeroIfCondition( - state, EmitMemoryElementInBounds(state, access.resource, access.index), - [&]() { return LoadWordInBounds(ctx, access.resource, access.index); }); + state, EmitMemoryElementInBounds(state, resource, index), + [&]() { return LoadWordInBounds(ctx, resource, index); }); } return ConstructU32Composite(state, components, values); }); @@ -984,11 +957,10 @@ void StoreWideShared(ValueEmitContext& ctx, const IR::Inst& inst, uint32_t compo ConstantU32(state, component * 4u)); const auto raw_index = Binary(state, OpShiftRightLogical, TypeU32(state), address, ConstantU32(state, 2)); - const auto access = PrepareMemoryElement(ctx, mem, resource, raw_index); - EmitIfCondition(state, EmitMemoryElementInBounds(state, access.resource, access.index), + const auto index = EmitMemoryElementIndex(state, resource, raw_index); + EmitIfCondition(state, EmitMemoryElementInBounds(state, resource, index), [&]() { - StoreWordInBounds(ctx, access.resource, access.index, - ctx.Arg(inst, component + 1u)); + StoreWordInBounds(ctx, resource, index, ctx.Arg(inst, component + 1u)); }); } }); diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterMemoryHelpers.cpp b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterMemoryHelpers.cpp index a6d347b4d..e6b1d4567 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterMemoryHelpers.cpp +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterMemoryHelpers.cpp @@ -206,15 +206,6 @@ bool IsSignedFormatComponent(Format::ComponentType type) { type == Format::ComponentType::Sscaled; } -uint32_t EmitHalfToF32Bits(EmitterState& state, uint32_t raw) { - const auto unpacked = state.builder.AllocateId(); - const auto value = state.builder.AllocateId(); - state.builder.AddFunction( - {OpExtInst, TypeF32Vector(state, 2), unpacked, GlslStd450(state), GlslUnpackHalf2x16, raw}); - state.builder.AddFunction({OpCompositeExtract, TypeF32(state), value, unpacked, 0}); - return EmitBitcastF32ToU32(state, value); -} - uint32_t EmitUFloatToF32Bits(EmitterState& state, uint32_t raw, uint32_t bits) { const auto mantissa_bits = bits == 11u ? 6u : 5u; const auto mantissa_mask = (1u << mantissa_bits) - 1u; @@ -295,7 +286,7 @@ uint32_t NormalizeFormatComponent(EmitterState& state, const Format::BufferForma return raw; } if (bits == 16u) { - return EmitHalfToF32Bits(state, raw); + return EmitBitcastF32ToU32(state, EmitF16BitsToF32(state, raw)); } return EmitUFloatToF32Bits(state, raw, bits); default: return raw; @@ -316,8 +307,7 @@ uint32_t EmitFloatAtomicReplacement(EmitterState& state, uint32_t old, uint32_t uint32_t key; }; const auto classify = [&](uint32_t bits) { - const auto value = EmitBitcastU32ToF32(state, bits); - const auto cls = EmitClassifyF32(state, value); + const auto cls = EmitClassifyF32Bits(state, bits); const auto negative = EmitCompareU32Constant( state, OpINotEqual, EmitAndConstant(state, bits, 0x80000000u), 0u); const auto negative_key = state.builder.AllocateId(); diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterProgram.cpp b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterProgram.cpp index c6cc08ff6..3b8ff85da 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterProgram.cpp +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterProgram.cpp @@ -435,12 +435,7 @@ uint32_t ValueEmitContext::Def(IR::Value value) { return id; } } - if (const auto found = definitions.find(inst); found != definitions.end()) { - return found->second; - } - const auto id = state.builder.AllocateId(); - definitions.emplace(inst, id); - return id; + return Result(*inst); } uint32_t ValueEmitContext::Arg(const IR::Inst& inst, size_t index) { @@ -535,10 +530,12 @@ uint32_t ValueEmitContext::Result(const IR::Inst& inst) { uint32_t ValueEmitContext::Emit(const IR::Inst& inst, uint32_t opcode, IR::Type type, std::initializer_list args) { - std::vector words {opcode, TypeId(type), Result(inst)}; + const auto type_id = TypeId(type); + const auto result = Result(inst); + std::vector words {opcode, type_id, result}; words.insert(words.end(), args.begin(), args.end()); state.builder.AddFunction(words); - return Result(inst); + return result; } uint32_t ValueEmitContext::Define(const IR::Inst& inst, uint32_t value) {