shader: implement s_bfe_i32

This commit is contained in:
nmzik
2026-08-16 00:42:04 +02:00
parent b4809e7170
commit 7556a74f19
8 changed files with 60 additions and 6 deletions
@@ -20,10 +20,10 @@ constexpr OpcodeMap SOP2_OPCODE_LIST[] = {
{0x1du, Opcode::SXnorB64}, {0x1eu, Opcode::SLshlB32}, {0x1fu, Opcode::SLshlB64},
{0x20u, Opcode::SLshrB32}, {0x21u, Opcode::SLshrB64}, {0x22u, Opcode::SAshrI32},
{0x24u, Opcode::SBfmB32}, {0x25u, Opcode::SBfmB64}, {0x26u, Opcode::SMulI32},
{0x27u, Opcode::SBfeU32}, {0x29u, Opcode::SBfeU64}, {0x2eu, Opcode::SLshl1AddU32},
{0x2fu, Opcode::SLshl2AddU32}, {0x30u, Opcode::SLshl3AddU32}, {0x31u, Opcode::SLshl4AddU32},
{0x32u, Opcode::SPackLlB32B16}, {0x33u, Opcode::SPackLhB32B16}, {0x34u, Opcode::SPackHhB32B16},
{0x35u, Opcode::SMulHiU32},
{0x27u, Opcode::SBfeU32}, {0x28u, Opcode::SBfeI32}, {0x29u, Opcode::SBfeU64},
{0x2eu, Opcode::SLshl1AddU32}, {0x2fu, Opcode::SLshl2AddU32}, {0x30u, Opcode::SLshl3AddU32},
{0x31u, Opcode::SLshl4AddU32}, {0x32u, Opcode::SPackLlB32B16}, {0x33u, Opcode::SPackLhB32B16},
{0x34u, Opcode::SPackHhB32B16}, {0x35u, Opcode::SMulHiU32},
};
constexpr OpcodeMap SOP1_OPCODE_LIST[] = {
@@ -516,6 +516,7 @@ std::string OpcodeToString(Opcode opcode) {
case Opcode::SMulHiU32: return "s_mul_hi_u32";
case Opcode::SMulkI32: return "s_mulk_i32";
case Opcode::SBfeU32: return "s_bfe_u32";
case Opcode::SBfeI32: return "s_bfe_i32";
case Opcode::SBfeU64: return "s_bfe_u64";
case Opcode::SBfmB32: return "s_bfm_b32";
case Opcode::SBfmB64: return "s_bfm_b64";
@@ -100,6 +100,7 @@ enum class Opcode {
SMulHiU32,
SMulkI32,
SBfeU32,
SBfeI32,
SBfeU64,
SBfmB32,
SBfmB64,
@@ -515,14 +515,18 @@ bool Translator::TranslateExtendedInteger(const IR::Instruction& inst) {
result = ir.Emit(IR::ValueOpcode::ShiftLeftLogical64, {right_mask64(count), offset});
break;
}
case IR::Opcode::BitFieldExtractU32: {
case IR::Opcode::BitFieldExtractU32:
case IR::Opcode::BitFieldExtractI32: {
const auto source = ReadU32(inst.src[0]);
const auto field = ReadU32(inst.src[1]);
const auto offset = extract(field, imm(0), imm(5), false);
const auto count =
IR::U32(ir.Emit(IR::ValueOpcode::UMin32, {extract(field, imm(16), imm(7), false),
ir.ISub(imm(32), offset)}));
result = ir.Emit(IR::ValueOpcode::BitFieldUExtract, {source, offset, count});
const auto opcode = inst.op == IR::Opcode::BitFieldExtractI32
? IR::ValueOpcode::BitFieldSExtract
: IR::ValueOpcode::BitFieldUExtract;
result = ir.Emit(opcode, {source, offset, count});
break;
}
case IR::Opcode::BitFieldExtractU64: {
@@ -63,6 +63,7 @@ constexpr LowerMap LOWER_OPS[] = {
{Decoder::Opcode::SMulHiU32, Opcode::UMulHighU32},
{Decoder::Opcode::SMulkI32, Opcode::IMulU32},
{Decoder::Opcode::SBfeU32, Opcode::BitFieldExtractU32},
{Decoder::Opcode::SBfeI32, Opcode::BitFieldExtractI32},
{Decoder::Opcode::SBfeU64, Opcode::BitFieldExtractU64},
{Decoder::Opcode::SBfmB32, Opcode::BitFieldMaskU32},
{Decoder::Opcode::SBfmB64, Opcode::BitFieldMaskU64},
@@ -492,6 +493,7 @@ bool ScalarResultWritesSccNonZero(Decoder::Opcode opcode) {
case Decoder::Opcode::SLshrB32:
case Decoder::Opcode::SAshrI32:
case Decoder::Opcode::SBfeU32:
case Decoder::Opcode::SBfeI32:
case Decoder::Opcode::SAndB64:
case Decoder::Opcode::SAndn2B64:
case Decoder::Opcode::SNotB64:
@@ -88,6 +88,7 @@ IR_OPCODE(FindMsbFromHighU64, General, ComposedInteger)
IR_OPCODE(BitFieldMaskU32, General, ExtendedInteger)
IR_OPCODE(BitFieldMaskU64, General, ExtendedInteger)
IR_OPCODE(BitFieldExtractU32, General, ExtendedInteger)
IR_OPCODE(BitFieldExtractI32, General, ExtendedInteger)
IR_OPCODE(BitFieldExtractU64, General, ExtendedInteger)
IR_OPCODE(BitFieldExtract3U32, General, ExtendedInteger)
IR_OPCODE(BitFieldExtract3I32, General, ExtendedInteger)
+31
View File
@@ -11164,6 +11164,36 @@ TestCase ScalarBrevB32PreservesScc() {
O::BufferStoreDword, O::SEndpgm}};
}
TestCase ScalarBfeI32CapturedRawSignExtends() {
using O = ShaderOpcode;
std::vector<u32> code;
AppendBufferLoadDword(&code, 0, 30);
code.push_back(EncodeVop1(0x02, 20, Vgpr(0)));
code.push_back(0x946aff14u); // s_bfe_i32 vcc_lo, s20, literal
code.push_back(0x0004001cu); // offset 28, width 4
code.push_back(EncodeSop2(0x0a, 21, InlineU32(1), InlineU32(0)));
code.push_back(EncodeSop2(0x28, 22, 20, 255u));
code.push_back(0u); // zero width produces zero and clears SCC
code.push_back(EncodeSop2(0x0a, 23, InlineU32(1), InlineU32(0)));
AppendStoreSgpr(&code, 106, 1);
AppendStoreSgpr(&code, 21, 2);
AppendStoreSgpr(&code, 22, 3);
AppendStoreSgpr(&code, 23, 4);
AppendEnd(&code);
TestCase test;
test.name = "ScalarBfeI32CapturedRawSignExtends";
test.code = std::move(code);
test.initial = {0xf0000000u, 0, 0, 0, 0};
test.expected = {0xf0000000u, 0xffffffffu, 1, 0, 0};
test.opcodes = {O::BufferLoadDword, O::VReadfirstlaneB32, O::SBfeI32,
O::SCselectB32, O::VMovB32, O::BufferStoreDword,
O::SEndpgm};
test.required_spirv = {"OpBitFieldSExtract"};
return test;
}
TestCase BitfieldExtractWidthPastEndEdges() {
using O = ShaderOpcode;
@@ -16981,6 +17011,7 @@ std::vector<TestCase> MakeCases() {
AddCase(ScalarGetpcWritesNextInstructionPc);
AddCase(ScalarBitfieldPack);
AddCase(ScalarBrevB32PreservesScc);
AddCase(ScalarBfeI32CapturedRawSignExtends);
AddCase(BitfieldExtractWidthPastEndEdges);
AddCase(Scalar64BitOps);
AddCase(ScalarAndn2B64SccBranch);
+14
View File
@@ -3356,6 +3356,20 @@ void TestNewShaderDecoderArchitecture() {
Check(literal.word_count == 2u && literal.src0.value == 0x12345678u,
"single-instruction decoder lost a compact literal extension");
const uint32_t scalar_signed_bfe[] = {
0x946aff14u, // s_bfe_i32 vcc_lo, s20, 0x0004001c
0x0004001cu,
};
Instruction signed_bfe;
Check(DecodeInstruction(scalar_signed_bfe, 0u, signed_bfe, &error),
error.c_str());
Check(signed_bfe.family == Family::SOP2 &&
signed_bfe.opcode == Opcode::SBfeI32 &&
signed_bfe.word_count == 2u &&
signed_bfe.dst.kind == OperandKind::VccLo &&
signed_bfe.src0.reg == 20u && signed_bfe.src1.value == 0x0004001cu,
"decoder rejected or misdecoded captured S_BFE_I32 instruction");
const uint32_t mimg_nsa[] = {EncodeMimg0(0x20, 0xf) | (3u << 1u),
EncodeMimg1(4, 0, 1, 8), 0x03020100u,
0x07060504u, 0x0b0a0908u};