mirror of
https://github.com/PabloMK7/citra
synced 2024-11-15 05:08:23 +00:00
shader_jit_a64: Optimize conditional tests (#229)
These conditional tests are a 1:1 translation from the x64 code but do not have to be. Reference-values are known at emit-time and can be embedded as an immediate into an `EOR` instruction rather than moved into a register. The `TST` instruction can be utilized to more optimally test and update the `EQ`/`NE` status flags.
This commit is contained in:
parent
e55e619328
commit
f248fefe06
2 changed files with 19 additions and 18 deletions
|
@ -386,35 +386,33 @@ void JitShader::Compile_SanitizedMul(QReg src1, QReg src2, QReg scratch0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitShader::Compile_EvaluateCondition(Instruction instr) {
|
void JitShader::Compile_EvaluateCondition(Instruction instr) {
|
||||||
// Note: NXOR is used below to check for equality
|
const u8 refx = instr.flow_control.refx.Value();
|
||||||
|
const u8 refy = instr.flow_control.refy.Value();
|
||||||
|
|
||||||
switch (instr.flow_control.op) {
|
switch (instr.flow_control.op) {
|
||||||
|
// Note: NXOR is used below to check for equality
|
||||||
case Instruction::FlowControlType::Or:
|
case Instruction::FlowControlType::Or:
|
||||||
MOV(XSCRATCH0, (instr.flow_control.refx.Value() ^ 1));
|
EOR(XSCRATCH0, COND0, refx ^ 1);
|
||||||
MOV(XSCRATCH1, (instr.flow_control.refy.Value() ^ 1));
|
EOR(XSCRATCH1, COND1, refy ^ 1);
|
||||||
EOR(XSCRATCH0, XSCRATCH0, COND0);
|
|
||||||
EOR(XSCRATCH1, XSCRATCH1, COND1);
|
|
||||||
ORR(XSCRATCH0, XSCRATCH0, XSCRATCH1);
|
ORR(XSCRATCH0, XSCRATCH0, XSCRATCH1);
|
||||||
|
CMP(XSCRATCH0, 0);
|
||||||
break;
|
break;
|
||||||
|
// Note: TST will AND two registers and set the EQ/NE flags on the result
|
||||||
case Instruction::FlowControlType::And:
|
case Instruction::FlowControlType::And:
|
||||||
MOV(XSCRATCH0, (instr.flow_control.refx.Value() ^ 1));
|
EOR(XSCRATCH0, COND0, refx ^ 1);
|
||||||
MOV(XSCRATCH1, (instr.flow_control.refy.Value() ^ 1));
|
EOR(XSCRATCH1, COND1, refy ^ 1);
|
||||||
EOR(XSCRATCH0, XSCRATCH0, COND0);
|
TST(XSCRATCH0, XSCRATCH1);
|
||||||
EOR(XSCRATCH1, XSCRATCH1, COND1);
|
|
||||||
AND(XSCRATCH0, XSCRATCH0, XSCRATCH1);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Instruction::FlowControlType::JustX:
|
case Instruction::FlowControlType::JustX:
|
||||||
MOV(XSCRATCH0, (instr.flow_control.refx.Value() ^ 1));
|
CMP(COND0, refx);
|
||||||
EOR(XSCRATCH0, XSCRATCH0, COND0);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Instruction::FlowControlType::JustY:
|
case Instruction::FlowControlType::JustY:
|
||||||
MOV(XSCRATCH0, (instr.flow_control.refy.Value() ^ 1));
|
CMP(COND1, refy);
|
||||||
EOR(XSCRATCH0, XSCRATCH0, COND1);
|
break;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
CMP(XSCRATCH0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitShader::Compile_UniformCondition(Instruction instr) {
|
void JitShader::Compile_UniformCondition(Instruction instr) {
|
||||||
|
|
|
@ -94,6 +94,9 @@ private:
|
||||||
*/
|
*/
|
||||||
void Compile_SanitizedMul(oaknut::QReg src1, oaknut::QReg src2, oaknut::QReg scratch0);
|
void Compile_SanitizedMul(oaknut::QReg src1, oaknut::QReg src2, oaknut::QReg scratch0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits the code to evaluate a conditional instruction and update the host's EQ/NE status-flags
|
||||||
|
*/
|
||||||
void Compile_EvaluateCondition(Instruction instr);
|
void Compile_EvaluateCondition(Instruction instr);
|
||||||
void Compile_UniformCondition(Instruction instr);
|
void Compile_UniformCondition(Instruction instr);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue