shader: implement V_ASHRREV_I64 (VOP3 0x301)

This commit is contained in:
Chai T authored and nmzik committed 2026-10-28 21:51:28 +01:00
1 parent c528324d27
commit a8e3c29b2e
6 files changed
+120 -5

No files matched your search

@@ -354,6 +354,7 @@ enum class Opcode {
V_ASHRREV_I32,
V_LSHLREV_B64,
V_LSHRREV_B64,
V_ASHRREV_I64,
V_LSHLREV_B16,
V_LSHRREV_B16,
V_ASHRREV_I16,
@@ -354,6 +354,7 @@ constexpr OpcodeMap VOP3_OPCODE_LIST[] = {
{0x16cu, Opcode::V_MUL_HI_I32},
{0x2ffu, Opcode::V_LSHLREV_B64},
{0x300u, Opcode::V_LSHRREV_B64},
{0x301u, Opcode::V_ASHRREV_I64},
{0x303u, Opcode::V_ADD_NC_U16},
{0x304u, Opcode::V_SUB_NC_U16},
{0x305u, Opcode::V_MUL_LO_U16},
@@ -1335,6 +1336,7 @@ uint32_t NativeVop3SourceCount(Opcode opcode) {
case Opcode::V_SUB_NC_I16:
case Opcode::V_LSHLREV_B64:
case Opcode::V_LSHRREV_B64:
case Opcode::V_ASHRREV_I64:
case Opcode::V_LSHLREV_B16:
case Opcode::V_LSHRREV_B16:
case Opcode::V_ASHRREV_I16:
@@ -147,6 +147,12 @@ void Translator::SimpleInteger(const Decoder::Instruction& inst, IR::ValueOpcode
const auto arg_type = IR::ArgTypeOf(opcode, index);
const auto& operand = SourceAt(inst, reverse && index < 2u ? 1u - index : index);
args[index] = ReadOperand(operand, arg_type == IR::Type::Void ? type : arg_type);
if (opcode == IR::ValueOpcode::ShiftRightArithmetic64 && index == 0u &&
operand.kind == Decoder::OperandKind::LiteralConstant) {
args[index] = ir.ConstructU64(
ReadU32(operand),
IR::U32(IR::Value((operand.value & 0x80000000u) ? 0xffffffffu : 0u)));
}
if (mask_shift_count && index == 1u) {
args[index] = ir.BitwiseAnd(IR::U32(args[index]), IR::U32(IR::Value(31u)));
}
@@ -565,6 +565,9 @@ void Translator::EmitVector(const Decoder::Instruction& inst) {
case O::V_LSHRREV_B64:
return SimpleInteger(inst, IR::ValueOpcode::ShiftRightLogical64, IR::Type::U64, true,
false, false);
case O::V_ASHRREV_I64:
return SimpleInteger(inst, IR::ValueOpcode::ShiftRightArithmetic64, IR::Type::U64, true,
false, false);
case O::V_XNOR_B32:
return ComposedIntegerBinary(inst, IR::ValueOpcode::BitwiseXor32, false, true, false);
+71 -5
View File
@@ -26927,6 +26927,67 @@ TestCase VectorVop3LshlrevB64Captured() {
return test;
}
TestCase VectorVop3AshrrevI64Operands() {
using O = ShaderOpcode;
TestCase test;
test.name = "VectorVop3AshrrevI64Operands";
test.initial = {33u, 0x89abcdefu, 0xfedcba98u};
test.expected = test.initial;
auto &code = test.code;
const auto store_result = [&](u32 dst, uint64_t value, u32 count) {
const auto output = static_cast<u32>(test.expected.size());
AppendStoreVgpr(&code, dst, output);
AppendStoreVgpr(&code, dst + 1u, output + 1u);
const auto expected = ReferenceAshrI64(value, count);
test.expected.push_back(static_cast<u32>(expected));
test.expected.push_back(static_cast<u32>(expected >> 32u));
};
constexpr uint64_t value = 0xfedcba9889abcdefull;
AppendVMovU32(&code, 30, sizeof(u32));
AppendBufferLoadDword(&code, 2, 30);
AppendVMovU32(&code, 30, 2u * sizeof(u32));
AppendBufferLoadDword(&code, 3, 30);
code.push_back(0xd7010007u);
code.push_back(0x00020498u);
store_result(7, value, 24u);
AppendSMovLiteral(&code, 106, static_cast<u32>(value));
AppendSMovLiteral(&code, 107, static_cast<u32>(value >> 32u));
AppendVMovU32(&code, 12, 68);
code.push_back(0xd7010001u);
code.push_back(0x0000d50cu);
store_result(1, value, 68u);
AppendVMovU32(&code, 30, 0);
AppendBufferLoadDword(&code, 12, 30);
for (const u32 literal : {0u, 0x7fffffffu, 0x80000000u, 0xffffffffu}) {
const uint64_t extended =
literal | ((literal & 0x80000000u) != 0 ? 0xffffffff00000000ull : 0ull);
for (const u32 count : {0u, 1u, 31u, 32u, 63u, 64u}) {
AppendVop3(&code, 0x301, 7, InlineU32(count), 255u);
code.push_back(literal);
store_result(7, extended, count);
}
AppendVop3(&code, 0x301, 7, Vgpr(12), 255u);
code.push_back(literal);
store_result(7, extended, 33u);
}
AppendVop3(&code, 0x301, 7, Vgpr(12), 193u);
store_result(7, UINT64_MAX, 33u);
AppendVMovLiteral(&code, 7, static_cast<u32>(value));
AppendVMovLiteral(&code, 8, static_cast<u32>(value >> 32u));
AppendVop3(&code, 0x301, 7, Vgpr(12), Vgpr(7));
store_result(7, value, 33u);
AppendEnd(&code);
test.initial.resize(test.expected.size());
test.opcodes = {O::S_MOV_B32, O::V_MOV_B32, O::BUFFER_LOAD_DWORD,
O::V_ASHRREV_I64, O::BUFFER_STORE_DWORD, O::S_ENDPGM};
test.required_spirv = {"OpShiftRightArithmetic", "OpTypeInt 64 0"};
return test;
}
TestCase VectorDynamicU64ShiftEdges() {
using O = ShaderOpcode;
TestCase test;
@@ -26944,10 +27005,12 @@ TestCase VectorDynamicU64ShiftEdges() {
// A buffer load prevents the constant-shift specialization.
AppendVMovU32(&code, 30, index * sizeof(u32));
AppendBufferLoadDword(&code, 3, 30);
for (const bool left : {true, false}) {
AppendVop3(&code, left ? 0x2ff : 0x300, 33, Vgpr(3), Vgpr(4));
for (const u32 opcode : {0x2ffu, 0x300u, 0x301u}) {
AppendVop3(&code, opcode, 33, Vgpr(3), Vgpr(4));
const auto amount = test.initial[index] & 63u;
const auto expected = left ? source << amount : source >> amount;
const auto expected = opcode == 0x2ffu ? source << amount
: opcode == 0x300u ? source >> amount
: ReferenceAshrI64(source, amount);
const auto output = static_cast<u32>(test.expected.size());
AppendStoreVgpr(&code, 33, output);
AppendStoreVgpr(&code, 34, output + 1u);
@@ -26959,9 +27022,10 @@ TestCase VectorDynamicU64ShiftEdges() {
AppendEnd(&code);
test.initial.resize(test.expected.size());
test.opcodes = {O::V_MOV_B32, O::BUFFER_LOAD_DWORD, O::V_LSHLREV_B64,
O::V_LSHRREV_B64, O::BUFFER_STORE_DWORD, O::S_ENDPGM};
O::V_LSHRREV_B64, O::V_ASHRREV_I64,
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
test.required_spirv = {"OpShiftLeftLogical", "OpShiftRightLogical",
"OpTypeInt 64 0"};
"OpShiftRightArithmetic", "OpTypeInt 64 0"};
return test;
}
@@ -45911,6 +45975,7 @@ std::vector<TestCase> MakeCases() {
cases.push_back(ScalarAshrI64Masks(32));
cases.push_back(ScalarAshrI64Masks(64));
AddCase(VectorDynamicU64ShiftEdges);
AddCase(VectorVop3AshrrevI64Operands);
AddCase(ScalarConditionalMoveB64);
AddCase(ScalarConditionalMoveB64PreservesMasks);
AddCase(ScalarAndn2B64SccUsesMaskShadow);
@@ -53094,6 +53159,7 @@ int main(int argc, char **argv) {
VulkanHarness vulkan;
RunCase(&vulkan, ScalarDynamic64BitOps());
RunCase(&vulkan, VectorDynamicU64ShiftEdges());
RunCase(&vulkan, VectorVop3AshrrevI64Operands());
RunCase(&vulkan, ScalarAshrI64Edges(false));
RunCase(&vulkan, ScalarAshrI64Edges(true));
RunCase(&vulkan, VectorCompareInteger64Edges());
+37
View File
@@ -10550,6 +10550,43 @@ void TestNewShaderRecompilerNativeU64Translation() {
"captured VOP3 V_LSHLREV_B64 was not present in the decoded dump");
CheckSpirvBinaryValidates(result.spirv);
const uint32_t ashrrev_i64_shader[] = {
0xd7010001u, 0x0000d50cu,
EncodeSopp(0x01),
};
Decoder::Instruction decoded_ashrrev_i64;
ShaderRecompiler::Decoder::DecodeInstruction(ashrrev_i64_shader, 0u,
decoded_ashrrev_i64);
Check(decoded_ashrrev_i64.opcode == Decoder::Opcode::V_ASHRREV_I64 &&
decoded_ashrrev_i64.dst.kind == Decoder::OperandKind::Vgpr &&
decoded_ashrrev_i64.dst.reg == 1u &&
decoded_ashrrev_i64.src_count == 2u &&
decoded_ashrrev_i64.src0.kind == Decoder::OperandKind::Vgpr &&
decoded_ashrrev_i64.src0.reg == 12u &&
decoded_ashrrev_i64.src1.kind == Decoder::OperandKind::VccLo,
"decoder rejected VOP3 V_ASHRREV_I64 fields");
result = RecompileForTest(ashrrev_i64_shader, options);
Check((result.decoded_dump.find("V_ASHRREV_I64 v1, v12, vcc_lo") != std::string::npos),
"VOP3 V_ASHRREV_I64 was not present in the decoded dump");
CheckSpirvBinaryValidates(result.spirv);
const uint32_t ashrrev_captured[] = {0xd7010007u, 0x00020498u, EncodeSopp(0x01)};
Decoder::Instruction decoded_ashrrev_captured;
ShaderRecompiler::Decoder::DecodeInstruction(ashrrev_captured, 0u,
decoded_ashrrev_captured);
Check(decoded_ashrrev_captured.opcode == Decoder::Opcode::V_ASHRREV_I64 &&
decoded_ashrrev_captured.family == Decoder::Family::VOP3 &&
decoded_ashrrev_captured.src_count == 2u &&
decoded_ashrrev_captured.dst.kind == Decoder::OperandKind::Vgpr &&
decoded_ashrrev_captured.dst.reg == 7u &&
decoded_ashrrev_captured.src0.kind == Decoder::OperandKind::IntegerInlineConstant &&
decoded_ashrrev_captured.src0.value == 24u &&
decoded_ashrrev_captured.src1.kind == Decoder::OperandKind::Vgpr &&
decoded_ashrrev_captured.src1.reg == 2u,
"captured VOP3 V_ASHRREV_I64 opcode 0x301 was not decoded");
result = RecompileForTest(ashrrev_captured, options);
CheckSpirvBinaryValidates(result.spirv);
const uint32_t cmpx_i64_shader[] = {
0xd4b5007eu, 0x00020e80u, // v_cmpx_ne_i64 exec, 0, v[7:8]
EncodeSopp(0x01),