mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 13:56:59 +01:00
shader: implement RDNA2 subvector loop mask and branch semantics
This commit is contained in:
@@ -22,6 +22,33 @@ Decoder::Operand ConditionOperand(Decoder::OperandKind kind) {
|
||||
|
||||
} // namespace
|
||||
|
||||
void Translator::S_SUBVECTOR_LOOP(const Decoder::Instruction& inst, bool begin) {
|
||||
const auto zero = IR::U32(IR::Value(0u));
|
||||
const auto lo = ir.GetExecLo();
|
||||
const auto hi = ir.GetExecHi();
|
||||
const auto saved = ReadU32(inst.dst);
|
||||
if (begin) {
|
||||
const auto low_active = ir.INotEqual(lo, zero);
|
||||
instruction_branch_condition = ir.IEqual(ir.BitwiseOr(lo, hi), zero);
|
||||
WriteRawU32(inst.dst, ir.Select(instruction_branch_condition, saved,
|
||||
ir.Select(low_active, hi, lo)));
|
||||
// Keep the ISA assignment order: SDST may itself name an EXEC half.
|
||||
WriteRawU32(ConditionOperand(Decoder::OperandKind::ExecHi),
|
||||
ir.Select(low_active, zero, ir.GetExecHi()));
|
||||
} else {
|
||||
const auto high_active = ir.INotEqual(hi, zero);
|
||||
instruction_branch_condition =
|
||||
ir.LogicalAnd(ir.LogicalNot(high_active), ir.INotEqual(saved, zero));
|
||||
WriteRawU32(ConditionOperand(Decoder::OperandKind::ExecHi),
|
||||
ir.Select(instruction_branch_condition, saved, hi));
|
||||
WriteRawU32(inst.dst,
|
||||
ir.Select(instruction_branch_condition, lo, ReadU32(inst.dst)));
|
||||
WriteRawU32(ConditionOperand(Decoder::OperandKind::ExecLo),
|
||||
ir.Select(high_active, saved,
|
||||
ir.Select(instruction_branch_condition, zero, ir.GetExecLo())));
|
||||
}
|
||||
}
|
||||
|
||||
void Translator::S_SAVEEXEC(const Decoder::Instruction& inst, IR::ValueOpcode operation,
|
||||
bool negate_exec, bool negate_source, bool write_64) {
|
||||
if (!write_64) {
|
||||
|
||||
@@ -11,6 +11,8 @@ bool Translator::EmitScalar(const Decoder::Instruction& inst) {
|
||||
case O::S_WQM_B64: S_WQM_B64(inst); return true;
|
||||
case O::S_GETPC_B64: S_GETPC_B64(inst); return true;
|
||||
case O::S_SETPC_B64: return true;
|
||||
case O::S_SUBVECTOR_LOOP_BEGIN: S_SUBVECTOR_LOOP(inst, true); return true;
|
||||
case O::S_SUBVECTOR_LOOP_END: S_SUBVECTOR_LOOP(inst, false); return true;
|
||||
case O::S_CSELECT_B32: S_CSELECT_B32(inst); return true;
|
||||
case O::S_CSELECT_B64: ScalarSelect64(inst, inst.src1); return true;
|
||||
case O::S_CMOV_B64: ScalarSelect64(inst, inst.dst); return true;
|
||||
|
||||
@@ -758,6 +758,10 @@ void Translator::AddBranchCondition(const CFG::BasicBlock& source, IR::BlockInfo
|
||||
case CFG::BranchCondition::VccNonZero: condition = ir.GetVcc(); break;
|
||||
case CFG::BranchCondition::ExecZero: condition = ir.LogicalNot(ir.GetExec()); break;
|
||||
case CFG::BranchCondition::ExecNonZero: condition = ir.GetExec(); break;
|
||||
case CFG::BranchCondition::ScalarInstruction:
|
||||
EXIT_IF(instruction_branch_condition.IsEmpty());
|
||||
condition = instruction_branch_condition;
|
||||
break;
|
||||
case CFG::BranchCondition::GotoVariable:
|
||||
if (source.terminator.goto_variable == UINT32_MAX) {
|
||||
EXIT("block %u reads an invalid goto variable", source.id);
|
||||
|
||||
@@ -212,6 +212,7 @@ private:
|
||||
bool V_CNDMASK_B32(const Decoder::Instruction& inst);
|
||||
bool PackB16(const Decoder::Instruction& inst, bool high0, bool high1);
|
||||
|
||||
void S_SUBVECTOR_LOOP(const Decoder::Instruction& inst, bool begin);
|
||||
void S_SAVEEXEC(const Decoder::Instruction& inst, IR::ValueOpcode operation, bool negate_exec,
|
||||
bool negate_source, bool write_64);
|
||||
void ADD_U32(const Decoder::Instruction& inst, bool vector, bool use_carry_in);
|
||||
@@ -252,6 +253,7 @@ private:
|
||||
|
||||
IR::Program& program;
|
||||
IR::IREmitter ir;
|
||||
IR::U1 instruction_branch_condition;
|
||||
Decoder::Opcode current_opcode = Decoder::Opcode::UNKNOWN;
|
||||
uint32_t current_pc = 0;
|
||||
uint32_t current_vector_limit = 1;
|
||||
|
||||
Reference in New Issue
Block a user