shader: fold exact float class masks into native NaN predicates
This commit is contained in:
parent
393257eaae
commit
7b9997baea
|
|
@ -263,10 +263,6 @@ uint32_t EmitUMedTri32(EmitterState& state, uint32_t arg0, uint32_t arg1, uint32
|
|||
return EmitUMax32(state, EmitUMin32(state, arg0, arg1), high_min);
|
||||
}
|
||||
|
||||
uint32_t EmitFPIsNan32(EmitterState& state, uint32_t arg0) {
|
||||
return EmitNative<spv::OpFUnordNotEqual, IR::Type::U1>(state, arg0, arg0);
|
||||
}
|
||||
|
||||
uint32_t EmitFPMin32(EmitterState& state, uint32_t arg0, uint32_t arg1) {
|
||||
return EmitMinMaxF32Value(state, arg0, arg1, false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ inline constexpr auto EmitFPOrdLessThanEqual32 = EmitFloatCompare32<spv::OpFOrdL
|
|||
inline constexpr auto EmitFPUnordLessThanEqual32 = EmitFloatCompare32<spv::OpFUnordLessThanEqual>;
|
||||
inline constexpr auto EmitFPOrdGreaterThanEqual32 = EmitFloatCompare32<spv::OpFOrdGreaterThanEqual>;
|
||||
inline constexpr auto EmitFPUnordGreaterThanEqual32 = EmitFloatCompare32<spv::OpFUnordGreaterThanEqual>;
|
||||
uint32_t EmitFPIsNan32(EmitterState& state, uint32_t arg0);
|
||||
EMIT_NATIVE(FPIsNan32, OpIsNan, U1, uint32_t)
|
||||
inline constexpr auto EmitFPCmpClass32 = EmitClassMaskF32;
|
||||
inline constexpr auto EmitFPCmpClass16 = EmitClassMaskF16;
|
||||
EMIT_NATIVE(FPAdd32, OpFAdd, F32, uint32_t, uint32_t)
|
||||
|
|
|
|||
|
|
@ -215,6 +215,24 @@ void FoldInstruction(Block& block, Block::iterator instruction,
|
|||
return;
|
||||
case ValueOpcode::SelectU32:
|
||||
case ValueOpcode::SelectF32: FoldSelect(inst); return;
|
||||
case ValueOpcode::FPCmpClass32: {
|
||||
const auto mask = Arg(inst, 1);
|
||||
if (!IsImmediate(mask, Type::U32)) {
|
||||
return;
|
||||
}
|
||||
switch (mask.U32() & 0x3ffu) {
|
||||
case 0u: Replace(inst, Value(false)); break;
|
||||
case 0x3ffu: Replace(inst, Value(true)); break;
|
||||
case 3u: {
|
||||
const auto result = block.PrependNewInst(
|
||||
instruction, ValueOpcode::FPIsNan32, {Arg(inst, 0)});
|
||||
Replace(inst, Value(&*result));
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
case ValueOpcode::BitFieldInsert: {
|
||||
const auto base = Arg(inst, 0);
|
||||
const auto insert = Arg(inst, 1);
|
||||
|
|
|
|||
|
|
@ -26812,6 +26812,48 @@ TestCase VectorCompareClassF32() {
|
|||
O::BUFFER_STORE_DWORD, O::S_ENDPGM}};
|
||||
}
|
||||
|
||||
TestCase VectorCompareClassF32ImmediateAndDynamicMasks() {
|
||||
using O = ShaderOpcode;
|
||||
// One input for each architectural class bit, in bit order.
|
||||
constexpr std::array<u32, 10> values{
|
||||
0x7f800001u, 0x7fc00001u, 0xff800000u, 0xbf800000u, 0x80000001u,
|
||||
0x80000000u, 0x00000000u, 0x00000001u, 0x3f800000u, 0x7f800000u};
|
||||
constexpr std::array<u32, 8> masks{
|
||||
0u, 0x3ffu, 3u, 7u, 0xfffffc00u, 0xffffffffu, 0xfffffc03u, 0xfffffc07u};
|
||||
TestCase test;
|
||||
test.name = "VectorCompareClassF32ImmediateAndDynamicMasks";
|
||||
test.initial.assign(values.begin(), values.end());
|
||||
test.initial.insert(test.initial.end(), masks.begin(), masks.end());
|
||||
test.expected = test.initial;
|
||||
auto &code = test.code;
|
||||
AppendVMovU32(&code, 1, 1);
|
||||
for (u32 index = 0; index < values.size(); ++index) {
|
||||
AppendVMovU32(&code, 30, index * 4u);
|
||||
AppendBufferLoadDword(&code, 0, 30);
|
||||
for (u32 mask_index = 0; mask_index < masks.size(); ++mask_index) {
|
||||
for (const bool dynamic : {false, true}) {
|
||||
if (dynamic) {
|
||||
AppendVMovU32(&code, 30, (values.size() + mask_index) * 4u);
|
||||
AppendBufferLoadDword(&code, 2, 30);
|
||||
code.push_back(EncodeVopc(0x88, Vgpr(0), 2));
|
||||
} else {
|
||||
AppendVop3(&code, 0x88, 106, Vgpr(0), 255);
|
||||
code.push_back(masks[mask_index]);
|
||||
}
|
||||
code.push_back(EncodeVop2(0x01, 3, InlineU32(0), 1));
|
||||
AppendStoreVgpr(&code, 3, static_cast<u32>(test.expected.size()));
|
||||
test.expected.push_back((masks[mask_index] & (1u << index)) != 0u);
|
||||
}
|
||||
}
|
||||
}
|
||||
AppendEnd(&code);
|
||||
test.initial.resize(test.expected.size());
|
||||
test.opcodes = {O::V_MOV_B32, O::BUFFER_LOAD_DWORD, O::V_CMP_CLASS_F32,
|
||||
O::V_CNDMASK_B32, O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
test.required_spirv = {"OpIsNan"};
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase VectorVopcSdwaCmpxClassF32CapturedExecMask() {
|
||||
using O = ShaderOpcode;
|
||||
|
||||
|
|
@ -36518,6 +36560,7 @@ std::vector<TestCase> MakeCases() {
|
|||
AddCase(VectorVopcCmpxNeU64CapturedExecMask);
|
||||
AddCase(VectorVop3CmpxNeI64CapturedExecMask);
|
||||
AddCase(VectorCompareClassF32);
|
||||
AddCase(VectorCompareClassF32ImmediateAndDynamicMasks);
|
||||
AddCase(VectorVopcSdwaCmpxClassF32CapturedExecMask);
|
||||
cases.push_back(VectorCmpClassF16(32));
|
||||
cases.push_back(VectorCmpClassF16(64));
|
||||
|
|
@ -42012,6 +42055,7 @@ int main(int argc, char **argv) {
|
|||
RunCase(&vulkan, VectorCompareF32DenormalModes(mode));
|
||||
}
|
||||
RunCase(&vulkan, VectorCompareClassF32());
|
||||
RunCase(&vulkan, VectorCompareClassF32ImmediateAndDynamicMasks());
|
||||
RunCase(&vulkan, VectorCompareF16Ops());
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue