mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 14:00:16 +02:00
RedundantFlagCalculationElimination: optimize parity
another global CFG-based optimization -- if we know that the raw PF is already 1-bit we can skip parity evaluation, saving work with floating point compares. Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
This commit is contained in:
1 parent
dd7c66db2e
commit
b36d1f7e7b
1 file changed
+68
@@ -157,6 +157,7 @@ private:
|
||||
void FoldBranch(IREmitter* IREmit, IRListView& CurrentIR, IROp_CondJump* Op, Ref CodeNode);
|
||||
CondClassType X86ToArmFloatCond(CondClassType X86);
|
||||
bool ProcessBlock(IREmitter* IREmit, IRListView& CurrentIR, Ref Block, ControlFlowGraph& CFG);
|
||||
void OptimizeParity(IREmitter* IREmit, IRListView& CurrentIR, ControlFlowGraph& CFG);
|
||||
};
|
||||
|
||||
unsigned DeadFlagCalculationEliminination::FlagsForCondClassType(CondClassType Cond) {
|
||||
@@ -635,6 +636,69 @@ bool DeadFlagCalculationEliminination::ProcessBlock(IREmitter* IREmit, IRListVie
|
||||
return (OldFlagsRead != FlagsRead);
|
||||
}
|
||||
|
||||
void DeadFlagCalculationEliminination::OptimizeParity(IREmitter* IREmit, IRListView& CurrentIR, ControlFlowGraph& CFG) {
|
||||
// Mapping for flags inside this pass.
|
||||
const uint8_t PARTIAL = 0;
|
||||
const uint8_t FULL = 1;
|
||||
|
||||
// Initialize conservatively: all blocks need full parity. This initialization
|
||||
// matters for proper handling of backedges.
|
||||
for (auto [Block, BlockHeader] : CurrentIR.GetBlocks()) {
|
||||
CFG.Get(Block)->Flags = FULL;
|
||||
}
|
||||
|
||||
for (auto [Block, BlockHeader] : CurrentIR.GetBlocks()) {
|
||||
bool Full = false;
|
||||
auto Predecessors = CFG.Get(Block)->Predecessors;
|
||||
|
||||
if (Predecessors.empty()) {
|
||||
// Conservatively assume there was full parity before the start block
|
||||
Full = true;
|
||||
} else {
|
||||
// If any predecessor needs full parity at the end, we need full parity.
|
||||
for (auto Pred : Predecessors) {
|
||||
Full |= (CFG.Get(Pred)->Flags == FULL);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto [CodeNode, IROp] : CurrentIR.GetCode(Block)) {
|
||||
if (IROp->Op == OP_STOREPF) {
|
||||
auto Op = IROp->CW<IR::IROp_StorePF>();
|
||||
auto Generator = CurrentIR.GetOp<IR::IROp_Header>(Op->Value);
|
||||
|
||||
// Determine if we only write 0/1 to the parity flag.
|
||||
Full = true;
|
||||
if (Generator->Op == OP_NZCVSELECT) {
|
||||
auto C0 = CurrentIR.GetOp<IR::IROp_Header>(Generator->Args[0]);
|
||||
auto C1 = CurrentIR.GetOp<IR::IROp_Header>(Generator->Args[1]);
|
||||
if (C0->Op == C1->Op && C0->Op == OP_INLINECONSTANT) {
|
||||
auto IC0 = CurrentIR.GetOp<IR::IROp_InlineConstant>(Generator->Args[0]);
|
||||
auto IC1 = CurrentIR.GetOp<IR::IROp_InlineConstant>(Generator->Args[1]);
|
||||
|
||||
// We need the full 8 if the constant has upper bits set.
|
||||
Full = (IC0->Constant | IC1->Constant) & ~1;
|
||||
}
|
||||
}
|
||||
} else if (IROp->Op == OP_PARITY && !Full) {
|
||||
// Eliminate parity calculations if it's only 1-bit.
|
||||
auto Parity = IROp->C<IROp_Parity>();
|
||||
Ref Value = CurrentIR.GetNode(Parity->Raw);
|
||||
|
||||
if (Parity->Invert) {
|
||||
IREmit->SetWriteCursor(CodeNode);
|
||||
Value = IREmit->_Xor(OpSize::i32Bit, Value, IREmit->_InlineConstant(1));
|
||||
}
|
||||
|
||||
IREmit->ReplaceUsesWithAfter(CodeNode, Value, CurrentIR.at(CodeNode));
|
||||
IREmit->Remove(CodeNode);
|
||||
}
|
||||
}
|
||||
|
||||
// Record our final state for our successors to read.
|
||||
CFG.Get(Block)->Flags = Full ? FULL : PARTIAL;
|
||||
}
|
||||
}
|
||||
|
||||
void DeadFlagCalculationEliminination::Run(IREmitter* IREmit) {
|
||||
FEXCORE_PROFILE_SCOPED("PassManager::DFE");
|
||||
|
||||
@@ -697,6 +761,10 @@ void DeadFlagCalculationEliminination::Run(IREmitter* IREmit) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (CurrentIR.GetHeader()->ReadsParity) {
|
||||
OptimizeParity(IREmit, CurrentIR, CFG);
|
||||
}
|
||||
}
|
||||
|
||||
fextl::unique_ptr<FEXCore::IR::Pass> CreateDeadFlagCalculationEliminination() {
|
||||
|
||||
Reference in new issue
Block a user