Skip to content

[NFC][EarlyIfConverter] Replace boolean Predicate for a class #108519

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 20, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
258 changes: 121 additions & 137 deletions llvm/lib/CodeGen/EarlyIfConversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,18 @@ class SSAIfConv {
/// The branch condition determined by analyzeBranch.
SmallVector<MachineOperand, 4> Cond;

class PredicationStrategyBase {
public:
virtual bool canConvertIf(MachineBasicBlock *Tail) { return true; }
virtual bool canPredicateInstr(const MachineInstr &I) = 0;
virtual void predicateBlock(MachineBasicBlock *MBB,
ArrayRef<MachineOperand> Cond,
bool Reverse) = 0;
virtual ~PredicationStrategyBase() = default;
};

PredicationStrategyBase &Predicate;

private:
/// Instructions in Head that define values used by the conditional blocks.
/// The hoisted instructions must be inserted after these instructions.
Expand All @@ -137,10 +149,6 @@ class SSAIfConv {
/// and FBB.
MachineBasicBlock::iterator InsertionPoint;

/// Return true if all non-terminator instructions in MBB can be safely
/// speculated.
bool canSpeculateInstrs(MachineBasicBlock *MBB);

/// Return true if all non-terminator instructions in MBB can be safely
/// predicated.
bool canPredicateInstrs(MachineBasicBlock *MBB);
Expand All @@ -149,10 +157,6 @@ class SSAIfConv {
/// Return false if any dependency is incompatible with if conversion.
bool InstrDependenciesAllowIfConv(MachineInstr *I);

/// Predicate all instructions of the basic block with current condition
/// except for terminators. Reverse the condition if ReversePredicate is set.
void PredicateBlock(MachineBasicBlock *MBB, bool ReversePredicate);

/// Find a valid insertion point in Head.
bool findInsertionPoint();

Expand All @@ -163,7 +167,8 @@ class SSAIfConv {
void rewritePHIOperands();

public:
SSAIfConv(MachineFunction &MF) {
SSAIfConv(PredicationStrategyBase &Predicate, MachineFunction &MF)
: Predicate(Predicate) {
TII = MF.getSubtarget().getInstrInfo();
TRI = MF.getSubtarget().getRegisterInfo();
MRI = &MF.getRegInfo();
Expand All @@ -175,77 +180,14 @@ class SSAIfConv {

/// canConvertIf - If the sub-CFG headed by MBB can be if-converted,
/// initialize the internal state, and return true.
/// If predicate is set try to predicate the block otherwise try to
/// speculatively execute it.
bool canConvertIf(MachineBasicBlock *MBB, bool Predicate = false);
bool canConvertIf(MachineBasicBlock *MBB);

/// convertIf - If-convert the last block passed to canConvertIf(), assuming
/// it is possible. Add any blocks that are to be erased to RemoveBlocks.
void convertIf(SmallVectorImpl<MachineBasicBlock *> &RemoveBlocks,
bool Predicate = false);
void convertIf(SmallVectorImpl<MachineBasicBlock *> &RemoveBlocks);
};
} // end anonymous namespace


/// canSpeculateInstrs - Returns true if all the instructions in MBB can safely
/// be speculated. The terminators are not considered.
///
/// If instructions use any values that are defined in the head basic block,
/// the defining instructions are added to InsertAfter.
///
/// Any clobbered regunits are added to ClobberedRegUnits.
///
bool SSAIfConv::canSpeculateInstrs(MachineBasicBlock *MBB) {
// Reject any live-in physregs. It's probably CPSR/EFLAGS, and very hard to
// get right.
if (!MBB->livein_empty()) {
LLVM_DEBUG(dbgs() << printMBBReference(*MBB) << " has live-ins.\n");
return false;
}

unsigned InstrCount = 0;

// Check all instructions, except the terminators. It is assumed that
// terminators never have side effects or define any used register values.
for (MachineInstr &MI :
llvm::make_range(MBB->begin(), MBB->getFirstTerminator())) {
if (MI.isDebugInstr())
continue;

if (++InstrCount > BlockInstrLimit && !Stress) {
LLVM_DEBUG(dbgs() << printMBBReference(*MBB) << " has more than "
<< BlockInstrLimit << " instructions.\n");
return false;
}

// There shouldn't normally be any phis in a single-predecessor block.
if (MI.isPHI()) {
LLVM_DEBUG(dbgs() << "Can't hoist: " << MI);
return false;
}

// Don't speculate loads. Note that it may be possible and desirable to
// speculate GOT or constant pool loads that are guaranteed not to trap,
// but we don't support that for now.
if (MI.mayLoad()) {
LLVM_DEBUG(dbgs() << "Won't speculate load: " << MI);
return false;
}

// We never speculate stores, so an AA pointer isn't necessary.
bool DontMoveAcrossStore = true;
if (!MI.isSafeToMove(DontMoveAcrossStore)) {
LLVM_DEBUG(dbgs() << "Can't speculate: " << MI);
return false;
}

// Check for any dependencies on Head instructions.
if (!InstrDependenciesAllowIfConv(&MI))
return false;
}
return true;
}

/// Check that there is no dependencies preventing if conversion.
///
/// If instruction uses any values that are defined in the head basic block,
Expand Down Expand Up @@ -319,17 +261,8 @@ bool SSAIfConv::canPredicateInstrs(MachineBasicBlock *MBB) {
return false;
}

// Check that instruction is predicable
if (!TII->isPredicable(*I)) {
LLVM_DEBUG(dbgs() << "Isn't predicable: " << *I);
return false;
}

// Check that instruction is not already predicated.
if (TII->isPredicated(*I) && !TII->canPredicatePredicatedInstr(*I)) {
LLVM_DEBUG(dbgs() << "Is already predicated: " << *I);
if (!Predicate.canPredicateInstr(*I))
return false;
}

// Check for any dependencies on Head instructions.
if (!InstrDependenciesAllowIfConv(&(*I)))
Expand All @@ -338,24 +271,6 @@ bool SSAIfConv::canPredicateInstrs(MachineBasicBlock *MBB) {
return true;
}

// Apply predicate to all instructions in the machine block.
void SSAIfConv::PredicateBlock(MachineBasicBlock *MBB, bool ReversePredicate) {
auto Condition = Cond;
if (ReversePredicate) {
bool CanRevCond = !TII->reverseBranchCondition(Condition);
assert(CanRevCond && "Reversed predicate is not supported");
(void)CanRevCond;
}
// Terminators don't need to be predicated as they will be removed.
for (MachineBasicBlock::iterator I = MBB->begin(),
E = MBB->getFirstTerminator();
I != E; ++I) {
if (I->isDebugInstr())
continue;
TII->PredicateInstruction(*I, Condition);
}
}

/// Find an insertion point in Head for the speculated instructions. The
/// insertion point must be:
///
Expand Down Expand Up @@ -434,7 +349,7 @@ bool SSAIfConv::findInsertionPoint() {
/// canConvertIf - analyze the sub-cfg rooted in MBB, and return true if it is
/// a potential candidate for if-conversion. Fill out the internal state.
///
bool SSAIfConv::canConvertIf(MachineBasicBlock *MBB, bool Predicate) {
bool SSAIfConv::canConvertIf(MachineBasicBlock *MBB) {
Head = MBB;
TBB = FBB = Tail = nullptr;

Expand Down Expand Up @@ -474,21 +389,17 @@ bool SSAIfConv::canConvertIf(MachineBasicBlock *MBB, bool Predicate) {
<< printMBBReference(*Tail) << '\n');
}

// This is a triangle or a diamond.
// Skip if we cannot predicate and there are no phis skip as there must be
// side effects that can only be handled with predication.
if (!Predicate && (Tail->empty() || !Tail->front().isPHI())) {
LLVM_DEBUG(dbgs() << "No phis in tail.\n");
return false;
}

// The branch we're looking to eliminate must be analyzable.
Cond.clear();
if (TII->analyzeBranch(*Head, TBB, FBB, Cond)) {
LLVM_DEBUG(dbgs() << "Branch not analyzable.\n");
return false;
}

if (!Predicate.canConvertIf(Tail)) {
return false;
}

// This is weird, probably some sort of degenerate CFG.
if (!TBB) {
LLVM_DEBUG(dbgs() << "analyzeBranch didn't find conditional branch.\n");
Expand Down Expand Up @@ -536,17 +447,9 @@ bool SSAIfConv::canConvertIf(MachineBasicBlock *MBB, bool Predicate) {
// Check that the conditional instructions can be speculated.
InsertAfter.clear();
ClobberedRegUnits.reset();
if (Predicate) {
if (TBB != Tail && !canPredicateInstrs(TBB))
for (MachineBasicBlock *MBB : {TBB, FBB})
if (MBB != Tail && !canPredicateInstrs(MBB))
return false;
if (FBB != Tail && !canPredicateInstrs(FBB))
return false;
} else {
if (TBB != Tail && !canSpeculateInstrs(TBB))
return false;
if (FBB != Tail && !canSpeculateInstrs(FBB))
return false;
}

// Try to find a valid insertion point for the speculated instructions in the
// head basic block.
Expand Down Expand Up @@ -679,8 +582,7 @@ void SSAIfConv::rewritePHIOperands() {
///
/// Any basic blocks that need to be erased will be added to RemoveBlocks.
///
void SSAIfConv::convertIf(SmallVectorImpl<MachineBasicBlock *> &RemoveBlocks,
bool Predicate) {
void SSAIfConv::convertIf(SmallVectorImpl<MachineBasicBlock *> &RemoveBlocks) {
assert(Head && Tail && TBB && FBB && "Call canConvertIf first.");

// Update statistics.
Expand All @@ -690,16 +592,15 @@ void SSAIfConv::convertIf(SmallVectorImpl<MachineBasicBlock *> &RemoveBlocks,
++NumDiamondsConv;

// Move all instructions into Head, except for the terminators.
if (TBB != Tail) {
if (Predicate)
PredicateBlock(TBB, /*ReversePredicate=*/false);
Head->splice(InsertionPoint, TBB, TBB->begin(), TBB->getFirstTerminator());
}
if (FBB != Tail) {
if (Predicate)
PredicateBlock(FBB, /*ReversePredicate=*/true);
Head->splice(InsertionPoint, FBB, FBB->begin(), FBB->getFirstTerminator());
for (MachineBasicBlock *MBB : {TBB, FBB}) {
if (MBB != Tail) {
// reverse the condition for the false bb
Predicate.predicateBlock(MBB, Cond, MBB == FBB);
Head->splice(InsertionPoint, MBB, MBB->begin(),
MBB->getFirstTerminator());
}
}

// Are there extra Tail predecessors?
bool ExtraPreds = Tail->pred_size() != 2;
if (ExtraPreds)
Expand Down Expand Up @@ -863,6 +764,46 @@ template <typename Remark> Remark &operator<<(Remark &R, Cycles C) {
}
} // anonymous namespace

class SpeculateStrategy : public SSAIfConv::PredicationStrategyBase {
public:
bool canConvertIf(MachineBasicBlock *Tail) override {
// This is a triangle or a diamond.
// Skip if we cannot predicate and there are no phis skip as there must
// be side effects that can only be handled with predication.
if (Tail->empty() || !Tail->front().isPHI()) {
LLVM_DEBUG(dbgs() << "No phis in tail.\n");
return false;
}
return true;
}

bool canPredicateInstr(const MachineInstr &I) override {
// Don't speculate loads. Note that it may be possible and desirable to
// speculate GOT or constant pool loads that are guaranteed not to trap,
// but we don't support that for now.
if (I.mayLoad()) {
LLVM_DEBUG(dbgs() << "Won't speculate load: " << I);
return false;
}

// We never speculate stores, so an AA pointer isn't necessary.
bool DontMoveAcrossStore = true;
if (!I.isSafeToMove(DontMoveAcrossStore)) {
LLVM_DEBUG(dbgs() << "Can't speculate: " << I);
return false;
}
return true;
}

void predicateBlock(MachineBasicBlock *MBB, ArrayRef<MachineOperand> Cond,
bool Reverse)
override { /* do nothing, everything is speculatable and it's valid to
move the instructions into the head */
}

~SpeculateStrategy() override = default;
};

/// Apply cost model and heuristics to the if-conversion in IfConv.
/// Return true if the conversion is a good idea.
///
Expand Down Expand Up @@ -1096,7 +1037,8 @@ bool EarlyIfConverter::runOnMachineFunction(MachineFunction &MF) {
MinInstr = nullptr;

bool Changed = false;
SSAIfConv IfConv(MF);
SpeculateStrategy Speculate;
SSAIfConv IfConv(Speculate, MF);

// Visit blocks in dominator tree post-order. The post-order enables nested
// if-conversion in a single pass. The tryConvertIf() function may erase
Expand Down Expand Up @@ -1158,6 +1100,48 @@ void EarlyIfPredicator::getAnalysisUsage(AnalysisUsage &AU) const {
MachineFunctionPass::getAnalysisUsage(AU);
}

class PredicatorStrategy : public SSAIfConv::PredicationStrategyBase {
const TargetInstrInfo *TII = nullptr;

public:
PredicatorStrategy(const TargetInstrInfo *TII) : TII(TII) {}

bool canPredicateInstr(const MachineInstr &I) override {
// Check that instruction is predicable
if (!TII->isPredicable(I)) {
LLVM_DEBUG(dbgs() << "Isn't predicable: " << I);
return false;
}

// Check that instruction is not already predicated.
if (TII->isPredicated(I) && !TII->canPredicatePredicatedInstr(I)) {
LLVM_DEBUG(dbgs() << "Is already predicated: " << I);
return false;
}
return true;
}

void predicateBlock(MachineBasicBlock *MBB, ArrayRef<MachineOperand> Cond,
bool Reverse) override {
SmallVector<MachineOperand> Condition(Cond.begin(), Cond.end());
if (Reverse) {
bool CanRevCond = !TII->reverseBranchCondition(Condition);
assert(CanRevCond && "Reversed predicate is not supported");
(void)CanRevCond;
}
// Terminators don't need to be predicated as they will be removed.
for (MachineBasicBlock::iterator I = MBB->begin(),
E = MBB->getFirstTerminator();
I != E; ++I) {
if (I->isDebugInstr())
continue;
TII->PredicateInstruction(*I, Condition);
}
}

~PredicatorStrategy() override = default;
};

/// Apply the target heuristic to decide if the transformation is profitable.
bool EarlyIfPredicator::shouldConvertIf(SSAIfConv &IfConv) {
auto TrueProbability = MBPI->getEdgeProbability(IfConv.Head, IfConv.TBB);
Expand Down Expand Up @@ -1202,11 +1186,10 @@ bool EarlyIfPredicator::shouldConvertIf(SSAIfConv &IfConv) {
bool EarlyIfPredicator::tryConvertIf(SSAIfConv &IfConv,
MachineBasicBlock *MBB) {
bool Changed = false;
while (IfConv.canConvertIf(MBB, /*Predicate=*/true) &&
shouldConvertIf(IfConv)) {
while (IfConv.canConvertIf(MBB) && shouldConvertIf(IfConv)) {
// If-convert MBB and update analyses.
SmallVector<MachineBasicBlock *, 4> RemoveBlocks;
IfConv.convertIf(RemoveBlocks, /*Predicate=*/true);
IfConv.convertIf(RemoveBlocks);
Changed = true;
updateDomTree(DomTree, IfConv, RemoveBlocks);
for (MachineBasicBlock *MBB : RemoveBlocks)
Expand All @@ -1232,7 +1215,8 @@ bool EarlyIfPredicator::runOnMachineFunction(MachineFunction &MF) {
MBPI = &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();

bool Changed = false;
SSAIfConv IfConv(MF);
PredicatorStrategy Predicate(TII);
SSAIfConv IfConv(Predicate, MF);

// Visit blocks in dominator tree post-order. The post-order enables nested
// if-conversion in a single pass. The tryConvertIf() function may erase
Expand Down
Loading