summaryrefslogtreecommitdiff
path: root/llvm/lib/Transforms/Scalar/MergeICmps.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Transforms/Scalar/MergeICmps.cpp')
-rw-r--r--llvm/lib/Transforms/Scalar/MergeICmps.cpp196
1 files changed, 89 insertions, 107 deletions
diff --git a/llvm/lib/Transforms/Scalar/MergeICmps.cpp b/llvm/lib/Transforms/Scalar/MergeICmps.cpp
index 7f8b75ac8806..f13f24ad2027 100644
--- a/llvm/lib/Transforms/Scalar/MergeICmps.cpp
+++ b/llvm/lib/Transforms/Scalar/MergeICmps.cpp
@@ -176,40 +176,39 @@ BCEAtom visitICmpLoadOperand(Value *const Val, BaseIdentifier &BaseId) {
Offset);
}
-// A basic block with a comparison between two BCE atoms, e.g. `a == o.a` in the
-// example at the top.
-// The block might do extra work besides the atom comparison, in which case
-// doesOtherWork() returns true. Under some conditions, the block can be
-// split into the atom comparison part and the "other work" part
-// (see canSplit()).
+// A comparison between two BCE atoms, e.g. `a == o.a` in the example at the
+// top.
// Note: the terminology is misleading: the comparison is symmetric, so there
// is no real {l/r}hs. What we want though is to have the same base on the
// left (resp. right), so that we can detect consecutive loads. To ensure this
// we put the smallest atom on the left.
-class BCECmpBlock {
- public:
- BCECmpBlock() {}
+struct BCECmp {
+ BCEAtom Lhs;
+ BCEAtom Rhs;
+ int SizeBits;
+ const ICmpInst *CmpI;
- BCECmpBlock(BCEAtom L, BCEAtom R, int SizeBits)
- : Lhs_(std::move(L)), Rhs_(std::move(R)), SizeBits_(SizeBits) {
- if (Rhs_ < Lhs_) std::swap(Rhs_, Lhs_);
+ BCECmp(BCEAtom L, BCEAtom R, int SizeBits, const ICmpInst *CmpI)
+ : Lhs(std::move(L)), Rhs(std::move(R)), SizeBits(SizeBits), CmpI(CmpI) {
+ if (Rhs < Lhs) std::swap(Rhs, Lhs);
}
+};
- bool IsValid() const { return Lhs_.BaseId != 0 && Rhs_.BaseId != 0; }
+// A basic block with a comparison between two BCE atoms.
+// The block might do extra work besides the atom comparison, in which case
+// doesOtherWork() returns true. Under some conditions, the block can be
+// split into the atom comparison part and the "other work" part
+// (see canSplit()).
+class BCECmpBlock {
+ public:
+ typedef SmallDenseSet<const Instruction *, 8> InstructionSet;
- // Assert the block is consistent: If valid, it should also have
- // non-null members besides Lhs_ and Rhs_.
- void AssertConsistent() const {
- if (IsValid()) {
- assert(BB);
- assert(CmpI);
- assert(BranchI);
- }
- }
+ BCECmpBlock(BCECmp Cmp, BasicBlock *BB, InstructionSet BlockInsts)
+ : BB(BB), BlockInsts(std::move(BlockInsts)), Cmp(std::move(Cmp)) {}
- const BCEAtom &Lhs() const { return Lhs_; }
- const BCEAtom &Rhs() const { return Rhs_; }
- int SizeBits() const { return SizeBits_; }
+ const BCEAtom &Lhs() const { return Cmp.Lhs; }
+ const BCEAtom &Rhs() const { return Cmp.Rhs; }
+ int SizeBits() const { return Cmp.SizeBits; }
// Returns true if the block does other works besides comparison.
bool doesOtherWork() const;
@@ -222,8 +221,7 @@ class BCECmpBlock {
// be sunk below this instruction. By doing this, we know we can separate the
// BCE-cmp-block instructions from the non-BCE-cmp-block instructions in the
// block.
- bool canSinkBCECmpInst(const Instruction *, DenseSet<Instruction *> &,
- AliasAnalysis &AA) const;
+ bool canSinkBCECmpInst(const Instruction *, AliasAnalysis &AA) const;
// We can separate the BCE-cmp-block instructions and the non-BCE-cmp-block
// instructions. Split the old block and move all non-BCE-cmp-insts into the
@@ -231,54 +229,45 @@ class BCECmpBlock {
void split(BasicBlock *NewParent, AliasAnalysis &AA) const;
// The basic block where this comparison happens.
- BasicBlock *BB = nullptr;
- // The ICMP for this comparison.
- ICmpInst *CmpI = nullptr;
- // The terminating branch.
- BranchInst *BranchI = nullptr;
+ BasicBlock *BB;
+ // Instructions relating to the BCECmp and branch.
+ InstructionSet BlockInsts;
// The block requires splitting.
bool RequireSplit = false;
private:
- BCEAtom Lhs_;
- BCEAtom Rhs_;
- int SizeBits_ = 0;
+ BCECmp Cmp;
};
bool BCECmpBlock::canSinkBCECmpInst(const Instruction *Inst,
- DenseSet<Instruction *> &BlockInsts,
AliasAnalysis &AA) const {
- // If this instruction has side effects and its in middle of the BCE cmp block
- // instructions, then bail for now.
- if (Inst->mayHaveSideEffects()) {
+ // If this instruction may clobber the loads and is in middle of the BCE cmp
+ // block instructions, then bail for now.
+ if (Inst->mayWriteToMemory()) {
// Bail if this is not a simple load or store
if (!isSimpleLoadOrStore(Inst))
return false;
// Disallow stores that might alias the BCE operands
- MemoryLocation LLoc = MemoryLocation::get(Lhs_.LoadI);
- MemoryLocation RLoc = MemoryLocation::get(Rhs_.LoadI);
+ MemoryLocation LLoc = MemoryLocation::get(Cmp.Lhs.LoadI);
+ MemoryLocation RLoc = MemoryLocation::get(Cmp.Rhs.LoadI);
if (isModSet(AA.getModRefInfo(Inst, LLoc)) ||
isModSet(AA.getModRefInfo(Inst, RLoc)))
return false;
}
// Make sure this instruction does not use any of the BCE cmp block
// instructions as operand.
- for (auto BI : BlockInsts) {
- if (is_contained(Inst->operands(), BI))
- return false;
- }
- return true;
+ return llvm::none_of(Inst->operands(), [&](const Value *Op) {
+ const Instruction *OpI = dyn_cast<Instruction>(Op);
+ return OpI && BlockInsts.contains(OpI);
+ });
}
void BCECmpBlock::split(BasicBlock *NewParent, AliasAnalysis &AA) const {
- DenseSet<Instruction *> BlockInsts(
- {Lhs_.GEP, Rhs_.GEP, Lhs_.LoadI, Rhs_.LoadI, CmpI, BranchI});
llvm::SmallVector<Instruction *, 4> OtherInsts;
for (Instruction &Inst : *BB) {
if (BlockInsts.count(&Inst))
continue;
- assert(canSinkBCECmpInst(&Inst, BlockInsts, AA) &&
- "Split unsplittable block");
+ assert(canSinkBCECmpInst(&Inst, AA) && "Split unsplittable block");
// This is a non-BCE-cmp-block instruction. And it can be separated
// from the BCE-cmp-block instruction.
OtherInsts.push_back(&Inst);
@@ -291,11 +280,9 @@ void BCECmpBlock::split(BasicBlock *NewParent, AliasAnalysis &AA) const {
}
bool BCECmpBlock::canSplit(AliasAnalysis &AA) const {
- DenseSet<Instruction *> BlockInsts(
- {Lhs_.GEP, Rhs_.GEP, Lhs_.LoadI, Rhs_.LoadI, CmpI, BranchI});
for (Instruction &Inst : *BB) {
if (!BlockInsts.count(&Inst)) {
- if (!canSinkBCECmpInst(&Inst, BlockInsts, AA))
+ if (!canSinkBCECmpInst(&Inst, AA))
return false;
}
}
@@ -303,10 +290,6 @@ bool BCECmpBlock::canSplit(AliasAnalysis &AA) const {
}
bool BCECmpBlock::doesOtherWork() const {
- AssertConsistent();
- // All the instructions we care about in the BCE cmp block.
- DenseSet<Instruction *> BlockInsts(
- {Lhs_.GEP, Rhs_.GEP, Lhs_.LoadI, Rhs_.LoadI, CmpI, BranchI});
// TODO(courbet): Can we allow some other things ? This is very conservative.
// We might be able to get away with anything does not have any side
// effects outside of the basic block.
@@ -320,9 +303,9 @@ bool BCECmpBlock::doesOtherWork() const {
// Visit the given comparison. If this is a comparison between two valid
// BCE atoms, returns the comparison.
-BCECmpBlock visitICmp(const ICmpInst *const CmpI,
- const ICmpInst::Predicate ExpectedPredicate,
- BaseIdentifier &BaseId) {
+Optional<BCECmp> visitICmp(const ICmpInst *const CmpI,
+ const ICmpInst::Predicate ExpectedPredicate,
+ BaseIdentifier &BaseId) {
// The comparison can only be used once:
// - For intermediate blocks, as a branch condition.
// - For the final block, as an incoming value for the Phi.
@@ -330,65 +313,68 @@ BCECmpBlock visitICmp(const ICmpInst *const CmpI,
// other comparisons as we would create an orphan use of the value.
if (!CmpI->hasOneUse()) {
LLVM_DEBUG(dbgs() << "cmp has several uses\n");
- return {};
+ return None;
}
if (CmpI->getPredicate() != ExpectedPredicate)
- return {};
+ return None;
LLVM_DEBUG(dbgs() << "cmp "
<< (ExpectedPredicate == ICmpInst::ICMP_EQ ? "eq" : "ne")
<< "\n");
auto Lhs = visitICmpLoadOperand(CmpI->getOperand(0), BaseId);
if (!Lhs.BaseId)
- return {};
+ return None;
auto Rhs = visitICmpLoadOperand(CmpI->getOperand(1), BaseId);
if (!Rhs.BaseId)
- return {};
+ return None;
const auto &DL = CmpI->getModule()->getDataLayout();
- return BCECmpBlock(std::move(Lhs), std::move(Rhs),
- DL.getTypeSizeInBits(CmpI->getOperand(0)->getType()));
+ return BCECmp(std::move(Lhs), std::move(Rhs),
+ DL.getTypeSizeInBits(CmpI->getOperand(0)->getType()), CmpI);
}
// Visit the given comparison block. If this is a comparison between two valid
// BCE atoms, returns the comparison.
-BCECmpBlock visitCmpBlock(Value *const Val, BasicBlock *const Block,
- const BasicBlock *const PhiBlock,
- BaseIdentifier &BaseId) {
- if (Block->empty()) return {};
+Optional<BCECmpBlock> visitCmpBlock(Value *const Val, BasicBlock *const Block,
+ const BasicBlock *const PhiBlock,
+ BaseIdentifier &BaseId) {
+ if (Block->empty()) return None;
auto *const BranchI = dyn_cast<BranchInst>(Block->getTerminator());
- if (!BranchI) return {};
+ if (!BranchI) return None;
LLVM_DEBUG(dbgs() << "branch\n");
+ Value *Cond;
+ ICmpInst::Predicate ExpectedPredicate;
if (BranchI->isUnconditional()) {
// In this case, we expect an incoming value which is the result of the
// comparison. This is the last link in the chain of comparisons (note
// that this does not mean that this is the last incoming value, blocks
// can be reordered).
- auto *const CmpI = dyn_cast<ICmpInst>(Val);
- if (!CmpI) return {};
- LLVM_DEBUG(dbgs() << "icmp\n");
- auto Result = visitICmp(CmpI, ICmpInst::ICMP_EQ, BaseId);
- Result.CmpI = CmpI;
- Result.BranchI = BranchI;
- return Result;
+ Cond = Val;
+ ExpectedPredicate = ICmpInst::ICMP_EQ;
} else {
// In this case, we expect a constant incoming value (the comparison is
// chained).
const auto *const Const = cast<ConstantInt>(Val);
LLVM_DEBUG(dbgs() << "const\n");
- if (!Const->isZero()) return {};
+ if (!Const->isZero()) return None;
LLVM_DEBUG(dbgs() << "false\n");
- auto *const CmpI = dyn_cast<ICmpInst>(BranchI->getCondition());
- if (!CmpI) return {};
- LLVM_DEBUG(dbgs() << "icmp\n");
assert(BranchI->getNumSuccessors() == 2 && "expecting a cond branch");
BasicBlock *const FalseBlock = BranchI->getSuccessor(1);
- auto Result = visitICmp(
- CmpI, FalseBlock == PhiBlock ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE,
- BaseId);
- Result.CmpI = CmpI;
- Result.BranchI = BranchI;
- return Result;
+ Cond = BranchI->getCondition();
+ ExpectedPredicate =
+ FalseBlock == PhiBlock ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE;
}
- return {};
+
+ auto *CmpI = dyn_cast<ICmpInst>(Cond);
+ if (!CmpI) return None;
+ LLVM_DEBUG(dbgs() << "icmp\n");
+
+ Optional<BCECmp> Result = visitICmp(CmpI, ExpectedPredicate, BaseId);
+ if (!Result)
+ return None;
+
+ BCECmpBlock::InstructionSet BlockInsts(
+ {Result->Lhs.GEP, Result->Rhs.GEP, Result->Lhs.LoadI, Result->Rhs.LoadI,
+ Result->CmpI, BranchI});
+ return BCECmpBlock(std::move(*Result), Block, BlockInsts);
}
static inline void enqueueBlock(std::vector<BCECmpBlock> &Comparisons,
@@ -440,18 +426,16 @@ BCECmpChain::BCECmpChain(const std::vector<BasicBlock *> &Blocks, PHINode &Phi,
// Now look inside blocks to check for BCE comparisons.
std::vector<BCECmpBlock> Comparisons;
BaseIdentifier BaseId;
- for (size_t BlockIdx = 0; BlockIdx < Blocks.size(); ++BlockIdx) {
- BasicBlock *const Block = Blocks[BlockIdx];
+ for (BasicBlock *const Block : Blocks) {
assert(Block && "invalid block");
- BCECmpBlock Comparison = visitCmpBlock(Phi.getIncomingValueForBlock(Block),
- Block, Phi.getParent(), BaseId);
- Comparison.BB = Block;
- if (!Comparison.IsValid()) {
+ Optional<BCECmpBlock> Comparison = visitCmpBlock(
+ Phi.getIncomingValueForBlock(Block), Block, Phi.getParent(), BaseId);
+ if (!Comparison) {
LLVM_DEBUG(dbgs() << "chain with invalid BCECmpBlock, no merge.\n");
return;
}
- if (Comparison.doesOtherWork()) {
- LLVM_DEBUG(dbgs() << "block '" << Comparison.BB->getName()
+ if (Comparison->doesOtherWork()) {
+ LLVM_DEBUG(dbgs() << "block '" << Comparison->BB->getName()
<< "' does extra work besides compare\n");
if (Comparisons.empty()) {
// This is the initial block in the chain, in case this block does other
@@ -467,15 +451,15 @@ BCECmpChain::BCECmpChain(const std::vector<BasicBlock *> &Blocks, PHINode &Phi,
// and start anew.
//
// NOTE: we only handle blocks a with single predecessor for now.
- if (Comparison.canSplit(AA)) {
+ if (Comparison->canSplit(AA)) {
LLVM_DEBUG(dbgs()
- << "Split initial block '" << Comparison.BB->getName()
+ << "Split initial block '" << Comparison->BB->getName()
<< "' that does extra work besides compare\n");
- Comparison.RequireSplit = true;
- enqueueBlock(Comparisons, std::move(Comparison));
+ Comparison->RequireSplit = true;
+ enqueueBlock(Comparisons, std::move(*Comparison));
} else {
LLVM_DEBUG(dbgs()
- << "ignoring initial block '" << Comparison.BB->getName()
+ << "ignoring initial block '" << Comparison->BB->getName()
<< "' that does extra work besides compare\n");
}
continue;
@@ -505,7 +489,7 @@ BCECmpChain::BCECmpChain(const std::vector<BasicBlock *> &Blocks, PHINode &Phi,
// We could still merge bb1 and bb2 though.
return;
}
- enqueueBlock(Comparisons, std::move(Comparison));
+ enqueueBlock(Comparisons, std::move(*Comparison));
}
// It is possible we have no suitable comparison to merge.
@@ -597,7 +581,7 @@ private:
append(BB->getName());
}
}
- return StringRef(Scratch);
+ return Scratch.str();
}
};
} // namespace
@@ -733,8 +717,7 @@ bool BCECmpChain::simplify(const TargetLibraryInfo &TLI, AliasAnalysis &AA,
// If the old cmp chain was the function entry, we need to update the function
// entry.
- const bool ChainEntryIsFnEntry =
- (EntryBlock_ == &EntryBlock_->getParent()->getEntryBlock());
+ const bool ChainEntryIsFnEntry = EntryBlock_->isEntryBlock();
if (ChainEntryIsFnEntry && DTU.hasDomTree()) {
LLVM_DEBUG(dbgs() << "Changing function entry from "
<< EntryBlock_->getName() << " to "
@@ -940,7 +923,6 @@ PreservedAnalyses MergeICmpsPass::run(Function &F,
if (!MadeChanges)
return PreservedAnalyses::all();
PreservedAnalyses PA;
- PA.preserve<GlobalsAA>();
PA.preserve<DominatorTreeAnalysis>();
return PA;
}