yuzu-emu
/
yuzu-mainline
Archived
1
0
Fork 0

Merge pull request #1279 from FernandoS27/csetp

shader_decompiler: Implemented (Partialy) Control Codes and CSETP
This commit is contained in:
bunnei 2018-09-18 22:10:48 -04:00 committed by GitHub
commit 0284cbe7ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 133 additions and 21 deletions

View File

@ -240,6 +240,41 @@ enum class FlowCondition : u64 {
Fcsm_Tr = 0x1C, // TODO(bunnei): What is this used for? Fcsm_Tr = 0x1C, // TODO(bunnei): What is this used for?
}; };
enum class ControlCode : u64 {
F = 0,
LT = 1,
EQ = 2,
LE = 3,
GT = 4,
NE = 5,
GE = 6,
Num = 7,
Nan = 8,
LTU = 9,
EQU = 10,
LEU = 11,
GTU = 12,
NEU = 13,
GEU = 14,
//
OFF = 16,
LO = 17,
SFF = 18,
LS = 19,
HI = 20,
SFT = 21,
HS = 22,
OFT = 23,
CSM_TA = 24,
CSM_TR = 25,
CSM_MX = 26,
FCSM_TA = 27,
FCSM_TR = 28,
FCSM_MX = 29,
RLE = 30,
RGT = 31,
};
enum class PredicateResultMode : u64 { enum class PredicateResultMode : u64 {
None = 0x0, None = 0x0,
NotZero = 0x3, NotZero = 0x3,
@ -554,6 +589,15 @@ union Instruction {
BitField<45, 2, PredOperation> op; BitField<45, 2, PredOperation> op;
} pset; } pset;
union {
BitField<0, 3, u64> pred0;
BitField<3, 3, u64> pred3;
BitField<8, 5, ControlCode> cc; // flag in cc
BitField<39, 3, u64> pred39;
BitField<42, 1, u64> neg_pred39;
BitField<45, 4, PredOperation> op; // op with pred39
} csetp;
union { union {
BitField<39, 3, u64> pred39; BitField<39, 3, u64> pred39;
BitField<42, 1, u64> neg_pred; BitField<42, 1, u64> neg_pred;
@ -881,6 +925,7 @@ union Instruction {
BitField<36, 5, u64> index; BitField<36, 5, u64> index;
} cbuf36; } cbuf36;
BitField<47, 1, u64> generates_cc;
BitField<61, 1, u64> is_b_imm; BitField<61, 1, u64> is_b_imm;
BitField<60, 1, u64> is_b_gpr; BitField<60, 1, u64> is_b_gpr;
BitField<59, 1, u64> is_c_gpr; BitField<59, 1, u64> is_c_gpr;
@ -1005,6 +1050,7 @@ public:
ISET_IMM, ISET_IMM,
PSETP, PSETP,
PSET, PSET,
CSETP,
XMAD_IMM, XMAD_IMM,
XMAD_CR, XMAD_CR,
XMAD_RC, XMAD_RC,
@ -1241,6 +1287,7 @@ private:
INST("0011011-0101----", Id::ISET_IMM, Type::IntegerSet, "ISET_IMM"), INST("0011011-0101----", Id::ISET_IMM, Type::IntegerSet, "ISET_IMM"),
INST("0101000010001---", Id::PSET, Type::PredicateSetRegister, "PSET"), INST("0101000010001---", Id::PSET, Type::PredicateSetRegister, "PSET"),
INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"), INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"),
INST("010100001010----", Id::CSETP, Type::PredicateSetPredicate, "CSETP"),
INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"), INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"),
INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"), INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"),
INST("010100010-------", Id::XMAD_RC, Type::Xmad, "XMAD_RC"), INST("010100010-------", Id::XMAD_RC, Type::Xmad, "XMAD_RC"),

View File

@ -236,6 +236,14 @@ private:
const std::string& suffix; const std::string& suffix;
}; };
enum class InternalFlag : u64 {
ZeroFlag = 0,
CarryFlag = 1,
OverflowFlag = 2,
NaNFlag = 3,
Amount
};
/** /**
* Used to manage shader registers that are emulated with GLSL. This class keeps track of the state * Used to manage shader registers that are emulated with GLSL. This class keeps track of the state
* of all registers (e.g. whether they are currently being used as Floats or Integers), and * of all registers (e.g. whether they are currently being used as Floats or Integers), and
@ -329,13 +337,19 @@ public:
void SetRegisterToInteger(const Register& reg, bool is_signed, u64 elem, void SetRegisterToInteger(const Register& reg, bool is_signed, u64 elem,
const std::string& value, u64 dest_num_components, const std::string& value, u64 dest_num_components,
u64 value_num_components, bool is_saturated = false, u64 value_num_components, bool is_saturated = false,
u64 dest_elem = 0, Register::Size size = Register::Size::Word) { u64 dest_elem = 0, Register::Size size = Register::Size::Word,
bool sets_cc = false) {
ASSERT_MSG(!is_saturated, "Unimplemented"); ASSERT_MSG(!is_saturated, "Unimplemented");
const std::string func{is_signed ? "intBitsToFloat" : "uintBitsToFloat"}; const std::string func{is_signed ? "intBitsToFloat" : "uintBitsToFloat"};
SetRegister(reg, elem, func + '(' + ConvertIntegerSize(value, size) + ')', SetRegister(reg, elem, func + '(' + ConvertIntegerSize(value, size) + ')',
dest_num_components, value_num_components, dest_elem); dest_num_components, value_num_components, dest_elem);
if (sets_cc) {
const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )";
SetInternalFlag(InternalFlag::ZeroFlag, zero_condition);
}
} }
/** /**
@ -352,6 +366,26 @@ public:
shader.AddLine(dest + " = " + src + ';'); shader.AddLine(dest + " = " + src + ';');
} }
std::string GetControlCode(const Tegra::Shader::ControlCode cc) const {
switch (cc) {
case Tegra::Shader::ControlCode::NEU:
return "!(" + GetInternalFlag(InternalFlag::ZeroFlag) + ')';
default:
LOG_CRITICAL(HW_GPU, "Unimplemented Control Code {}", static_cast<u32>(cc));
UNREACHABLE();
return "false";
}
}
std::string GetInternalFlag(const InternalFlag ii) const {
const u32 code = static_cast<u32>(ii);
return "internalFlag_" + std::to_string(code) + suffix;
}
void SetInternalFlag(const InternalFlag ii, const std::string& value) const {
shader.AddLine(GetInternalFlag(ii) + " = " + value + ';');
}
/** /**
* Writes code that does a output attribute assignment to register operation. Output attributes * Writes code that does a output attribute assignment to register operation. Output attributes
* are stored as floats, so this may require conversion. * are stored as floats, so this may require conversion.
@ -415,6 +449,12 @@ public:
} }
declarations.AddNewLine(); declarations.AddNewLine();
for (u32 ii = 0; ii < static_cast<u64>(InternalFlag::Amount); ii++) {
const InternalFlag code = static_cast<InternalFlag>(ii);
declarations.AddLine("bool " + GetInternalFlag(code) + " = false;");
}
declarations.AddNewLine();
for (const auto element : declr_input_attribute) { for (const auto element : declr_input_attribute) {
// TODO(bunnei): Use proper number of elements for these // TODO(bunnei): Use proper number of elements for these
u32 idx = u32 idx =
@ -1620,7 +1660,8 @@ private:
} }
regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1, regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1,
1, instr.alu.saturate_d, 0, instr.conversion.dest_size); 1, instr.alu.saturate_d, 0, instr.conversion.dest_size,
instr.generates_cc.Value() != 0);
break; break;
} }
case OpCode::Id::I2F_R: case OpCode::Id::I2F_R:
@ -2277,6 +2318,8 @@ private:
break; break;
} }
case OpCode::Type::PredicateSetPredicate: { case OpCode::Type::PredicateSetPredicate: {
switch (opcode->GetId()) {
case OpCode::Id::PSETP: {
const std::string op_a = const std::string op_a =
GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0); GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0);
const std::string op_b = const std::string op_b =
@ -2305,6 +2348,28 @@ private:
} }
break; break;
} }
case OpCode::Id::CSETP: {
const std::string pred =
GetPredicateCondition(instr.csetp.pred39, instr.csetp.neg_pred39 != 0);
const std::string combiner = GetPredicateCombiner(instr.csetp.op);
const std::string controlCode = regs.GetControlCode(instr.csetp.cc);
if (instr.csetp.pred3 != static_cast<u64>(Pred::UnusedIndex)) {
SetPredicate(instr.csetp.pred3,
'(' + controlCode + ") " + combiner + " (" + pred + ')');
}
if (instr.csetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
SetPredicate(instr.csetp.pred0,
"!(" + controlCode + ") " + combiner + " (" + pred + ')');
}
break;
}
default: {
LOG_CRITICAL(HW_GPU, "Unhandled predicate instruction: {}", opcode->GetName());
UNREACHABLE();
}
}
break;
}
case OpCode::Type::FloatSet: { case OpCode::Type::FloatSet: {
std::string op_a = instr.fset.neg_a ? "-" : ""; std::string op_a = instr.fset.neg_a ? "-" : "";
op_a += regs.GetRegisterAsFloat(instr.gpr8); op_a += regs.GetRegisterAsFloat(instr.gpr8);