shader: reuse SPIR-V helpers and memory resources

This commit is contained in:
nmzik
2026-09-08 13:33:18 +04:00
parent fde550ef66
commit 9f49ac8249
7 changed files with 139 additions and 195 deletions
@@ -10,26 +10,6 @@ struct Pair {
uint32_t high = 0; 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 ExtractPair(EmitterState& state, uint32_t value) {
Pair result {state.builder.AllocateId(), state.builder.AllocateId()}; Pair result {state.builder.AllocateId(), state.builder.AllocateId()};
state.builder.AddFunction({OpCompositeExtract, TypeU32(state), result.low, value, 0}); 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, uint32_t CompareEqual64(EmitterState& state, uint32_t lhs_value, uint32_t rhs_value,
bool not_equal) { 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); 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 CompareOrdered64(EmitterState& state, uint32_t lhs_value, uint32_t rhs_value,
uint32_t high_compare, uint32_t low_compare) { uint32_t high_compare, uint32_t low_compare) {
const auto lhs = ExtractPair(state, lhs_value); const auto lhs = ExtractPair(state, lhs_value);
const auto rhs = ExtractPair(state, rhs_value); const auto rhs = ExtractPair(state, rhs_value);
const auto high_equal = NewBinary(state, OpIEqual, TypeBool(state), lhs.high, rhs.high); const auto high_equal = Binary(state, OpIEqual, TypeBool(state), lhs.high, rhs.high);
const auto high_result = NewBinary(state, high_compare, TypeBool(state), lhs.high, rhs.high); const auto high_result = Binary(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_result = Binary(state, low_compare, TypeBool(state), lhs.low, rhs.low);
const auto low_path = NewBinary(state, OpLogicalAnd, TypeBool(state), high_equal, low_result); const auto low_path = Binary(state, OpLogicalAnd, TypeBool(state), high_equal, low_result);
return NewBinary(state, OpLogicalOr, TypeBool(state), high_result, low_path); return Binary(state, OpLogicalOr, TypeBool(state), high_result, low_path);
} }
uint32_t EmitAdd64(EmitterState& state, uint32_t lhs_value, uint32_t rhs_value) { 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({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), low, low_pair, 0});
state.builder.AddFunction({OpCompositeExtract, TypeU32(state), carry, low_pair, 1}); state.builder.AddFunction({OpCompositeExtract, TypeU32(state), carry, low_pair, 1});
const auto high0 = NewBinary(state, OpIAdd, TypeU32(state), lhs.high, rhs.high); const auto high0 = Binary(state, OpIAdd, TypeU32(state), lhs.high, rhs.high);
const auto high = NewBinary(state, OpIAdd, TypeU32(state), high0, carry); const auto high = Binary(state, OpIAdd, TypeU32(state), high0, carry);
return MakePair(state, low, high); return MakePair(state, low, high);
} }
uint32_t EmitSub64(EmitterState& state, uint32_t lhs_value, uint32_t rhs_value) { uint32_t EmitSub64(EmitterState& state, uint32_t lhs_value, uint32_t rhs_value) {
const auto lhs = ExtractPair(state, lhs_value); const auto lhs = ExtractPair(state, lhs_value);
const auto rhs = ExtractPair(state, rhs_value); const auto rhs = ExtractPair(state, rhs_value);
const auto low = NewBinary(state, OpISub, TypeU32(state), lhs.low, rhs.low); const auto low = Binary(state, OpISub, TypeU32(state), lhs.low, rhs.low);
const auto borrow = NewBinary(state, OpULessThan, TypeBool(state), lhs.low, rhs.low); const auto borrow = Binary(state, OpULessThan, TypeBool(state), lhs.low, rhs.low);
const auto borrow_u32 = const auto borrow_u32 =
NewSelect(state, TypeU32(state), borrow, ConstantU32(state, 1), ConstantU32(state, 0)); Select(state, TypeU32(state), borrow, ConstantU32(state, 1), ConstantU32(state, 0));
const auto high0 = NewBinary(state, OpISub, TypeU32(state), lhs.high, rhs.high); const auto high0 = Binary(state, OpISub, TypeU32(state), lhs.high, rhs.high);
const auto high = NewBinary(state, OpISub, TypeU32(state), high0, borrow_u32); const auto high = Binary(state, OpISub, TypeU32(state), high0, borrow_u32);
return MakePair(state, low, high); 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 lhs_operand = lhs;
uint32_t rhs_operand = rhs; uint32_t rhs_operand = rhs;
if (signed_value) { if (signed_value) {
lhs_operand = NewUnary(state, OpBitcast, TypeI32(state), lhs); lhs_operand = Unary(state, OpBitcast, TypeI32(state), lhs);
rhs_operand = NewUnary(state, OpBitcast, TypeI32(state), rhs); rhs_operand = Unary(state, OpBitcast, TypeI32(state), rhs);
} }
const auto extended = state.builder.AllocateId(); const auto extended = state.builder.AllocateId();
state.builder.AddFunction({signed_value ? OpSMulExtended : OpUMulExtended, pair_type, extended, state.builder.AddFunction({signed_value ? OpSMulExtended : OpUMulExtended, pair_type, extended,
lhs_operand, rhs_operand}); lhs_operand, rhs_operand});
const auto high = state.builder.AllocateId(); const auto high = state.builder.AllocateId();
state.builder.AddFunction({OpCompositeExtract, operand_type, high, extended, 1}); 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) { uint32_t EmitMul64(EmitterState& state, uint32_t lhs_value, uint32_t rhs_value) {
const auto lhs = ExtractPair(state, lhs_value); const auto lhs = ExtractPair(state, lhs_value);
const auto rhs = ExtractPair(state, rhs_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 high0 = EmitMulHigh(state, lhs.low, rhs.low, false);
const auto high1 = NewBinary(state, OpIMul, TypeU32(state), lhs.low, rhs.high); const auto high1 = Binary(state, OpIMul, TypeU32(state), lhs.low, rhs.high);
const auto high2 = NewBinary(state, OpIMul, TypeU32(state), lhs.high, rhs.low); const auto high2 = Binary(state, OpIMul, TypeU32(state), lhs.high, rhs.low);
return MakePair(state, low, return MakePair(state, low,
NewBinary(state, OpIAdd, TypeU32(state), Binary(state, OpIAdd, TypeU32(state),
NewBinary(state, OpIAdd, TypeU32(state), high0, high1), high2)); Binary(state, OpIAdd, TypeU32(state), high0, high1), high2));
} }
uint32_t EmitShift64(EmitterState& state, uint32_t opcode, uint32_t value, uint32_t shift) { 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); EmitShiftRightLogicalU64Values(state, pair.low, pair.high, shift, low, high);
} else { } else {
const auto amount = 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 = 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 = 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 = 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 = 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 = 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 = const auto carry_count =
NewBinary(state, OpBitwiseAnd, TypeU32(state), Binary(state, OpBitwiseAnd, TypeU32(state),
NewBinary(state, OpISub, TypeU32(state), ConstantU32(state, 32), word_shift), Binary(state, OpISub, TypeU32(state), ConstantU32(state, 32), word_shift),
ConstantU32(state, 31)); ConstantU32(state, 31));
const auto carry = const auto carry =
NewSelect(state, TypeU32(state), nonzero, Select(state, TypeU32(state), nonzero,
NewBinary(state, OpShiftLeftLogical, TypeU32(state), pair.high, carry_count), Binary(state, OpShiftLeftLogical, TypeU32(state), pair.high, carry_count),
ConstantU32(state, 0)); 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 = const auto negative =
NewBinary(state, OpSLessThan, TypeBool(state), pair.high, ConstantU32(state, 0)); Binary(state, OpSLessThan, TypeBool(state), pair.high, ConstantU32(state, 0));
const auto sign_fill = NewSelect(state, TypeU32(state), negative, const auto sign_fill = Select(state, TypeU32(state), negative,
ConstantU32(state, 0xffffffffu), ConstantU32(state, 0)); ConstantU32(state, 0xffffffffu), ConstantU32(state, 0));
return MakePair(state, return MakePair(state,
NewSelect(state, TypeU32(state), at_least_32, high_shifted, low_below_32), Select(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, sign_fill, high_shifted));
} }
return MakePair(state, low, high); 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); const auto pair = ExtractPair(state, value);
if (opcode == OpShiftLeftLogical) { if (opcode == OpShiftLeftLogical) {
if (shift < 32u) { 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)); ConstantU32(state, shift));
const auto high = NewBinary(state, OpBitwiseOr, TypeU32(state), const auto high = Binary(state, OpBitwiseOr, TypeU32(state),
NewBinary(state, OpShiftLeftLogical, TypeU32(state), Binary(state, OpShiftLeftLogical, TypeU32(state),
pair.high, ConstantU32(state, shift)), pair.high, ConstantU32(state, shift)),
NewBinary(state, OpShiftRightLogical, TypeU32(state), Binary(state, OpShiftRightLogical, TypeU32(state),
pair.low, ConstantU32(state, 32u - shift))); pair.low, ConstantU32(state, 32u - shift)));
return MakePair(state, low, high); return MakePair(state, low, high);
} }
return MakePair(state, ConstantU32(state, 0), return MakePair(state, ConstantU32(state, 0),
shift == 32u ? pair.low shift == 32u ? pair.low
: NewBinary(state, OpShiftLeftLogical, TypeU32(state), : Binary(state, OpShiftLeftLogical, TypeU32(state),
pair.low, ConstantU32(state, shift - 32u))); pair.low, ConstantU32(state, shift - 32u)));
} }
if (shift < 32u) { if (shift < 32u) {
const auto low = NewBinary(state, OpBitwiseOr, TypeU32(state), const auto low = Binary(state, OpBitwiseOr, TypeU32(state),
NewBinary(state, OpShiftRightLogical, TypeU32(state), pair.low, Binary(state, OpShiftRightLogical, TypeU32(state), pair.low,
ConstantU32(state, shift)), ConstantU32(state, shift)),
NewBinary(state, OpShiftLeftLogical, TypeU32(state), pair.high, Binary(state, OpShiftLeftLogical, TypeU32(state), pair.high,
ConstantU32(state, 32u - shift))); ConstantU32(state, 32u - shift)));
const auto high = 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); return MakePair(state, low, high);
} }
const auto high = opcode == OpShiftRightArithmetic const auto high = opcode == OpShiftRightArithmetic
? NewBinary(state, OpShiftRightArithmetic, TypeU32(state), pair.high, ? Binary(state, OpShiftRightArithmetic, TypeU32(state), pair.high,
ConstantU32(state, 31u)) ConstantU32(state, 31u))
: ConstantU32(state, 0); : ConstantU32(state, 0);
const auto low = shift == 32u ? pair.high 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)); ConstantU32(state, shift - 32u));
return MakePair(state, low, high); 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}); {OpExtInst, TypeI32(state), high_i, GlslStd450(state), GlslFindUMsb, pair.high});
state.builder.AddFunction( state.builder.AddFunction(
{OpExtInst, TypeI32(state), low_i, GlslStd450(state), GlslFindUMsb, pair.low}); {OpExtInst, TypeI32(state), low_i, GlslStd450(state), GlslFindUMsb, pair.low});
const auto high = NewUnary(state, OpBitcast, TypeU32(state), high_i); const auto high = Unary(state, OpBitcast, TypeU32(state), high_i);
const auto low = NewUnary(state, OpBitcast, TypeU32(state), low_i); const auto low = Unary(state, OpBitcast, TypeU32(state), low_i);
const auto high_nonzero = const auto high_nonzero =
NewBinary(state, OpINotEqual, TypeBool(state), pair.high, ConstantU32(state, 0)); Binary(state, OpINotEqual, TypeBool(state), pair.high, ConstantU32(state, 0));
return NewSelect(state, TypeU32(state), high_nonzero, return Select(state, TypeU32(state), high_nonzero,
NewBinary(state, OpIAdd, TypeU32(state), high, ConstantU32(state, 32)), low); 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, 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) { 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 minimum = EmitMinMax3(state, a, b, c, signed_value, false);
const auto maximum = EmitMinMax3(state, a, b, c, signed_value, true); const auto maximum = EmitMinMax3(state, a, b, c, signed_value, true);
const auto ab = NewBinary(state, OpIAdd, TypeU32(state), a, b); const auto ab = Binary(state, OpIAdd, TypeU32(state), a, b);
const auto abc = NewBinary(state, OpIAdd, TypeU32(state), ab, c); const auto abc = Binary(state, OpIAdd, TypeU32(state), ab, c);
return NewBinary(state, OpISub, TypeU32(state), return Binary(state, OpISub, TypeU32(state),
NewBinary(state, OpISub, TypeU32(state), abc, minimum), maximum); 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) { 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 max_ab = EmitMinMaxF32Value(state, a, b, true);
const auto high_min = EmitMinMaxF32Value(state, max_ab, c, false); const auto high_min = EmitMinMaxF32Value(state, max_ab, c, false);
const auto median = EmitMinMaxF32Value(state, min_ab, high_min, true); 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); EmitClassifyF32(state, a).nan, EmitClassifyF32(state, b).nan);
const auto any_nan = const auto any_nan =
NewBinary(state, OpLogicalOr, TypeBool(state), nan_ab, EmitClassifyF32(state, c).nan); Binary(state, OpLogicalOr, TypeBool(state), nan_ab, EmitClassifyF32(state, c).nan);
return NewSelect(state, TypeF32(state), any_nan, min3, median); return Select(state, TypeF32(state), any_nan, min3, median);
} }
uint32_t EmitExt(EmitterState& state, uint32_t type, uint32_t opcode, 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; const auto nan = EmitClassifyF32(state, src).nan;
if (signed_value) { if (signed_value) {
const auto below = NewBinary(state, OpFOrdLessThanEqual, TypeBool(state), src, const auto below = Binary(state, OpFOrdLessThanEqual, TypeBool(state), src,
ConstantF32(state, 0xcf000000u)); ConstantF32(state, 0xcf000000u));
const auto above = NewBinary(state, OpFOrdGreaterThanEqual, TypeBool(state), src, const auto above = Binary(state, OpFOrdGreaterThanEqual, TypeBool(state), src,
ConstantF32(state, 0x4f000000u)); ConstantF32(state, 0x4f000000u));
const auto high = 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 = const auto low =
NewSelect(state, TypeU32(state), below, ConstantU32(state, 0x80000000u), high); Select(state, TypeU32(state), below, ConstantU32(state, 0x80000000u), high);
return NewSelect(state, TypeU32(state), nan, ConstantU32(state, 0), low); return Select(state, TypeU32(state), nan, ConstantU32(state, 0), low);
} }
const auto below = const auto below =
NewBinary(state, OpFOrdLessThanEqual, TypeBool(state), src, ConstantF32(state, 0)); Binary(state, OpFOrdLessThanEqual, TypeBool(state), src, ConstantF32(state, 0));
const auto above = NewBinary(state, OpFOrdGreaterThanEqual, TypeBool(state), src, const auto above = Binary(state, OpFOrdGreaterThanEqual, TypeBool(state), src,
ConstantF32(state, 0x4f800000u)); 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 = const auto high =
NewSelect(state, TypeU32(state), above, ConstantU32(state, 0xffffffffu), converted_raw); Select(state, TypeU32(state), above, ConstantU32(state, 0xffffffffu), converted_raw);
return NewSelect(state, TypeU32(state), zero, ConstantU32(state, 0), high); return Select(state, TypeU32(state), zero, ConstantU32(state, 0), high);
} }
uint32_t EmitPackHalf(EmitterState& state, uint32_t src) { uint32_t EmitPackHalf(EmitterState& state, uint32_t src) {
return EmitExt(state, TypeU32(state), GlslPackHalf2x16, {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 } // namespace
bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) { bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) {
@@ -341,7 +314,7 @@ bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) {
return true; return true;
} }
case IR::ValueOpcode::ConvertF32F16: case IR::ValueOpcode::ConvertF32F16:
ctx.Define(inst, EmitUnpackHalf(state, ctx.Arg(inst, 0))); ctx.Define(inst, EmitF16BitsToF32(state, ctx.Arg(inst, 0)));
return true; return true;
case IR::ValueOpcode::ConvertS32F32: case IR::ValueOpcode::ConvertS32F32:
ctx.Define(inst, EmitF32ToU32(state, ctx.Arg(inst, 0), true)); 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)); ctx.Define(inst, EmitF32ToU32(state, ctx.Arg(inst, 0), false));
return true; return true;
case IR::ValueOpcode::ConvertF32S32: { 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}); ctx.Emit(inst, OpConvertSToF, IR::Type::F32, {signed_value});
return true; return true;
} }
@@ -394,9 +367,9 @@ bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) {
case IR::ValueOpcode::PackFloat2x16Rtz: { case IR::ValueOpcode::PackFloat2x16Rtz: {
const auto low = EmitF32ToF16RtzBits(state, ctx.Arg(inst, 0)); const auto low = EmitF32ToF16RtzBits(state, ctx.Arg(inst, 0));
const auto high = const auto high =
NewBinary(state, OpShiftLeftLogical, TypeU32(state), Binary(state, OpShiftLeftLogical, TypeU32(state),
EmitF32ToF16RtzBits(state, ctx.Arg(inst, 1)), ConstantU32(state, 16)); 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; return true;
} }
case IR::ValueOpcode::FPAbs32: case IR::ValueOpcode::FPAbs32:
@@ -458,10 +431,10 @@ bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) {
return true; return true;
case IR::ValueOpcode::IAbs32: { case IR::ValueOpcode::IAbs32: {
const auto value = ctx.Arg(inst, 0); 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 = const auto negative =
NewBinary(state, OpSLessThan, TypeBool(state), value, ConstantU32(state, 0)); Binary(state, OpSLessThan, TypeBool(state), value, ConstantU32(state, 0));
ctx.Define(inst, NewSelect(state, TypeU32(state), negative, neg, value)); ctx.Define(inst, Select(state, TypeU32(state), negative, neg, value));
return true; return true;
} }
case IR::ValueOpcode::ShiftLeftLogical32: return binary(OpShiftLeftLogical, IR::Type::U32); 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::BitwiseXor32: return binary(OpBitwiseXor, IR::Type::U32);
case IR::ValueOpcode::BitwiseNot32: return unary(OpNot, IR::Type::U32); case IR::ValueOpcode::BitwiseNot32: return unary(OpNot, IR::Type::U32);
case IR::ValueOpcode::BitwiseAnd64: 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))); ctx.Arg(inst, 1)));
return true; return true;
case IR::ValueOpcode::BitReverse32: return unary(OpBitReverse, IR::Type::U32); case IR::ValueOpcode::BitReverse32: return unary(OpBitReverse, IR::Type::U32);
case IR::ValueOpcode::BitCount32: return unary(OpBitCount, IR::Type::U32); case IR::ValueOpcode::BitCount32: return unary(OpBitCount, IR::Type::U32);
case IR::ValueOpcode::BitCount64: { case IR::ValueOpcode::BitCount64: {
const auto pair = const auto pair =
ExtractPair(state, NewUnary(state, OpBitCount, TypeU64(state), ctx.Arg(inst, 0))); ExtractPair(state, Unary(state, OpBitCount, TypeU64(state), ctx.Arg(inst, 0)));
ctx.Define(inst, NewBinary(state, OpIAdd, TypeU32(state), pair.low, pair.high)); ctx.Define(inst, Binary(state, OpIAdd, TypeU32(state), pair.low, pair.high));
return true; return true;
} }
case IR::ValueOpcode::FindILsb32: { case IR::ValueOpcode::FindILsb32: {
const auto value = EmitExt(state, TypeI32(state), GlslFindILsb, {ctx.Arg(inst, 0)}); 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; return true;
} }
case IR::ValueOpcode::FindUMsb32: { case IR::ValueOpcode::FindUMsb32: {
const auto value = EmitExt(state, TypeI32(state), GlslFindUMsb, {ctx.Arg(inst, 0)}); 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; return true;
} }
case IR::ValueOpcode::FindUMsb64: case IR::ValueOpcode::FindUMsb64:
@@ -638,13 +611,13 @@ bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) {
return true; return true;
case IR::ValueOpcode::FPRecip32: { case IR::ValueOpcode::FPRecip32: {
const auto source = EmitFlushF32DenormToSignedZero(state, ctx.Arg(inst, 0)); 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)); ConstantF32(state, 0x3f800000u), source));
return true; return true;
} }
case IR::ValueOpcode::FPRecipIFlag32: case IR::ValueOpcode::FPRecipIFlag32:
// Integer-to-float inputs used by IFLAG cannot be denormal. // 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))); ConstantF32(state, 0x3f800000u), ctx.Arg(inst, 0)));
return true; return true;
case IR::ValueOpcode::FPRecipSqrt32: case IR::ValueOpcode::FPRecipSqrt32:
@@ -659,7 +632,7 @@ bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) {
case IR::ValueOpcode::FPCos: { case IR::ValueOpcode::FPCos: {
auto source = EmitTrigCycleF32(state, ctx.Arg(inst, 0), op == IR::ValueOpcode::FPSin); auto source = EmitTrigCycleF32(state, ctx.Arg(inst, 0), op == IR::ValueOpcode::FPSin);
source = 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), ctx.Define(inst, EmitExt(state, TypeF32(state),
op == IR::ValueOpcode::FPSin ? GlslSin : GlslCos, {source})); op == IR::ValueOpcode::FPSin ? GlslSin : GlslCos, {source}));
return true; return true;
@@ -673,7 +646,7 @@ bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) {
{EmitFlushF32DenormToSignedZero(state, ctx.Arg(inst, 0))})); {EmitFlushF32DenormToSignedZero(state, ctx.Arg(inst, 0))}));
return true; return true;
case IR::ValueOpcode::FPLdexp: { 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, ctx.Define(inst,
EmitExt(state, TypeF32(state), GlslLdexp, {ctx.Arg(inst, 0), exponent})); EmitExt(state, TypeF32(state), GlslLdexp, {ctx.Arg(inst, 0), exponent}));
return true; return true;
@@ -215,9 +215,9 @@ uint32_t EmitLogicalNotBool(EmitterState& state, uint32_t value) {
return ret; return ret;
} }
F32Class EmitClassifyF32(EmitterState& state, uint32_t value) { F32Class EmitClassifyF32Bits(EmitterState& state, uint32_t bits) {
F32Class cls; F32Class cls;
cls.bits = EmitBitcastF32ToU32(state, value); cls.bits = bits;
const auto abs_bits = EmitAndConstant(state, cls.bits, 0x7fffffffu); const auto abs_bits = EmitAndConstant(state, cls.bits, 0x7fffffffu);
const auto exponent_bits = EmitAndConstant(state, abs_bits, 0x7f800000u); const auto exponent_bits = EmitAndConstant(state, abs_bits, 0x7f800000u);
const auto mantissa_bits = EmitAndConstant(state, abs_bits, 0x007fffffu); const auto mantissa_bits = EmitAndConstant(state, abs_bits, 0x007fffffu);
@@ -228,6 +228,10 @@ F32Class EmitClassifyF32(EmitterState& state, uint32_t value) {
return cls; 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 EmitClassMaskBitMatch(EmitterState& state, uint32_t mask, uint32_t bit,
uint32_t class_match) { uint32_t class_match) {
const auto selected = const auto selected =
@@ -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) { bool HasFlag(const IR::MemoryInfo& mem, uint32_t flag) {
return (mem.image_sample_flags & flag) != 0u; return (mem.image_sample_flags & flag) != 0u;
} }
@@ -437,6 +437,26 @@ inline void EmitLabel(EmitterState& state, uint32_t label) {
state.builder.AddFunction({OpLabel, 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 { struct ValueEmitContext {
explicit ValueEmitContext(EmitterState& state_): state(state_) {} 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); 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 EmitUFloatToF32Bits(EmitterState& state, uint32_t raw, uint32_t bits);
uint32_t NormalizeFormatComponent(EmitterState& state, const Format::BufferFormatInfo& info, 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); uint32_t EmitLogicalNotBool(EmitterState& state, uint32_t value);
F32Class EmitClassifyF32Bits(EmitterState& state, uint32_t bits);
F32Class EmitClassifyF32(EmitterState& state, uint32_t value); F32Class EmitClassifyF32(EmitterState& state, uint32_t value);
uint32_t EmitClassMaskBitMatch(EmitterState& state, uint32_t mask, uint32_t bit, uint32_t EmitClassMaskBitMatch(EmitterState& state, uint32_t mask, uint32_t bit,
@@ -7,25 +7,6 @@
namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter { namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter {
namespace { 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) { uint32_t AndCondition(EmitterState& state, uint32_t lhs, uint32_t rhs) {
return Binary(state, OpLogicalAnd, TypeBool(state), lhs, 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}; 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 LoadWordInBounds(ValueEmitContext& ctx, const MemoryResourceAccess& resource,
uint32_t index); 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, uint32_t LoadWordPrepared(ValueEmitContext& ctx, const IR::Inst& inst, const IR::MemoryInfo& mem,
const MemoryResourceAccess& resource) { 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( return EmitValueOrZeroIfCondition(
ctx.state, EmitMemoryElementInBounds(ctx.state, access.resource, access.index), ctx.state, EmitMemoryElementInBounds(ctx.state, resource, index),
[&]() { return LoadWordInBounds(ctx, access.resource, access.index); }); [&]() { return LoadWordInBounds(ctx, resource, index); });
} }
uint32_t LoadWord(ValueEmitContext& ctx, const IR::Inst& inst, IR::MemoryInfo mem) { 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 address = ByteAddress(ctx, inst, mem);
const auto raw_index = Binary(ctx.state, OpShiftRightLogical, TypeU32(ctx.state), address, const auto raw_index = Binary(ctx.state, OpShiftRightLogical, TypeU32(ctx.state), address,
ConstantU32(ctx.state, 2)); ConstantU32(ctx.state, 2));
const auto access = PrepareMemoryElement(ctx, mem, resource, raw_index); const auto index = EmitMemoryElementIndex(ctx.state, resource, raw_index);
return EmitValueOrZeroIfCondition( return EmitValueOrZeroIfCondition(
ctx.state, EmitMemoryElementInBounds(ctx.state, access.resource, access.index), [&]() { ctx.state, EmitMemoryElementInBounds(ctx.state, resource, index), [&]() {
return LoadSubwordInBounds(ctx, access.resource, address, access.index, bits, return LoadSubwordInBounds(ctx, resource, address, index, bits, sign_extend);
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 address = ByteAddress(ctx, inst, mem);
const auto raw_index = Binary(ctx.state, OpShiftRightLogical, TypeU32(ctx.state), address, const auto raw_index = Binary(ctx.state, OpShiftRightLogical, TypeU32(ctx.state), address,
ConstantU32(ctx.state, 2)); ConstantU32(ctx.state, 2));
const auto access = PrepareMemoryElement(ctx, mem, resource, raw_index); const auto index = EmitMemoryElementIndex(ctx.state, resource, raw_index);
EmitIfCondition( EmitIfCondition(
ctx.state, EmitMemoryElementInBounds(ctx.state, access.resource, access.index), [&]() { ctx.state, EmitMemoryElementInBounds(ctx.state, resource, index), [&]() {
StoreSubwordInBounds(ctx, mem, access.resource, address, access.index, bits, data); 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, void StoreWordPrepared(ValueEmitContext& ctx, const IR::Inst& inst, const IR::MemoryInfo& mem,
const MemoryResourceAccess& resource, uint32_t data) { 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( EmitIfCondition(
ctx.state, EmitMemoryElementInBounds(ctx.state, access.resource, access.index), [&]() { ctx.state, EmitMemoryElementInBounds(ctx.state, resource, index), [&]() {
ctx.state.builder.AddFunction( ctx.state.builder.AddFunction(
{OpStore, EmitMemoryElementPointer(ctx.state, access.resource, access.index), {OpStore, EmitMemoryElementPointer(ctx.state, resource, index), data});
data});
}); });
} }
@@ -963,10 +936,10 @@ uint32_t LoadWideShared(ValueEmitContext& ctx, const IR::Inst& inst, uint32_t co
ConstantU32(state, component * 4u)); ConstantU32(state, component * 4u));
const auto raw_index = Binary(state, OpShiftRightLogical, TypeU32(state), address, const auto raw_index = Binary(state, OpShiftRightLogical, TypeU32(state), address,
ConstantU32(state, 2)); ConstantU32(state, 2));
const auto access = PrepareMemoryElement(ctx, mem, resource, raw_index); const auto index = EmitMemoryElementIndex(state, resource, raw_index);
values[component] = EmitValueOrZeroIfCondition( values[component] = EmitValueOrZeroIfCondition(
state, EmitMemoryElementInBounds(state, access.resource, access.index), state, EmitMemoryElementInBounds(state, resource, index),
[&]() { return LoadWordInBounds(ctx, access.resource, access.index); }); [&]() { return LoadWordInBounds(ctx, resource, index); });
} }
return ConstructU32Composite(state, components, values); return ConstructU32Composite(state, components, values);
}); });
@@ -984,11 +957,10 @@ void StoreWideShared(ValueEmitContext& ctx, const IR::Inst& inst, uint32_t compo
ConstantU32(state, component * 4u)); ConstantU32(state, component * 4u));
const auto raw_index = const auto raw_index =
Binary(state, OpShiftRightLogical, TypeU32(state), address, ConstantU32(state, 2)); 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);
EmitIfCondition(state, EmitMemoryElementInBounds(state, access.resource, access.index), EmitIfCondition(state, EmitMemoryElementInBounds(state, resource, index),
[&]() { [&]() {
StoreWordInBounds(ctx, access.resource, access.index, StoreWordInBounds(ctx, resource, index, ctx.Arg(inst, component + 1u));
ctx.Arg(inst, component + 1u));
}); });
} }
}); });
@@ -206,15 +206,6 @@ bool IsSignedFormatComponent(Format::ComponentType type) {
type == Format::ComponentType::Sscaled; 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) { uint32_t EmitUFloatToF32Bits(EmitterState& state, uint32_t raw, uint32_t bits) {
const auto mantissa_bits = bits == 11u ? 6u : 5u; const auto mantissa_bits = bits == 11u ? 6u : 5u;
const auto mantissa_mask = (1u << mantissa_bits) - 1u; const auto mantissa_mask = (1u << mantissa_bits) - 1u;
@@ -295,7 +286,7 @@ uint32_t NormalizeFormatComponent(EmitterState& state, const Format::BufferForma
return raw; return raw;
} }
if (bits == 16u) { if (bits == 16u) {
return EmitHalfToF32Bits(state, raw); return EmitBitcastF32ToU32(state, EmitF16BitsToF32(state, raw));
} }
return EmitUFloatToF32Bits(state, raw, bits); return EmitUFloatToF32Bits(state, raw, bits);
default: return raw; default: return raw;
@@ -316,8 +307,7 @@ uint32_t EmitFloatAtomicReplacement(EmitterState& state, uint32_t old, uint32_t
uint32_t key; uint32_t key;
}; };
const auto classify = [&](uint32_t bits) { const auto classify = [&](uint32_t bits) {
const auto value = EmitBitcastU32ToF32(state, bits); const auto cls = EmitClassifyF32Bits(state, bits);
const auto cls = EmitClassifyF32(state, value);
const auto negative = EmitCompareU32Constant( const auto negative = EmitCompareU32Constant(
state, OpINotEqual, EmitAndConstant(state, bits, 0x80000000u), 0u); state, OpINotEqual, EmitAndConstant(state, bits, 0x80000000u), 0u);
const auto negative_key = state.builder.AllocateId(); const auto negative_key = state.builder.AllocateId();
@@ -435,12 +435,7 @@ uint32_t ValueEmitContext::Def(IR::Value value) {
return id; return id;
} }
} }
if (const auto found = definitions.find(inst); found != definitions.end()) { return Result(*inst);
return found->second;
}
const auto id = state.builder.AllocateId();
definitions.emplace(inst, id);
return id;
} }
uint32_t ValueEmitContext::Arg(const IR::Inst& inst, size_t index) { 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, uint32_t ValueEmitContext::Emit(const IR::Inst& inst, uint32_t opcode, IR::Type type,
std::initializer_list<uint32_t> args) { std::initializer_list<uint32_t> args) {
std::vector<uint32_t> words {opcode, TypeId(type), Result(inst)}; const auto type_id = TypeId(type);
const auto result = Result(inst);
std::vector<uint32_t> words {opcode, type_id, result};
words.insert(words.end(), args.begin(), args.end()); words.insert(words.end(), args.begin(), args.end());
state.builder.AddFunction(words); state.builder.AddFunction(words);
return Result(inst); return result;
} }
uint32_t ValueEmitContext::Define(const IR::Inst& inst, uint32_t value) { uint32_t ValueEmitContext::Define(const IR::Inst& inst, uint32_t value) {