mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-19 18:36:53 +02:00
shader: implement S_ORN2_SAVEEXEC_B32
This commit is contained in:
@@ -62,6 +62,7 @@ constexpr OpcodeMap SOP1_OPCODE_LIST[] = {
|
||||
{0x37u, Opcode::S_ANDN1_SAVEEXEC_B64},
|
||||
{0x3bu, Opcode::S_BITREPLICATE_B64_B32},
|
||||
{0x3cu, Opcode::S_AND_SAVEEXEC_B32},
|
||||
{0x40u, Opcode::S_ORN2_SAVEEXEC_B32},
|
||||
{0x44u, Opcode::S_ANDN1_SAVEEXEC_B32},
|
||||
};
|
||||
|
||||
|
||||
@@ -485,6 +485,7 @@ std::string InstructionToString(const Instruction& inst) {
|
||||
case Opcode::S_WQM_B64:
|
||||
case Opcode::S_QUADMASK_B64:
|
||||
case Opcode::S_AND_SAVEEXEC_B32:
|
||||
case Opcode::S_ORN2_SAVEEXEC_B32:
|
||||
case Opcode::S_ANDN1_SAVEEXEC_B32:
|
||||
case Opcode::S_AND_SAVEEXEC_B64:
|
||||
case Opcode::S_ORN2_SAVEEXEC_B64:
|
||||
|
||||
@@ -54,6 +54,7 @@ enum class Opcode {
|
||||
S_GETPC_B64,
|
||||
S_SETPC_B64,
|
||||
S_AND_SAVEEXEC_B32,
|
||||
S_ORN2_SAVEEXEC_B32,
|
||||
S_ANDN1_SAVEEXEC_B32,
|
||||
S_AND_SAVEEXEC_B64,
|
||||
S_ORN2_SAVEEXEC_B64,
|
||||
|
||||
@@ -24,27 +24,34 @@ Decoder::Operand ConditionOperand(Decoder::OperandKind kind) {
|
||||
|
||||
void Translator::S_SAVEEXEC(const Decoder::Instruction& inst, IR::ValueOpcode operation,
|
||||
bool negate_exec, bool negate_source, bool write_64) {
|
||||
if (!write_64) {
|
||||
// Read the encoded scalar word and preserve EXEC_HI, including in wave32.
|
||||
const auto old = ir.GetExecLo();
|
||||
const auto src = ReadU32(inst.src0);
|
||||
const auto lhs = negate_exec ? ir.BitwiseNot(old) : old;
|
||||
const auto rhs = negate_source ? ir.BitwiseNot(src) : src;
|
||||
IR::U32 result;
|
||||
switch (operation) {
|
||||
case IR::ValueOpcode::LogicalAnd: result = ir.BitwiseAnd(lhs, rhs); break;
|
||||
case IR::ValueOpcode::LogicalOr: result = ir.BitwiseOr(lhs, rhs); break;
|
||||
default: EXIT("unsupported SAVEEXEC operation");
|
||||
}
|
||||
WriteRawU32(inst.dst, old);
|
||||
WriteRawU32(ConditionOperand(Decoder::OperandKind::ExecLo), result);
|
||||
ir.SetScc(ir.INotEqual(result, IR::U32(IR::Value(0u))));
|
||||
return;
|
||||
}
|
||||
const auto old = ir.GetExec();
|
||||
const auto src = ReadMask(inst.src0);
|
||||
const auto lhs = negate_exec ? ir.LogicalNot(old) : old;
|
||||
const auto rhs = negate_source ? ir.LogicalNot(src) : src;
|
||||
auto result = IR::U1(ir.Emit(operation, {lhs, rhs}));
|
||||
if (write_64) {
|
||||
WriteMask(inst.dst, old, true);
|
||||
} else {
|
||||
WriteRawU32(inst.dst, ir.GetExecLo());
|
||||
if (program.wave_size == 64u) {
|
||||
const auto low_half =
|
||||
ir.ULessThan(IR::U32(ir.Emit(IR::ValueOpcode::LaneId)), IR::U32(IR::Value(32u)));
|
||||
result = IR::U1(ir.Emit(IR::ValueOpcode::SelectU1, {low_half, result, old}));
|
||||
}
|
||||
}
|
||||
const auto result = IR::U1(ir.Emit(operation, {lhs, rhs}));
|
||||
WriteMask(inst.dst, old, true);
|
||||
const auto mask = BallotMask(result);
|
||||
ir.SetExec(result);
|
||||
ir.SetExecLo(mask[0]);
|
||||
ir.SetExecHi(mask[1]);
|
||||
ir.SetScc(
|
||||
ir.INotEqual(write_64 ? ir.BitwiseOr(mask[0], mask[1]) : mask[0], IR::U32(IR::Value(0u))));
|
||||
ir.SetScc(ir.INotEqual(ir.BitwiseOr(mask[0], mask[1]), IR::U32(IR::Value(0u))));
|
||||
}
|
||||
|
||||
void Translator::ADD_U32(const Decoder::Instruction& inst, bool vector, bool use_carry_in) {
|
||||
|
||||
@@ -23,6 +23,9 @@ bool Translator::EmitScalar(const Decoder::Instruction& inst) {
|
||||
case O::S_ANDN1_SAVEEXEC_B32:
|
||||
S_SAVEEXEC(inst, IR::ValueOpcode::LogicalAnd, false, true, false);
|
||||
return true;
|
||||
case O::S_ORN2_SAVEEXEC_B32:
|
||||
S_SAVEEXEC(inst, IR::ValueOpcode::LogicalOr, true, false, false);
|
||||
return true;
|
||||
case O::S_AND_SAVEEXEC_B64:
|
||||
S_SAVEEXEC(inst, IR::ValueOpcode::LogicalAnd, false, false, true);
|
||||
return true;
|
||||
|
||||
@@ -14968,6 +14968,69 @@ TestCase ScalarOrn2SaveexecUsesSourceOrNotExec() {
|
||||
O::BUFFER_STORE_DWORD, O::S_ENDPGM}};
|
||||
}
|
||||
|
||||
TestCase ScalarOrn2SaveexecB32(u32 wave_size, u32 threads) {
|
||||
using O = ShaderOpcode;
|
||||
constexpr u32 exec_hi = 0xa5a55a5au;
|
||||
constexpr u32 vcc_hi = 0x13579bdfu;
|
||||
struct Case {
|
||||
u32 exec_lo, source, destination, result;
|
||||
};
|
||||
constexpr Case cases[] = {
|
||||
{0x8000000cu, 126, 106, 0xffffffffu}, // Captured vcc_lo, exec_lo.
|
||||
{0x0000000fu, 6, 6, 0xfffffff3u}, // Aliased SGPR source/destination.
|
||||
{0xffffffffu, 128, 8, 0}, // SCC ignores the nonzero high half.
|
||||
{0xffffffffu, 107, 8, vcc_hi},
|
||||
{0xffffffffu, 127, 8, exec_hi},
|
||||
{0xffffffffu, 253, 8, 1}, // SCC is a scalar value, not a mask.
|
||||
};
|
||||
TestCase test;
|
||||
test.name = wave_size == 64 ? "ScalarOrn2SaveexecB32Wave64"
|
||||
: threads == 32 ? "ScalarOrn2SaveexecB32Wave32"
|
||||
: "ScalarOrn2SaveexecB32PartialWave";
|
||||
auto &code = test.code;
|
||||
for (const auto &item : cases) {
|
||||
AppendVMovU32(&code, 2, 0);
|
||||
AppendSMovLiteral(&code, 126, item.exec_lo);
|
||||
AppendSMovLiteral(&code, 127, exec_hi);
|
||||
AppendSMovLiteral(&code, 107, vcc_hi);
|
||||
AppendSMovLiteral(&code, 6, 3);
|
||||
code.push_back(EncodeSopc(0x06, InlineU32(0), InlineU32(0)));
|
||||
code.push_back(item.source == 126 ? 0xbeea407eu
|
||||
: EncodeSop1(0x40, item.destination, item.source));
|
||||
const u32 snapshots[] = {item.destination, 126, 127, 107, 253};
|
||||
for (u32 i = 0; i < std::size(snapshots); ++i) {
|
||||
code.push_back(EncodeSMovB32(20 + i, snapshots[i]));
|
||||
}
|
||||
AppendVMovU32(&code, 2, 1);
|
||||
code.push_back(EncodeSop1(0x04, 126, 193u)); // Restore EXEC for readback.
|
||||
const u32 expected[] = {item.exec_lo, item.result, exec_hi, vcc_hi,
|
||||
item.result != 0 ? 1u : 0u};
|
||||
for (u32 i = 0; i < std::size(expected); ++i) {
|
||||
AppendStoreSgprAtLaneDwordOffset(&code, 20 + i, 0,
|
||||
static_cast<u32>(test.expected.size()));
|
||||
test.expected.insert(test.expected.end(), threads, expected[i]);
|
||||
}
|
||||
AppendStoreVgprAtLaneDwordOffset(&code, 2, 0,
|
||||
static_cast<u32>(test.expected.size()));
|
||||
for (u32 lane = 0; lane < threads; ++lane) {
|
||||
const u32 mask = lane < 32 ? item.result : exec_hi;
|
||||
test.expected.push_back((mask >> (lane % 32)) & 1u);
|
||||
}
|
||||
}
|
||||
AppendEnd(&code);
|
||||
test.initial.resize(test.expected.size());
|
||||
test.opcodes = {O::S_MOV_B32, O::S_MOV_B64, O::S_CMP_EQ_U32,
|
||||
O::S_ORN2_SAVEEXEC_B32, O::V_MOV_B32, O::V_LSHLREV_B32,
|
||||
O::V_ADD_NC_U32, O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
test.decoded_counts = {{"S_ORN2_SAVEEXEC_B32 vcc_lo, exec_lo", 1}};
|
||||
test.compute_info.threads_num[0] = threads;
|
||||
test.compute_info.threads_num[1] = test.compute_info.threads_num[2] = 1;
|
||||
test.compute_info.thread_ids_num = 1;
|
||||
test.compute_info.wave_size = wave_size;
|
||||
test.has_compute_info = true;
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase ScalarGetpcWritesNextInstructionPc() {
|
||||
using O = ShaderOpcode;
|
||||
|
||||
@@ -23993,6 +24056,9 @@ std::vector<TestCase> MakeCases() {
|
||||
AddCase(ScalarFlbitI32B32Gpu);
|
||||
AddCase(ScalarSaveExecOps);
|
||||
AddCase(ScalarOrn2SaveexecUsesSourceOrNotExec);
|
||||
cases.push_back(ScalarOrn2SaveexecB32(32, 32));
|
||||
cases.push_back(ScalarOrn2SaveexecB32(64, 64));
|
||||
cases.push_back(ScalarOrn2SaveexecB32(32, 4));
|
||||
AddCase(ScalarGetpcWritesNextInstructionPc);
|
||||
AddCase(ScalarBitfieldPack);
|
||||
AddCase(ScalarBrevB32PreservesScc);
|
||||
@@ -28448,6 +28514,9 @@ int main(int argc, char **argv) {
|
||||
RunCase(&vulkan, DispatcherIrreducibleControlFlow());
|
||||
RunCase(&vulkan, ScalarSaveExecOps());
|
||||
RunCase(&vulkan, ScalarOrn2SaveexecUsesSourceOrNotExec());
|
||||
RunCase(&vulkan, ScalarOrn2SaveexecB32(32, 32));
|
||||
RunCase(&vulkan, ScalarOrn2SaveexecB32(64, 64));
|
||||
RunCase(&vulkan, ScalarOrn2SaveexecB32(32, 4));
|
||||
RunCase(&vulkan, ScalarNotB64UpdatesScc());
|
||||
RunCase(&vulkan, ScalarSelectB64PreservesMaskProvenance());
|
||||
RunCase(&vulkan, ScalarConditionalMoveB64());
|
||||
|
||||
@@ -4033,6 +4033,16 @@ void TestNewShaderDecoderArchitecture() {
|
||||
Check(GetInstructionFamily(EncodeDs0(0x36)) == Family::DS,
|
||||
"decoder did not classify DS directly");
|
||||
|
||||
const uint32_t orn2_saveexec_code[] = {0xbeea407eu};
|
||||
Instruction orn2_saveexec;
|
||||
ShaderRecompiler::Decoder::DecodeInstruction(orn2_saveexec_code, 0u, orn2_saveexec);
|
||||
Check(orn2_saveexec.family == Family::SOP1 &&
|
||||
orn2_saveexec.opcode == Opcode::S_ORN2_SAVEEXEC_B32 &&
|
||||
orn2_saveexec.word_count == 1u && orn2_saveexec.src_count == 1u &&
|
||||
orn2_saveexec.dst.kind == OperandKind::VccLo &&
|
||||
orn2_saveexec.src0.kind == OperandKind::ExecLo,
|
||||
"decoder rejected or misdecoded captured S_ORN2_SAVEEXEC_B32");
|
||||
|
||||
const uint32_t offset_code[] = {0u, EncodeVop1(0x01, 2, 3)};
|
||||
Instruction direct;
|
||||
ShaderRecompiler::Decoder::DecodeInstruction(offset_code, 1u, direct);
|
||||
|
||||
Reference in New Issue
Block a user