Merge pull request #1279 from FernandoS27/csetp
shader_decompiler: Implemented (Partialy) Control Codes and CSETP
This commit is contained in:
commit
0284cbe7ec
|
@ -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"),
|
||||||
|
|
|
@ -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,31 +2318,55 @@ private:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Type::PredicateSetPredicate: {
|
case OpCode::Type::PredicateSetPredicate: {
|
||||||
const std::string op_a =
|
switch (opcode->GetId()) {
|
||||||
GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0);
|
case OpCode::Id::PSETP: {
|
||||||
const std::string op_b =
|
const std::string op_a =
|
||||||
GetPredicateCondition(instr.psetp.pred29, instr.psetp.neg_pred29 != 0);
|
GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0);
|
||||||
|
const std::string op_b =
|
||||||
|
GetPredicateCondition(instr.psetp.pred29, instr.psetp.neg_pred29 != 0);
|
||||||
|
|
||||||
// We can't use the constant predicate as destination.
|
// We can't use the constant predicate as destination.
|
||||||
ASSERT(instr.psetp.pred3 != static_cast<u64>(Pred::UnusedIndex));
|
ASSERT(instr.psetp.pred3 != static_cast<u64>(Pred::UnusedIndex));
|
||||||
|
|
||||||
const std::string second_pred =
|
const std::string second_pred =
|
||||||
GetPredicateCondition(instr.psetp.pred39, instr.psetp.neg_pred39 != 0);
|
GetPredicateCondition(instr.psetp.pred39, instr.psetp.neg_pred39 != 0);
|
||||||
|
|
||||||
const std::string combiner = GetPredicateCombiner(instr.psetp.op);
|
const std::string combiner = GetPredicateCombiner(instr.psetp.op);
|
||||||
|
|
||||||
const std::string predicate =
|
const std::string predicate =
|
||||||
'(' + op_a + ") " + GetPredicateCombiner(instr.psetp.cond) + " (" + op_b + ')';
|
'(' + op_a + ") " + GetPredicateCombiner(instr.psetp.cond) + " (" + op_b + ')';
|
||||||
|
|
||||||
// Set the primary predicate to the result of Predicate OP SecondPredicate
|
// Set the primary predicate to the result of Predicate OP SecondPredicate
|
||||||
SetPredicate(instr.psetp.pred3,
|
SetPredicate(instr.psetp.pred3,
|
||||||
'(' + predicate + ") " + combiner + " (" + second_pred + ')');
|
'(' + predicate + ") " + combiner + " (" + second_pred + ')');
|
||||||
|
|
||||||
if (instr.psetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
|
if (instr.psetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
|
||||||
// Set the secondary predicate to the result of !Predicate OP SecondPredicate,
|
// Set the secondary predicate to the result of !Predicate OP SecondPredicate,
|
||||||
// if enabled
|
// if enabled
|
||||||
SetPredicate(instr.psetp.pred0,
|
SetPredicate(instr.psetp.pred0,
|
||||||
"!(" + predicate + ") " + combiner + " (" + second_pred + ')');
|
"!(" + predicate + ") " + combiner + " (" + second_pred + ')');
|
||||||
|
}
|
||||||
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue