Skip to content

Commit 0d3807b

Browse files
committed
[MergeICmps] Separate out BCECmp and use Optional (NFC)
Separate out the BCECmp part from BCECmpBlock, which just stores the comparison atoms without the branch instruction. At the same time switch the code to return Optional<> rather than objects in invalid state and partially constructed objects.
1 parent 981e9dc commit 0d3807b

File tree

1 file changed

+73
-80
lines changed

1 file changed

+73
-80
lines changed

llvm/lib/Transforms/Scalar/MergeICmps.cpp

Lines changed: 73 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -176,40 +176,37 @@ BCEAtom visitICmpLoadOperand(Value *const Val, BaseIdentifier &BaseId) {
176176
Offset);
177177
}
178178

179-
// A basic block with a comparison between two BCE atoms, e.g. `a == o.a` in the
180-
// example at the top.
181-
// The block might do extra work besides the atom comparison, in which case
182-
// doesOtherWork() returns true. Under some conditions, the block can be
183-
// split into the atom comparison part and the "other work" part
184-
// (see canSplit()).
179+
// A comparison between two BCE atoms, e.g. `a == o.a` in the example at the
180+
// top.
185181
// Note: the terminology is misleading: the comparison is symmetric, so there
186182
// is no real {l/r}hs. What we want though is to have the same base on the
187183
// left (resp. right), so that we can detect consecutive loads. To ensure this
188184
// we put the smallest atom on the left.
189-
class BCECmpBlock {
190-
public:
191-
BCECmpBlock() {}
185+
struct BCECmp {
186+
BCEAtom Lhs;
187+
BCEAtom Rhs;
188+
int SizeBits;
189+
const ICmpInst *CmpI;
192190

193-
BCECmpBlock(BCEAtom L, BCEAtom R, int SizeBits)
194-
: Lhs_(std::move(L)), Rhs_(std::move(R)), SizeBits_(SizeBits) {
195-
if (Rhs_ < Lhs_) std::swap(Rhs_, Lhs_);
191+
BCECmp(BCEAtom L, BCEAtom R, int SizeBits, const ICmpInst *CmpI)
192+
: Lhs(std::move(L)), Rhs(std::move(R)), SizeBits(SizeBits), CmpI(CmpI) {
193+
if (Rhs < Lhs) std::swap(Rhs, Lhs);
196194
}
195+
};
197196

198-
bool IsValid() const { return Lhs_.BaseId != 0 && Rhs_.BaseId != 0; }
199-
200-
// Assert the block is consistent: If valid, it should also have
201-
// non-null members besides Lhs_ and Rhs_.
202-
void AssertConsistent() const {
203-
if (IsValid()) {
204-
assert(BB);
205-
assert(CmpI);
206-
assert(BranchI);
207-
}
208-
}
197+
// A basic block with a comparison between two BCE atoms.
198+
// The block might do extra work besides the atom comparison, in which case
199+
// doesOtherWork() returns true. Under some conditions, the block can be
200+
// split into the atom comparison part and the "other work" part
201+
// (see canSplit()).
202+
class BCECmpBlock {
203+
public:
204+
BCECmpBlock(BCECmp Cmp, BasicBlock *BB, BranchInst *BranchI)
205+
: BB(BB), BranchI(BranchI), Cmp(std::move(Cmp)) {}
209206

210-
const BCEAtom &Lhs() const { return Lhs_; }
211-
const BCEAtom &Rhs() const { return Rhs_; }
212-
int SizeBits() const { return SizeBits_; }
207+
const BCEAtom &Lhs() const { return Cmp.Lhs; }
208+
const BCEAtom &Rhs() const { return Cmp.Rhs; }
209+
int SizeBits() const { return Cmp.SizeBits; }
213210

214211
// Returns true if the block does other works besides comparison.
215212
bool doesOtherWork() const;
@@ -222,7 +219,7 @@ class BCECmpBlock {
222219
// be sunk below this instruction. By doing this, we know we can separate the
223220
// BCE-cmp-block instructions from the non-BCE-cmp-block instructions in the
224221
// block.
225-
bool canSinkBCECmpInst(const Instruction *, DenseSet<Instruction *> &,
222+
bool canSinkBCECmpInst(const Instruction *, DenseSet<const Instruction *> &,
226223
AliasAnalysis &AA) const;
227224

228225
// We can separate the BCE-cmp-block instructions and the non-BCE-cmp-block
@@ -231,22 +228,18 @@ class BCECmpBlock {
231228
void split(BasicBlock *NewParent, AliasAnalysis &AA) const;
232229

233230
// The basic block where this comparison happens.
234-
BasicBlock *BB = nullptr;
235-
// The ICMP for this comparison.
236-
ICmpInst *CmpI = nullptr;
231+
BasicBlock *BB;
237232
// The terminating branch.
238-
BranchInst *BranchI = nullptr;
233+
BranchInst *BranchI;
239234
// The block requires splitting.
240235
bool RequireSplit = false;
241236

242237
private:
243-
BCEAtom Lhs_;
244-
BCEAtom Rhs_;
245-
int SizeBits_ = 0;
238+
BCECmp Cmp;
246239
};
247240

248241
bool BCECmpBlock::canSinkBCECmpInst(const Instruction *Inst,
249-
DenseSet<Instruction *> &BlockInsts,
242+
DenseSet<const Instruction *> &BlockInsts,
250243
AliasAnalysis &AA) const {
251244
// If this instruction may clobber the loads and is in middle of the BCE cmp
252245
// block instructions, then bail for now.
@@ -255,8 +248,8 @@ bool BCECmpBlock::canSinkBCECmpInst(const Instruction *Inst,
255248
if (!isSimpleLoadOrStore(Inst))
256249
return false;
257250
// Disallow stores that might alias the BCE operands
258-
MemoryLocation LLoc = MemoryLocation::get(Lhs_.LoadI);
259-
MemoryLocation RLoc = MemoryLocation::get(Rhs_.LoadI);
251+
MemoryLocation LLoc = MemoryLocation::get(Cmp.Lhs.LoadI);
252+
MemoryLocation RLoc = MemoryLocation::get(Cmp.Rhs.LoadI);
260253
if (isModSet(AA.getModRefInfo(Inst, LLoc)) ||
261254
isModSet(AA.getModRefInfo(Inst, RLoc)))
262255
return false;
@@ -271,8 +264,9 @@ bool BCECmpBlock::canSinkBCECmpInst(const Instruction *Inst,
271264
}
272265

273266
void BCECmpBlock::split(BasicBlock *NewParent, AliasAnalysis &AA) const {
274-
DenseSet<Instruction *> BlockInsts(
275-
{Lhs_.GEP, Rhs_.GEP, Lhs_.LoadI, Rhs_.LoadI, CmpI, BranchI});
267+
DenseSet<const Instruction *> BlockInsts(
268+
{Cmp.Lhs.GEP, Cmp.Rhs.GEP, Cmp.Lhs.LoadI, Cmp.Rhs.LoadI, Cmp.CmpI,
269+
BranchI});
276270
llvm::SmallVector<Instruction *, 4> OtherInsts;
277271
for (Instruction &Inst : *BB) {
278272
if (BlockInsts.count(&Inst))
@@ -291,8 +285,9 @@ void BCECmpBlock::split(BasicBlock *NewParent, AliasAnalysis &AA) const {
291285
}
292286

293287
bool BCECmpBlock::canSplit(AliasAnalysis &AA) const {
294-
DenseSet<Instruction *> BlockInsts(
295-
{Lhs_.GEP, Rhs_.GEP, Lhs_.LoadI, Rhs_.LoadI, CmpI, BranchI});
288+
DenseSet<const Instruction *> BlockInsts(
289+
{Cmp.Lhs.GEP, Cmp.Rhs.GEP, Cmp.Lhs.LoadI, Cmp.Rhs.LoadI, Cmp.CmpI,
290+
BranchI});
296291
for (Instruction &Inst : *BB) {
297292
if (!BlockInsts.count(&Inst)) {
298293
if (!canSinkBCECmpInst(&Inst, BlockInsts, AA))
@@ -303,10 +298,10 @@ bool BCECmpBlock::canSplit(AliasAnalysis &AA) const {
303298
}
304299

305300
bool BCECmpBlock::doesOtherWork() const {
306-
AssertConsistent();
307301
// All the instructions we care about in the BCE cmp block.
308-
DenseSet<Instruction *> BlockInsts(
309-
{Lhs_.GEP, Rhs_.GEP, Lhs_.LoadI, Rhs_.LoadI, CmpI, BranchI});
302+
DenseSet<const Instruction *> BlockInsts(
303+
{Cmp.Lhs.GEP, Cmp.Rhs.GEP, Cmp.Lhs.LoadI, Cmp.Rhs.LoadI, Cmp.CmpI,
304+
BranchI});
310305
// TODO(courbet): Can we allow some other things ? This is very conservative.
311306
// We might be able to get away with anything does not have any side
312307
// effects outside of the basic block.
@@ -320,55 +315,55 @@ bool BCECmpBlock::doesOtherWork() const {
320315

321316
// Visit the given comparison. If this is a comparison between two valid
322317
// BCE atoms, returns the comparison.
323-
BCECmpBlock visitICmp(const ICmpInst *const CmpI,
324-
const ICmpInst::Predicate ExpectedPredicate,
325-
BaseIdentifier &BaseId) {
318+
Optional<BCECmp> visitICmp(const ICmpInst *const CmpI,
319+
const ICmpInst::Predicate ExpectedPredicate,
320+
BaseIdentifier &BaseId) {
326321
// The comparison can only be used once:
327322
// - For intermediate blocks, as a branch condition.
328323
// - For the final block, as an incoming value for the Phi.
329324
// If there are any other uses of the comparison, we cannot merge it with
330325
// other comparisons as we would create an orphan use of the value.
331326
if (!CmpI->hasOneUse()) {
332327
LLVM_DEBUG(dbgs() << "cmp has several uses\n");
333-
return {};
328+
return None;
334329
}
335330
if (CmpI->getPredicate() != ExpectedPredicate)
336-
return {};
331+
return None;
337332
LLVM_DEBUG(dbgs() << "cmp "
338333
<< (ExpectedPredicate == ICmpInst::ICMP_EQ ? "eq" : "ne")
339334
<< "\n");
340335
auto Lhs = visitICmpLoadOperand(CmpI->getOperand(0), BaseId);
341336
if (!Lhs.BaseId)
342-
return {};
337+
return None;
343338
auto Rhs = visitICmpLoadOperand(CmpI->getOperand(1), BaseId);
344339
if (!Rhs.BaseId)
345-
return {};
340+
return None;
346341
const auto &DL = CmpI->getModule()->getDataLayout();
347-
return BCECmpBlock(std::move(Lhs), std::move(Rhs),
348-
DL.getTypeSizeInBits(CmpI->getOperand(0)->getType()));
342+
return BCECmp(std::move(Lhs), std::move(Rhs),
343+
DL.getTypeSizeInBits(CmpI->getOperand(0)->getType()), CmpI);
349344
}
350345

351346
// Visit the given comparison block. If this is a comparison between two valid
352347
// BCE atoms, returns the comparison.
353-
BCECmpBlock visitCmpBlock(Value *const Val, BasicBlock *const Block,
354-
const BasicBlock *const PhiBlock,
355-
BaseIdentifier &BaseId) {
356-
if (Block->empty()) return {};
348+
Optional<BCECmpBlock> visitCmpBlock(Value *const Val, BasicBlock *const Block,
349+
const BasicBlock *const PhiBlock,
350+
BaseIdentifier &BaseId) {
351+
if (Block->empty()) return None;
357352
auto *const BranchI = dyn_cast<BranchInst>(Block->getTerminator());
358-
if (!BranchI) return {};
353+
if (!BranchI) return None;
359354
LLVM_DEBUG(dbgs() << "branch\n");
360355
if (BranchI->isUnconditional()) {
361356
// In this case, we expect an incoming value which is the result of the
362357
// comparison. This is the last link in the chain of comparisons (note
363358
// that this does not mean that this is the last incoming value, blocks
364359
// can be reordered).
365360
auto *const CmpI = dyn_cast<ICmpInst>(Val);
366-
if (!CmpI) return {};
361+
if (!CmpI) return None;
367362
LLVM_DEBUG(dbgs() << "icmp\n");
368-
auto Result = visitICmp(CmpI, ICmpInst::ICMP_EQ, BaseId);
369-
Result.CmpI = CmpI;
370-
Result.BranchI = BranchI;
371-
return Result;
363+
Optional<BCECmp> Result = visitICmp(CmpI, ICmpInst::ICMP_EQ, BaseId);
364+
if (!Result)
365+
return None;
366+
return BCECmpBlock(std::move(*Result), Block, BranchI);
372367
} else {
373368
// In this case, we expect a constant incoming value (the comparison is
374369
// chained).
@@ -381,14 +376,13 @@ BCECmpBlock visitCmpBlock(Value *const Val, BasicBlock *const Block,
381376
LLVM_DEBUG(dbgs() << "icmp\n");
382377
assert(BranchI->getNumSuccessors() == 2 && "expecting a cond branch");
383378
BasicBlock *const FalseBlock = BranchI->getSuccessor(1);
384-
auto Result = visitICmp(
379+
Optional<BCECmp> Result = visitICmp(
385380
CmpI, FalseBlock == PhiBlock ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE,
386381
BaseId);
387-
Result.CmpI = CmpI;
388-
Result.BranchI = BranchI;
389-
return Result;
382+
if (!Result)
383+
return None;
384+
return BCECmpBlock(std::move(*Result), Block, BranchI);
390385
}
391-
return {};
392386
}
393387

394388
static inline void enqueueBlock(std::vector<BCECmpBlock> &Comparisons,
@@ -442,15 +436,14 @@ BCECmpChain::BCECmpChain(const std::vector<BasicBlock *> &Blocks, PHINode &Phi,
442436
BaseIdentifier BaseId;
443437
for (BasicBlock *const Block : Blocks) {
444438
assert(Block && "invalid block");
445-
BCECmpBlock Comparison = visitCmpBlock(Phi.getIncomingValueForBlock(Block),
446-
Block, Phi.getParent(), BaseId);
447-
Comparison.BB = Block;
448-
if (!Comparison.IsValid()) {
439+
Optional<BCECmpBlock> Comparison = visitCmpBlock(
440+
Phi.getIncomingValueForBlock(Block), Block, Phi.getParent(), BaseId);
441+
if (!Comparison) {
449442
LLVM_DEBUG(dbgs() << "chain with invalid BCECmpBlock, no merge.\n");
450443
return;
451444
}
452-
if (Comparison.doesOtherWork()) {
453-
LLVM_DEBUG(dbgs() << "block '" << Comparison.BB->getName()
445+
if (Comparison->doesOtherWork()) {
446+
LLVM_DEBUG(dbgs() << "block '" << Comparison->BB->getName()
454447
<< "' does extra work besides compare\n");
455448
if (Comparisons.empty()) {
456449
// This is the initial block in the chain, in case this block does other
@@ -466,15 +459,15 @@ BCECmpChain::BCECmpChain(const std::vector<BasicBlock *> &Blocks, PHINode &Phi,
466459
// and start anew.
467460
//
468461
// NOTE: we only handle blocks a with single predecessor for now.
469-
if (Comparison.canSplit(AA)) {
462+
if (Comparison->canSplit(AA)) {
470463
LLVM_DEBUG(dbgs()
471-
<< "Split initial block '" << Comparison.BB->getName()
464+
<< "Split initial block '" << Comparison->BB->getName()
472465
<< "' that does extra work besides compare\n");
473-
Comparison.RequireSplit = true;
474-
enqueueBlock(Comparisons, std::move(Comparison));
466+
Comparison->RequireSplit = true;
467+
enqueueBlock(Comparisons, std::move(*Comparison));
475468
} else {
476469
LLVM_DEBUG(dbgs()
477-
<< "ignoring initial block '" << Comparison.BB->getName()
470+
<< "ignoring initial block '" << Comparison->BB->getName()
478471
<< "' that does extra work besides compare\n");
479472
}
480473
continue;
@@ -504,7 +497,7 @@ BCECmpChain::BCECmpChain(const std::vector<BasicBlock *> &Blocks, PHINode &Phi,
504497
// We could still merge bb1 and bb2 though.
505498
return;
506499
}
507-
enqueueBlock(Comparisons, std::move(Comparison));
500+
enqueueBlock(Comparisons, std::move(*Comparison));
508501
}
509502

510503
// It is possible we have no suitable comparison to merge.

0 commit comments

Comments
 (0)