OpcodeDispatcher: eliminate branch in cmpxchg pair

In the old case:

* if we take the branch, 1 instruction
* if we don't take the branch, 3 instruction
* branch predictor fun
* 3 instructions of icache pressure

In the new case:

* unconditionally 2 instructions
* no branch predictor dependence
* 2 instructions of icache pressure

This should not be non-neglibly worse, and it simplifies things for RA.

Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
This commit is contained in:
Alyssa Rosenzweig committed 2024-03-27 12:40:06 -04:00
1 parent 7b74ca1931
commit 61758ea47d
1 file changed
+8 -16
@@ -4270,23 +4270,15 @@ void OpDispatchBuilder::CMPXCHGPairOp(OpcodeArgs) {
SetRFLAG<FEXCore::X86State::RFLAG_ZF_RAW_LOC>(ZFResult);
CalculateDeferredFlags();
auto CondJump_ = CondJump(ZFResult);
auto UpdateIfNotZF = [this](auto Reg, auto Value) {
// Always use 64-bit csel to preserve existing upper bits. If we have a
// 32-bit cmpxchg in a 64-bit context, Value will be zeroed in upper bits.
StoreGPRRegister(Reg, _NZCVSelect(OpSize::i64Bit, CondClassType{COND_NEQ},
Value, LoadGPRRegister(Reg)));
};
// Make sure to start a new block after ending this one
auto JumpTarget = CreateNewCodeBlockAfter(GetCurrentBlock());
SetFalseJumpTarget(CondJump_, JumpTarget);
SetCurrentCodeBlock(JumpTarget);
StartNewBlock();
StoreGPRRegister(X86State::REG_RAX, Result_Lower);
StoreGPRRegister(X86State::REG_RDX, Result_Upper);
auto Jump_ = Jump();
auto NextJumpTarget = CreateNewCodeBlockAfter(JumpTarget);
SetJumpTarget(Jump_, NextJumpTarget);
SetTrueJumpTarget(CondJump_, NextJumpTarget);
SetCurrentCodeBlock(NextJumpTarget);
StartNewBlock();
UpdateIfNotZF(X86State::REG_RAX, Result_Lower);
UpdateIfNotZF(X86State::REG_RDX, Result_Upper);
}
void OpDispatchBuilder::CreateJumpBlocks(fextl::vector<FEXCore::Frontend::Decoder::DecodedBlocks> const *Blocks) {