shader: decode S_FLBIT_I32 and S_FLBIT_I32_I64 with a 4-op signed leading-bit search

This commit is contained in:
nmzik
2026-10-23 13:22:50 +02:00
parent 3688412dca
commit ecc30a1f2d
6 changed files with 71 additions and 10 deletions
@@ -57,6 +57,8 @@ constexpr OpcodeMap SOP1_OPCODE_LIST[] = {
{0x14u, Opcode::S_FF1_I32_B64},
{0x15u, Opcode::S_FLBIT_I32_B32},
{0x16u, Opcode::S_FLBIT_I32_B64},
{0x17u, Opcode::S_FLBIT_I32},
{0x18u, Opcode::S_FLBIT_I32_I64},
{0x19u, Opcode::S_SEXT_I32_I8},
{0x1au, Opcode::S_SEXT_I32_I16},
{0x1bu, Opcode::S_BITSET0_B32},
@@ -60,6 +60,8 @@ enum class Opcode {
S_FF1_I32_B64,
S_FLBIT_I32_B32,
S_FLBIT_I32_B64,
S_FLBIT_I32,
S_FLBIT_I32_I64,
S_BITREPLICATE_B64_B32,
S_QUADMASK_B64,
S_GETPC_B64,
@@ -221,8 +221,17 @@ void Translator::V_XOR3_B32(const Decoder::Instruction& inst) {
WriteOperand(DestinationOperand(inst), result);
}
void Translator::S_FF_I32_B64(const Decoder::Instruction& inst, bool find_zero, bool from_msb) {
void Translator::S_FF_I32_B64(const Decoder::Instruction& inst, bool find_zero, bool from_msb,
bool sign) {
auto source = ReadU32Pair(inst.src0);
if (sign) {
// A signed source sign-extends a literal; then bits equal to the sign become zero.
if (inst.src0.kind == Decoder::OperandKind::LiteralConstant) {
source[1] = ir.ShiftRightArithmetic(source[0], IR::U32(IR::Value(31u)));
}
const auto mask = ir.ShiftRightArithmetic(source[1], IR::U32(IR::Value(31u)));
source = {ir.BitwiseXor(source[0], mask), ir.BitwiseXor(source[1], mask)};
}
for (auto& word: source) {
word = find_zero ? ir.BitwiseNot(word) : word;
}
@@ -240,12 +249,19 @@ void Translator::S_FF_I32_B64(const Decoder::Instruction& inst, bool find_zero,
void Translator::V_FFBH_32(const Decoder::Instruction& inst, bool sign) {
const auto source = ReadU32(inst.src0);
const auto value = sign ? ir.BitwiseXor(
source, ir.ShiftRightArithmetic(source, IR::U32(IR::Value(31u))))
: source;
const auto msb = IR::U32(ir.Emit(IR::ValueOpcode::FindUMsb32, {value}));
if (sign) {
// Bits equal to the sign become zero; FindILsb of the reversed bits is ~0 when none.
const auto bits =
ir.BitwiseXor(source, ir.ShiftRightArithmetic(source, IR::U32(IR::Value(31u))));
const auto reversed = ir.Emit(IR::ValueOpcode::BitReverse32, {bits});
WriteOperand(DestinationOperand(inst),
IR::U32(ir.Emit(IR::ValueOpcode::FindILsb32, {reversed})));
return;
}
// ResourceTracking matches this 31 - FindUMsb32 form.
const auto msb = IR::U32(ir.Emit(IR::ValueOpcode::FindUMsb32, {source}));
const auto position = ir.ISub(IR::U32(IR::Value(31u)), msb);
const auto result = ir.Select(ir.INotEqual(value, IR::U32(IR::Value(0u))), position,
const auto result = ir.Select(ir.INotEqual(source, IR::U32(IR::Value(0u))), position,
IR::U32(IR::Value(0xffffffffu)));
WriteOperand(DestinationOperand(inst), result);
}
@@ -238,10 +238,12 @@ void Translator::EmitScalar(const Decoder::Instruction& inst) {
return ComposedIntegerBinary(inst, IR::ValueOpcode::BitwiseOr32, false, true, true);
case O::S_XNOR_B32:
return ComposedIntegerBinary(inst, IR::ValueOpcode::BitwiseXor32, false, true, true);
case O::S_FF0_I32_B64: return S_FF_I32_B64(inst, true, false);
case O::S_FF1_I32_B64: return S_FF_I32_B64(inst, false, false);
case O::S_FF0_I32_B64: return S_FF_I32_B64(inst, true, false, false);
case O::S_FF1_I32_B64: return S_FF_I32_B64(inst, false, false, false);
case O::S_FLBIT_I32_B32: return V_FFBH_32(inst, false);
case O::S_FLBIT_I32_B64: return S_FF_I32_B64(inst, false, true);
case O::S_FLBIT_I32_B64: return S_FF_I32_B64(inst, false, true, false);
case O::S_FLBIT_I32: return V_FFBH_32(inst, true);
case O::S_FLBIT_I32_I64: return S_FF_I32_B64(inst, false, true, true);
case O::S_BITSET0_B32: return S_BITSET_B32(inst, false);
case O::S_BITSET1_B32: return S_BITSET_B32(inst, true);
@@ -182,7 +182,7 @@ private:
void V_AND_OR_B32(const Decoder::Instruction& inst);
void V_OR3_B32(const Decoder::Instruction& inst);
void V_XOR3_B32(const Decoder::Instruction& inst);
void S_FF_I32_B64(const Decoder::Instruction& inst, bool find_zero, bool from_msb);
void S_FF_I32_B64(const Decoder::Instruction& inst, bool find_zero, bool from_msb, bool sign);
void V_FFBH_32(const Decoder::Instruction& inst, bool sign);
void Integer24(const Decoder::Instruction& inst, bool sign, bool addend);
void V_MAD_U64_U32(const Decoder::Instruction& inst);
+39
View File
@@ -23119,6 +23119,43 @@ TestCase ScalarFlbitI32B32Gpu() {
O::BUFFER_STORE_DWORD, O::S_ENDPGM}};
}
TestCase ScalarFlbitSignedGpu() {
using O = ShaderOpcode;
// RDNA2's S_FLBIT_I32 examples; 64-bit signs come from the high word.
constexpr u32 values32[] = {0x00000000u, 0x0000ccccu, 0xffff3333u,
0x7fffffffu, 0x80000000u, 0xffffffffu};
constexpr uint64_t values64[] = {0x0000000000000000ull, 0xffffffffffffffffull,
0x0000000100000000ull, 0xffffffff7fffffffull,
0xc000000000000000ull, 0x0000000000008000ull};
std::vector<u32> code;
u32 out = 0;
for (const auto value : values32) {
AppendSMovLiteral(&code, 0, value);
code.push_back(EncodeSop1(0x17, 20, 0));
AppendStoreSgpr(&code, 20, out++);
}
for (const auto value : values64) {
AppendSMovLiteral(&code, 0, static_cast<u32>(value));
AppendSMovLiteral(&code, 1, static_cast<u32>(value >> 32u));
code.push_back(EncodeSop1(0x18, 20, 0));
AppendStoreSgpr(&code, 20, out++);
}
// A signed 64-bit source sign-extends a literal.
code.push_back(EncodeSop1(0x18, 20, 255));
code.push_back(0x80000000u);
AppendStoreSgpr(&code, 20, out);
AppendEnd(&code);
return {"ScalarFlbitSignedGpu",
code,
{},
{0xffffffffu, 16, 16, 1, 1, 0xffffffffu, 0xffffffffu, 0xffffffffu,
31, 32, 2, 48, 33},
{O::S_MOV_B32, O::S_FLBIT_I32, O::S_FLBIT_I32_I64, O::V_MOV_B32,
O::BUFFER_STORE_DWORD, O::S_ENDPGM}};
}
TestCase ScalarSaveExecOps() {
using O = ShaderOpcode;
@@ -43766,6 +43803,7 @@ std::vector<TestCase> MakeCases() {
AddCase(ScalarQuadmaskB64);
AddCase(ScalarFlbitI32B64Gpu);
AddCase(ScalarFlbitI32B32Gpu);
AddCase(ScalarFlbitSignedGpu);
AddCase(ScalarSaveExecOps);
AddCase(ScalarOrn2SaveexecUsesSourceOrNotExec);
cases.push_back(ScalarOrn2SaveexecB32(32, 32));
@@ -50070,6 +50108,7 @@ int main(int argc, char **argv) {
RunCase(&vulkan, VectorCompareF16Ops());
RunCase(&vulkan, ScalarBrevB64OperandsAndMasks(32));
RunCase(&vulkan, ScalarBrevB64OperandsAndMasks(64));
RunCase(&vulkan, ScalarFlbitSignedGpu());
for (bool add : {false, true}) {
RunCase(&vulkan, DsAtomic64Bounds(add));
for (u32 wave_size : {32, 64}) {