mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-19 18:36:53 +02:00
shader: emit native integer operations and remove signedness casts
This commit is contained in:
@@ -56,23 +56,6 @@ uint32_t EmitMulHigh(EmitterState& state, uint32_t lhs, uint32_t rhs, bool signe
|
||||
return signed_value ? Unary(state, spv::OpBitcast, TypeU32(state), high) : high;
|
||||
}
|
||||
|
||||
uint32_t EmitMinMax3(EmitterState& state, uint32_t a, uint32_t b, uint32_t c, bool signed_value,
|
||||
bool max_value) {
|
||||
const auto ab = signed_value ? EmitMinMaxI32Value(state, a, b, max_value)
|
||||
: EmitMinMaxU32Value(state, a, b, max_value);
|
||||
return signed_value ? EmitMinMaxI32Value(state, ab, c, max_value)
|
||||
: EmitMinMaxU32Value(state, ab, c, max_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 maximum = EmitMinMax3(state, a, b, c, signed_value, true);
|
||||
const auto ab = Binary(state, spv::OpIAdd, TypeU32(state), a, b);
|
||||
const auto abc = Binary(state, spv::OpIAdd, TypeU32(state), ab, c);
|
||||
return Binary(state, spv::OpISub, TypeU32(state),
|
||||
Binary(state, spv::OpISub, TypeU32(state), abc, minimum), maximum);
|
||||
}
|
||||
|
||||
uint32_t EmitFMinMax3(EmitterState& state, uint32_t a, uint32_t b, uint32_t c, bool max_value) {
|
||||
return EmitMinMaxF32Value(state, EmitMinMaxF32Value(state, a, b, max_value), c, max_value);
|
||||
}
|
||||
@@ -246,14 +229,6 @@ uint32_t EmitUMulHi(EmitterState& state, uint32_t arg0, uint32_t arg1) {
|
||||
return EmitMulHigh(state, arg0, arg1, false);
|
||||
}
|
||||
|
||||
uint32_t EmitIAbs32(EmitterState& state, uint32_t arg0) {
|
||||
const auto value = arg0;
|
||||
const auto neg = Unary(state, spv::OpSNegate, TypeU32(state), value);
|
||||
const auto negative =
|
||||
Binary(state, spv::OpSLessThan, TypeBool(state), value, ConstantU32(state, 0));
|
||||
return Select(state, TypeU32(state), negative, neg, value);
|
||||
}
|
||||
|
||||
uint32_t EmitBitCount64(EmitterState& state, uint32_t arg0) {
|
||||
// Vulkan bit-count operands remain 32-bit, including when counting a U64.
|
||||
const auto unpacked = Unary(state, spv::OpBitcast, TypeU32Vector(state, 2), arg0);
|
||||
@@ -262,54 +237,30 @@ uint32_t EmitBitCount64(EmitterState& state, uint32_t arg0) {
|
||||
return Binary(state, spv::OpIAdd, TypeU32(state), pair.low, pair.high);
|
||||
}
|
||||
|
||||
uint32_t EmitFindILsb32(EmitterState& state, uint32_t arg0) {
|
||||
const auto value = EmitExt(state, TypeI32(state), GLSLstd450FindILsb, {arg0});
|
||||
return Unary(state, spv::OpBitcast, TypeU32(state), value);
|
||||
}
|
||||
|
||||
uint32_t EmitFindUMsb32(EmitterState& state, uint32_t arg0) {
|
||||
const auto value = EmitExt(state, TypeI32(state), GLSLstd450FindUMsb, {arg0});
|
||||
return Unary(state, spv::OpBitcast, TypeU32(state), value);
|
||||
}
|
||||
|
||||
uint32_t EmitSMin32(EmitterState& state, uint32_t arg0, uint32_t arg1) {
|
||||
return EmitMinMaxI32Value(state, arg0, arg1, false);
|
||||
}
|
||||
|
||||
uint32_t EmitSMax32(EmitterState& state, uint32_t arg0, uint32_t arg1) {
|
||||
return EmitMinMaxI32Value(state, arg0, arg1, true);
|
||||
}
|
||||
|
||||
uint32_t EmitUMin32(EmitterState& state, uint32_t arg0, uint32_t arg1) {
|
||||
return EmitMinMaxU32Value(state, arg0, arg1, false);
|
||||
}
|
||||
|
||||
uint32_t EmitUMax32(EmitterState& state, uint32_t arg0, uint32_t arg1) {
|
||||
return EmitMinMaxU32Value(state, arg0, arg1, true);
|
||||
}
|
||||
|
||||
uint32_t EmitSMinTri32(EmitterState& state, uint32_t arg0, uint32_t arg1, uint32_t arg2) {
|
||||
return EmitMinMax3(state, arg0, arg1, arg2, true, false);
|
||||
return EmitSMin32(state, arg0, EmitSMin32(state, arg1, arg2));
|
||||
}
|
||||
|
||||
uint32_t EmitSMaxTri32(EmitterState& state, uint32_t arg0, uint32_t arg1, uint32_t arg2) {
|
||||
return EmitMinMax3(state, arg0, arg1, arg2, true, true);
|
||||
return EmitSMax32(state, arg0, EmitSMax32(state, arg1, arg2));
|
||||
}
|
||||
|
||||
uint32_t EmitUMinTri32(EmitterState& state, uint32_t arg0, uint32_t arg1, uint32_t arg2) {
|
||||
return EmitMinMax3(state, arg0, arg1, arg2, false, false);
|
||||
return EmitUMin32(state, arg0, EmitUMin32(state, arg1, arg2));
|
||||
}
|
||||
|
||||
uint32_t EmitUMaxTri32(EmitterState& state, uint32_t arg0, uint32_t arg1, uint32_t arg2) {
|
||||
return EmitMinMax3(state, arg0, arg1, arg2, false, true);
|
||||
return EmitUMax32(state, arg0, EmitUMax32(state, arg1, arg2));
|
||||
}
|
||||
|
||||
uint32_t EmitSMedTri32(EmitterState& state, uint32_t arg0, uint32_t arg1, uint32_t arg2) {
|
||||
return EmitMed3(state, arg0, arg1, arg2, true);
|
||||
const auto high_min = EmitSMin32(state, EmitSMax32(state, arg0, arg1), arg2);
|
||||
return EmitSMax32(state, EmitSMin32(state, arg0, arg1), high_min);
|
||||
}
|
||||
|
||||
uint32_t EmitUMedTri32(EmitterState& state, uint32_t arg0, uint32_t arg1, uint32_t arg2) {
|
||||
return EmitMed3(state, arg0, arg1, arg2, false);
|
||||
const auto high_min = EmitUMin32(state, EmitUMax32(state, arg0, arg1), arg2);
|
||||
return EmitUMax32(state, EmitUMin32(state, arg0, arg1), high_min);
|
||||
}
|
||||
|
||||
uint32_t EmitFPIsNan32(EmitterState& state, uint32_t arg0) {
|
||||
|
||||
@@ -82,24 +82,6 @@ uint32_t EmitF32ToF16RtzBits(EmitterState& state, uint32_t f32) {
|
||||
return EmitAndConstant(state, EmitSelectValueU32(state, exp_eq_255, special, finite2), 0xffffu);
|
||||
}
|
||||
|
||||
uint32_t EmitMinMaxU32Value(EmitterState& state, uint32_t lhs, uint32_t rhs, bool max_value) {
|
||||
const auto cond = state.builder.AllocateId();
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction(max_value ? spv::OpUGreaterThan : spv::OpULessThan, TypeBool(state),
|
||||
cond, lhs, rhs);
|
||||
state.builder.AddFunction(spv::OpSelect, TypeU32(state), ret, cond, lhs, rhs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t EmitMinMaxI32Value(EmitterState& state, uint32_t lhs, uint32_t rhs, bool max_value) {
|
||||
const auto cond = state.builder.AllocateId();
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction(max_value ? spv::OpSGreaterThan : spv::OpSLessThan, TypeBool(state),
|
||||
cond, lhs, rhs);
|
||||
state.builder.AddFunction(spv::OpSelect, TypeU32(state), ret, cond, lhs, rhs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
F32Class EmitClassifyF32Bits(EmitterState& state, uint32_t bits) {
|
||||
F32Class cls;
|
||||
cls.bits = bits;
|
||||
|
||||
@@ -23,13 +23,8 @@ uint32_t EmitConvertF16F32(EmitterState& state, uint32_t arg0);
|
||||
inline constexpr auto EmitConvertF32F16 = EmitF16BitsToF32;
|
||||
uint32_t EmitConvertS32F32(EmitterState& state, uint32_t arg0);
|
||||
uint32_t EmitConvertU32F32(EmitterState& state, uint32_t arg0);
|
||||
template <IR::Type type>
|
||||
uint32_t EmitConvertSigned32ToFloat(EmitterState& state, uint32_t arg0) {
|
||||
const auto signed_value = Unary(state, spv::OpBitcast, TypeI32(state), arg0);
|
||||
return EmitNative<spv::OpConvertSToF, type>(state, signed_value);
|
||||
}
|
||||
inline constexpr auto EmitConvertF32S32 = EmitConvertSigned32ToFloat<IR::Type::F32>;
|
||||
inline constexpr auto EmitConvertF64S32 = EmitConvertSigned32ToFloat<IR::Type::F64>;
|
||||
EMIT_NATIVE(ConvertF32S32, OpConvertSToF, F32, uint32_t)
|
||||
EMIT_NATIVE(ConvertF64S32, OpConvertSToF, F64, uint32_t)
|
||||
uint32_t EmitConvertF32F64(EmitterState& state, uint32_t arg0);
|
||||
uint32_t EmitConvertF64F32(EmitterState& state, uint32_t arg0);
|
||||
EMIT_NATIVE(ConvertF32U32, OpConvertUToF, F32, uint32_t)
|
||||
@@ -69,7 +64,7 @@ EMIT_NATIVE(IMul64, OpIMul, U64, uint32_t, uint32_t)
|
||||
EMIT_NATIVE(IAddCarry32, OpIAddCarry, U32x2, uint32_t, uint32_t)
|
||||
uint32_t EmitSMulHi(EmitterState& state, uint32_t arg0, uint32_t arg1);
|
||||
uint32_t EmitUMulHi(EmitterState& state, uint32_t arg0, uint32_t arg1);
|
||||
uint32_t EmitIAbs32(EmitterState& state, uint32_t arg0);
|
||||
inline constexpr auto EmitIAbs32 = EmitGlsl<GLSLstd450SAbs, IR::Type::U32, uint32_t>;
|
||||
EMIT_NATIVE(ShiftLeftLogical32, OpShiftLeftLogical, U32, uint32_t, uint32_t)
|
||||
EMIT_NATIVE(ShiftRightLogical32, OpShiftRightLogical, U32, uint32_t, uint32_t)
|
||||
EMIT_NATIVE(ShiftRightArithmetic32, OpShiftRightArithmetic, U32, uint32_t, uint32_t)
|
||||
@@ -96,13 +91,13 @@ EMIT_NATIVE(BitwiseAnd64, OpBitwiseAnd, U64, uint32_t, uint32_t)
|
||||
EMIT_NATIVE(BitReverse32, OpBitReverse, U32, uint32_t)
|
||||
EMIT_NATIVE(BitCount32, OpBitCount, U32, uint32_t)
|
||||
uint32_t EmitBitCount64(EmitterState& state, uint32_t arg0);
|
||||
uint32_t EmitFindILsb32(EmitterState& state, uint32_t arg0);
|
||||
uint32_t EmitFindUMsb32(EmitterState& state, uint32_t arg0);
|
||||
inline constexpr auto EmitFindILsb32 = EmitGlsl<GLSLstd450FindILsb, IR::Type::U32, uint32_t>;
|
||||
inline constexpr auto EmitFindUMsb32 = EmitGlsl<GLSLstd450FindUMsb, IR::Type::U32, uint32_t>;
|
||||
uint32_t EmitFindUMsb64(EmitterState& state, uint32_t arg0);
|
||||
uint32_t EmitSMin32(EmitterState& state, uint32_t arg0, uint32_t arg1);
|
||||
uint32_t EmitSMax32(EmitterState& state, uint32_t arg0, uint32_t arg1);
|
||||
uint32_t EmitUMin32(EmitterState& state, uint32_t arg0, uint32_t arg1);
|
||||
uint32_t EmitUMax32(EmitterState& state, uint32_t arg0, uint32_t arg1);
|
||||
inline constexpr auto EmitSMin32 = EmitGlsl<GLSLstd450SMin, IR::Type::U32, uint32_t, uint32_t>;
|
||||
inline constexpr auto EmitSMax32 = EmitGlsl<GLSLstd450SMax, IR::Type::U32, uint32_t, uint32_t>;
|
||||
inline constexpr auto EmitUMin32 = EmitGlsl<GLSLstd450UMin, IR::Type::U32, uint32_t, uint32_t>;
|
||||
inline constexpr auto EmitUMax32 = EmitGlsl<GLSLstd450UMax, IR::Type::U32, uint32_t, uint32_t>;
|
||||
uint32_t EmitSMinTri32(EmitterState& state, uint32_t arg0, uint32_t arg1, uint32_t arg2);
|
||||
uint32_t EmitSMaxTri32(EmitterState& state, uint32_t arg0, uint32_t arg1, uint32_t arg2);
|
||||
uint32_t EmitUMinTri32(EmitterState& state, uint32_t arg0, uint32_t arg1, uint32_t arg2);
|
||||
|
||||
@@ -471,10 +471,6 @@ uint32_t EmitSubConstantMinusU32(EmitterState& state, uint32_t constant, uint32_
|
||||
|
||||
uint32_t EmitF32ToF16RtzBits(EmitterState& state, uint32_t f32);
|
||||
|
||||
uint32_t EmitMinMaxU32Value(EmitterState& state, uint32_t lhs, uint32_t rhs, bool max_value);
|
||||
|
||||
uint32_t EmitMinMaxI32Value(EmitterState& state, uint32_t lhs, uint32_t rhs, bool max_value);
|
||||
|
||||
inline constexpr auto EmitBitcastF32ToU32 = EmitNative<spv::OpBitcast, IR::Type::U32, uint32_t>;
|
||||
|
||||
inline constexpr auto EmitBitcastU32ToF32 = EmitNative<spv::OpBitcast, IR::Type::F32, uint32_t>;
|
||||
|
||||
@@ -19729,27 +19729,34 @@ TestCase ScalarAbsI32UpdatesScc() {
|
||||
code.push_back(EncodeSop2(0x0a, dst_sgpr, InlineU32(1), InlineU32(0)));
|
||||
};
|
||||
|
||||
code.push_back(EncodeSMovB32(0, InlineU32(0)));
|
||||
AppendSmemLoadOpcode(&code, 0x08, 16, 0);
|
||||
set_scc(true);
|
||||
code.push_back(EncodeSop1(0x34, 1, 0));
|
||||
capture_scc(2);
|
||||
code.push_back(EncodeSop1(0x34, 17, 16));
|
||||
capture_scc(18);
|
||||
|
||||
AppendSMovLiteral(&code, 3, 0xfffffffbu);
|
||||
AppendSmemLoadOpcode(&code, 0x08, 19, 4);
|
||||
set_scc(false);
|
||||
code.push_back(EncodeSop1(0x34, 4, 3));
|
||||
capture_scc(5);
|
||||
code.push_back(EncodeSop1(0x34, 20, 19));
|
||||
capture_scc(21);
|
||||
|
||||
AppendStoreSgpr(&code, 1, 0);
|
||||
AppendStoreSgpr(&code, 2, 1);
|
||||
AppendStoreSgpr(&code, 4, 2);
|
||||
AppendStoreSgpr(&code, 5, 3);
|
||||
AppendSmemLoadOpcode(&code, 0x08, 22, 8);
|
||||
set_scc(false);
|
||||
code.push_back(EncodeSop1(0x34, 23, 22));
|
||||
capture_scc(24);
|
||||
|
||||
AppendStoreSgpr(&code, 17, 0);
|
||||
AppendStoreSgpr(&code, 18, 1);
|
||||
AppendStoreSgpr(&code, 20, 2);
|
||||
AppendStoreSgpr(&code, 21, 3);
|
||||
AppendStoreSgpr(&code, 23, 4);
|
||||
AppendStoreSgpr(&code, 24, 5);
|
||||
AppendEnd(&code);
|
||||
|
||||
return {"ScalarAbsI32UpdatesScc",
|
||||
code,
|
||||
{},
|
||||
{0, 0, 5, 1},
|
||||
{O::S_MOV_B32, O::S_CMP_EQ_U32, O::S_ABS_I32, O::S_CSELECT_B32,
|
||||
{0, 0xfffffffbu, 0x80000000u},
|
||||
{0, 0, 5, 1, 0x80000000u, 1},
|
||||
{O::S_BUFFER_LOAD_DWORD, O::S_CMP_EQ_U32, O::S_ABS_I32, O::S_CSELECT_B32,
|
||||
O::V_MOV_B32, O::BUFFER_STORE_DWORD, O::S_ENDPGM}};
|
||||
}
|
||||
|
||||
@@ -21887,6 +21894,62 @@ TestCase VectorIntegerOps() {
|
||||
O::S_ENDPGM}};
|
||||
}
|
||||
|
||||
TestCase VectorIntegerExtremaRuntimeEdges() {
|
||||
using O = ShaderOpcode;
|
||||
constexpr std::array<std::array<u32, 3>, 8> inputs{{
|
||||
{0x80000000u, 0u, 0x7fffffffu},
|
||||
{0xffffffffu, 1u, 0x80000000u},
|
||||
{1u, 0x80000000u, 0xffffffffu},
|
||||
{1u, 0xffffffffu, 0x80000000u},
|
||||
{0x7fffffffu, 0x7fffffffu, 0x80000000u},
|
||||
{0x80000000u, 0x80000000u, 0xffffffffu},
|
||||
{0xffffffffu, 0xffffffffu, 0xffffffffu},
|
||||
{0u, 0u, 0u},
|
||||
}};
|
||||
TestCase test;
|
||||
test.name = "VectorIntegerExtremaRuntimeEdges";
|
||||
for (const auto &values : inputs)
|
||||
test.initial.insert(test.initial.end(), values.begin(), values.end());
|
||||
test.expected = test.initial;
|
||||
for (u32 i = 0; i < inputs.size(); ++i) {
|
||||
for (u32 reg = 0; reg < 3; ++reg) {
|
||||
AppendVMovU32(&test.code, 30, (i * 3u + reg) * 4u);
|
||||
AppendBufferLoadDword(&test.code, reg, 30);
|
||||
}
|
||||
for (u32 op = 0; op < 4; ++op)
|
||||
test.code.push_back(EncodeVop2(0x11u + op, 4u + op, Vgpr(0), 1));
|
||||
constexpr std::array opcodes{0x152u, 0x155u, 0x158u, 0x153u, 0x156u, 0x159u};
|
||||
for (u32 op = 0; op < opcodes.size(); ++op)
|
||||
AppendVop3(&test.code, opcodes[op], 8u + op, Vgpr(0), Vgpr(1), Vgpr(2));
|
||||
const auto output = static_cast<u32>(test.expected.size());
|
||||
for (u32 result = 0; result < 10; ++result)
|
||||
AppendStoreVgpr(&test.code, 4u + result, output + result);
|
||||
|
||||
auto unsigned_values = inputs[i];
|
||||
std::array<int32_t, 3> signed_values;
|
||||
for (u32 j = 0; j < 3; ++j)
|
||||
signed_values[j] = std::bit_cast<int32_t>(unsigned_values[j]);
|
||||
test.expected.insert(test.expected.end(), {
|
||||
static_cast<u32>(std::min(signed_values[0], signed_values[1])),
|
||||
static_cast<u32>(std::max(signed_values[0], signed_values[1])),
|
||||
std::min(unsigned_values[0], unsigned_values[1]),
|
||||
std::max(unsigned_values[0], unsigned_values[1])});
|
||||
std::sort(signed_values.begin(), signed_values.end());
|
||||
std::sort(unsigned_values.begin(), unsigned_values.end());
|
||||
test.expected.insert(test.expected.end(), {
|
||||
static_cast<u32>(signed_values[0]), static_cast<u32>(signed_values[2]),
|
||||
static_cast<u32>(signed_values[1]), unsigned_values[0],
|
||||
unsigned_values[2], unsigned_values[1]});
|
||||
}
|
||||
AppendEnd(&test.code);
|
||||
test.opcodes = {O::V_MOV_B32, O::BUFFER_LOAD_DWORD, O::V_MIN_I32, O::V_MAX_I32,
|
||||
O::V_MIN_U32, O::V_MAX_U32, O::V_MIN3_I32, O::V_MAX3_I32,
|
||||
O::V_MED3_I32, O::V_MIN3_U32, O::V_MAX3_U32, O::V_MED3_U32,
|
||||
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
test.required_spirv = {" SMin ", " SMax ", " UMin ", " UMax "};
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase VectorFfbhI32NativeAndVop3OnGpu() {
|
||||
using O = ShaderOpcode;
|
||||
|
||||
@@ -22731,7 +22794,7 @@ TestCase Vop3Min3U16CapturedAndSelectors() {
|
||||
test.opcodes = {O::V_MOV_B32, O::BUFFER_LOAD_DWORD, O::V_MIN3_U16,
|
||||
O::S_MOV_B64, O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
test.decoded_counts = {{"V_MIN3_U16", cases.size()}};
|
||||
test.required_spirv = {"OpULessThan"};
|
||||
test.required_spirv = {" UMin "};
|
||||
return test;
|
||||
}
|
||||
|
||||
@@ -22757,7 +22820,7 @@ TestCase Vop3Med3I16Captured() {
|
||||
test.decoded_counts = {{"0x00000020: V_MED3_I16 v3.sdwa(sel=5,sext=0), "
|
||||
"v5.opsel(lo=1,hi=0,neghi=0), s25, s27\n",
|
||||
1}};
|
||||
test.required_spirv = {"OpSLessThan"};
|
||||
test.required_spirv = {" SMin ", " SMax "};
|
||||
return test;
|
||||
}
|
||||
|
||||
@@ -22783,7 +22846,7 @@ TestCase Vop2SdwaMinU32PreservesWordDestination() {
|
||||
test.expected = {0xa1b20007u, 0xa1b2001fu};
|
||||
test.opcodes = {O::V_MOV_B32, O::V_MIN_U32, O::BUFFER_STORE_DWORD,
|
||||
O::S_ENDPGM};
|
||||
test.required_spirv = {"OpULessThan", "OpSelect"};
|
||||
test.required_spirv = {" UMin ", "OpSelect"};
|
||||
return test;
|
||||
}
|
||||
|
||||
@@ -36327,6 +36390,7 @@ std::vector<TestCase> MakeCases() {
|
||||
AddCase(VectorMoves);
|
||||
AddCase(VectorVop3MoveAppliesFloatSourceModifiers);
|
||||
AddCase(VectorIntegerOps);
|
||||
AddCase(VectorIntegerExtremaRuntimeEdges);
|
||||
AddCase(VectorFfbhI32NativeAndVop3OnGpu);
|
||||
AddCase(Vop1SdwaBfrevSourceSelectors);
|
||||
AddCase(Vop1SdwaFfbhCapturedScalarLowWordSource);
|
||||
|
||||
Reference in New Issue
Block a user