51
51
#include " llvm/Analysis/ValueTracking.h"
52
52
#include " llvm/IR/ConstantRange.h"
53
53
#include " llvm/IR/Dominators.h"
54
+ #include " llvm/IR/IRBuilder.h"
54
55
#include " llvm/IR/IntrinsicInst.h"
55
56
#include " llvm/IR/PatternMatch.h"
56
57
#include " llvm/InitializePasses.h"
@@ -123,10 +124,12 @@ static void eliminateGuard(Instruction *GuardInst, MemorySSAUpdater *MSSAU) {
123
124
// / condition should stay invariant. Otherwise there can be a miscompile, like
124
125
// / the one described at https://github.com/llvm/llvm-project/issues/60234. The
125
126
// / safest way to do it is to expand the new condition at WC's block.
126
- static Instruction *findInsertionPointForWideCondition (Instruction *Guard) {
127
- if (auto WC = extractWidenableCondition (Guard))
127
+ static Instruction *findInsertionPointForWideCondition (Instruction *WCOrGuard) {
128
+ if (isGuard (WCOrGuard))
129
+ return WCOrGuard;
130
+ if (auto WC = extractWidenableCondition (WCOrGuard))
128
131
return cast<Instruction>(WC);
129
- return Guard ;
132
+ return nullptr ;
130
133
}
131
134
132
135
class GuardWideningImpl {
@@ -179,9 +182,11 @@ class GuardWideningImpl {
179
182
static StringRef scoreTypeToString (WideningScore WS);
180
183
181
184
// / Compute the score for widening the condition in \p DominatedInstr
182
- // / into \p DominatingGuard .
185
+ // / into \p WideningPoint .
183
186
WideningScore computeWideningScore (Instruction *DominatedInstr,
184
- Instruction *DominatingGuard);
187
+ Instruction *WideningPoint,
188
+ SmallVectorImpl<Value *> &ChecksToHoist,
189
+ SmallVectorImpl<Value *> &ChecksToWiden);
185
190
186
191
// / Helper to check if \p V can be hoisted to \p InsertPos.
187
192
bool canBeHoistedTo (const Value *V, const Instruction *InsertPos) const {
@@ -192,22 +197,35 @@ class GuardWideningImpl {
192
197
bool canBeHoistedTo (const Value *V, const Instruction *InsertPos,
193
198
SmallPtrSetImpl<const Instruction *> &Visited) const ;
194
199
200
+ bool canBeHoistedTo (const SmallVectorImpl<Value *> &Checks,
201
+ const Instruction *InsertPos) const {
202
+ return all_of (Checks,
203
+ [&](const Value *V) { return canBeHoistedTo (V, InsertPos); });
204
+ }
195
205
// / Helper to hoist \p V to \p InsertPos. Guaranteed to succeed if \c
196
206
// / canBeHoistedTo returned true.
197
207
void makeAvailableAt (Value *V, Instruction *InsertPos) const ;
198
208
209
+ void makeAvailableAt (const SmallVectorImpl<Value *> &Checks,
210
+ Instruction *InsertPos) const {
211
+ for_each (Checks, [&](Value *V) { makeAvailableAt (V, InsertPos); });
212
+ }
213
+
199
214
// / Common helper used by \c widenGuard and \c isWideningCondProfitable. Try
200
- // / to generate an expression computing the logical AND of \p Cond0 and Cond1.
201
- // / Return true if the expression computing the AND is only as
202
- // / expensive as computing one of the two. If \p InsertPt is true then
203
- // / actually generate the resulting expression, make it available at \p
204
- // / InsertPt and return it in \p Result (else no change to the IR is made).
205
- std::optional<Value *> mergeChecks (Value *Cond0, Value *Cond1,
215
+ // / to generate an expression computing the logical AND of \p ChecksToHoist
216
+ // / and \p ChecksToWiden. Return true if the expression computing the AND is
217
+ // / only as expensive as computing one of the set of expressions. If \p
218
+ // / InsertPt is true then actually generate the resulting expression, make it
219
+ // / available at \p InsertPt and return it in \p Result (else no change to the
220
+ // / IR is made).
221
+ std::optional<Value *> mergeChecks (SmallVectorImpl<Value *> &ChecksToHoist,
222
+ SmallVectorImpl<Value *> &ChecksToWiden,
206
223
Instruction *InsertPt);
207
224
208
- // / Generate the logical AND of \p Cond0 and \p Cond1 and make it available at
209
- // / \p InsertPt
210
- Value *hoistChecks (Value *Cond0, Value *Cond1, Instruction *InsertPt);
225
+ // / Generate the logical AND of \p ChecksToHoist and \p OldCondition and make
226
+ // / it available at InsertPt
227
+ Value *hoistChecks (SmallVectorImpl<Value *> &ChecksToHoist,
228
+ Value *OldCondition, Instruction *InsertPt);
211
229
212
230
// / Adds freeze to Orig and push it as far as possible very aggressively.
213
231
// / Also replaces all uses of frozen instruction with frozen version.
@@ -252,16 +270,19 @@ class GuardWideningImpl {
252
270
}
253
271
};
254
272
255
- // / Parse \p CheckCond into a conjunction (logical-and) of range checks; and
273
+ // / Parse \p ToParse into a conjunction (logical-and) of range checks; and
256
274
// / append them to \p Checks. Returns true on success, may clobber \c Checks
257
275
// / on failure.
258
- bool parseRangeChecks (Value *CheckCond, SmallVectorImpl<RangeCheck> &Checks) {
259
- SmallPtrSet<const Value *, 8 > Visited;
260
- return parseRangeChecks (CheckCond, Checks, Visited);
276
+ bool parseRangeChecks (SmallVectorImpl<Value *> &ToParse,
277
+ SmallVectorImpl<RangeCheck> &Checks) {
278
+ for (auto CheckCond : ToParse) {
279
+ if (!parseRangeChecks (CheckCond, Checks))
280
+ return false ;
281
+ }
282
+ return true ;
261
283
}
262
284
263
- bool parseRangeChecks (Value *CheckCond, SmallVectorImpl<RangeCheck> &Checks,
264
- SmallPtrSetImpl<const Value *> &Visited);
285
+ bool parseRangeChecks (Value *CheckCond, SmallVectorImpl<RangeCheck> &Checks);
265
286
266
287
// / Combine the checks in \p Checks into a smaller set of checks and append
267
288
// / them into \p CombinedChecks. Return true on success (i.e. all of checks
@@ -270,20 +291,23 @@ class GuardWideningImpl {
270
291
bool combineRangeChecks (SmallVectorImpl<RangeCheck> &Checks,
271
292
SmallVectorImpl<RangeCheck> &CombinedChecks) const ;
272
293
273
- // / Can we compute the logical AND of \p Cond0 and \p Cond1 for the price of
274
- // / computing only one of the two expressions?
275
- bool isWideningCondProfitable (Value *Cond0, Value *Cond1) {
276
- return mergeChecks (Cond0, Cond1, /* InsertPt=*/ nullptr ).has_value ();
294
+ // / Can we compute the logical AND of \p ChecksToHoist and \p ChecksToWiden
295
+ // / for the price of computing only one of the set of expressions?
296
+ bool isWideningCondProfitable (SmallVectorImpl<Value *> &ChecksToHoist,
297
+ SmallVectorImpl<Value *> &ChecksToWiden) {
298
+ return mergeChecks (ChecksToHoist, ChecksToWiden, /* InsertPt=*/ nullptr )
299
+ .has_value ();
277
300
}
278
301
279
- // / Widen \p ToWiden to fail if \p NewCondition is false
280
- void widenGuard (Instruction *ToWiden, Value *NewCondition) {
302
+ // / Widen \p ChecksToWiden to fail if any of \p ChecksToHoist is false
303
+ void widenGuard (SmallVectorImpl<Value *> &ChecksToHoist,
304
+ SmallVectorImpl<Value *> &ChecksToWiden,
305
+ Instruction *ToWiden) {
281
306
Instruction *InsertPt = findInsertionPointForWideCondition (ToWiden);
282
- auto MergedCheck =
283
- mergeChecks (getCondition (ToWiden), NewCondition, InsertPt);
307
+ auto MergedCheck = mergeChecks (ChecksToHoist, ChecksToWiden, InsertPt);
284
308
Value *Result = MergedCheck ? *MergedCheck
285
- : hoistChecks (getCondition (ToWiden) ,
286
- NewCondition , InsertPt);
309
+ : hoistChecks (ChecksToHoist ,
310
+ getCondition (ToWiden) , InsertPt);
287
311
288
312
if (isGuardAsWidenableBranch (ToWiden)) {
289
313
setWidenableBranchCond (cast<BranchInst>(ToWiden), Result);
@@ -352,10 +376,13 @@ bool GuardWideningImpl::eliminateInstrViaWidening(
352
376
Instruction *Instr, const df_iterator<DomTreeNode *> &DFSI,
353
377
const DenseMap<BasicBlock *, SmallVector<Instruction *, 8 >>
354
378
&GuardsInBlock) {
379
+ SmallVector<Value *> ChecksToHoist;
380
+ parseWidenableGuard (Instr, ChecksToHoist);
355
381
// Ignore trivial true or false conditions. These instructions will be
356
382
// trivially eliminated by any cleanup pass. Do not erase them because other
357
383
// guards can possibly be widened into them.
358
- if (isa<ConstantInt>(getCondition (Instr)))
384
+ if (ChecksToHoist.empty () ||
385
+ (ChecksToHoist.size () == 1 && isa<ConstantInt>(ChecksToHoist.front ())))
359
386
return false ;
360
387
361
388
Instruction *BestSoFar = nullptr ;
@@ -391,10 +418,15 @@ bool GuardWideningImpl::eliminateInstrViaWidening(
391
418
assert ((i == (e - 1 )) == (Instr->getParent () == CurBB) && " Bad DFS?" );
392
419
393
420
for (auto *Candidate : make_range (I, E)) {
394
- auto Score = computeWideningScore (Instr, Candidate);
395
- LLVM_DEBUG (dbgs () << " Score between " << *getCondition (Instr)
396
- << " and " << *getCondition (Candidate) << " is "
397
- << scoreTypeToString (Score) << " \n " );
421
+ auto *WideningPoint = findInsertionPointForWideCondition (Candidate);
422
+ if (!WideningPoint)
423
+ continue ;
424
+ SmallVector<Value *> CandidateChecks;
425
+ parseWidenableGuard (Candidate, CandidateChecks);
426
+ auto Score = computeWideningScore (Instr, WideningPoint, ChecksToHoist,
427
+ CandidateChecks);
428
+ LLVM_DEBUG (dbgs () << " Score between " << *Instr << " and " << *Candidate
429
+ << " is " << scoreTypeToString (Score) << " \n " );
398
430
if (Score > BestScoreSoFar) {
399
431
BestScoreSoFar = Score;
400
432
BestSoFar = Candidate;
@@ -413,19 +445,22 @@ bool GuardWideningImpl::eliminateInstrViaWidening(
413
445
LLVM_DEBUG (dbgs () << " Widening " << *Instr << " into " << *BestSoFar
414
446
<< " with score " << scoreTypeToString (BestScoreSoFar)
415
447
<< " \n " );
416
- widenGuard (BestSoFar, getCondition (Instr));
448
+ SmallVector<Value *> ChecksToWiden;
449
+ parseWidenableGuard (BestSoFar, ChecksToWiden);
450
+ widenGuard (ChecksToHoist, ChecksToWiden, BestSoFar);
417
451
auto NewGuardCondition = ConstantInt::getTrue (Instr->getContext ());
418
452
setCondition (Instr, NewGuardCondition);
419
453
EliminatedGuardsAndBranches.push_back (Instr);
420
454
WidenedGuards.insert (BestSoFar);
421
455
return true ;
422
456
}
423
457
424
- GuardWideningImpl::WideningScore
425
- GuardWideningImpl::computeWideningScore (Instruction *DominatedInstr,
426
- Instruction *DominatingGuard) {
458
+ GuardWideningImpl::WideningScore GuardWideningImpl::computeWideningScore (
459
+ Instruction *DominatedInstr, Instruction *WideningPoint,
460
+ SmallVectorImpl<Value *> &ChecksToHoist,
461
+ SmallVectorImpl<Value *> &ChecksToWiden) {
427
462
Loop *DominatedInstrLoop = LI.getLoopFor (DominatedInstr->getParent ());
428
- Loop *DominatingGuardLoop = LI.getLoopFor (DominatingGuard ->getParent ());
463
+ Loop *DominatingGuardLoop = LI.getLoopFor (WideningPoint ->getParent ());
429
464
bool HoistingOutOfLoop = false ;
430
465
431
466
if (DominatingGuardLoop != DominatedInstrLoop) {
@@ -438,10 +473,9 @@ GuardWideningImpl::computeWideningScore(Instruction *DominatedInstr,
438
473
HoistingOutOfLoop = true ;
439
474
}
440
475
441
- auto *WideningPoint = findInsertionPointForWideCondition (DominatingGuard);
442
- if (!canBeHoistedTo (getCondition (DominatedInstr), WideningPoint))
476
+ if (!canBeHoistedTo (ChecksToHoist, WideningPoint))
443
477
return WS_IllegalOrNegative;
444
- if (!canBeHoistedTo (getCondition (DominatingGuard) , WideningPoint))
478
+ if (!canBeHoistedTo (ChecksToWiden , WideningPoint))
445
479
return WS_IllegalOrNegative;
446
480
447
481
// If the guard was conditional executed, it may never be reached
@@ -452,8 +486,7 @@ GuardWideningImpl::computeWideningScore(Instruction *DominatedInstr,
452
486
// here. TODO: evaluate cost model for spurious deopt
453
487
// NOTE: As written, this also lets us hoist right over another guard which
454
488
// is essentially just another spelling for control flow.
455
- if (isWideningCondProfitable (getCondition (DominatedInstr),
456
- getCondition (DominatingGuard)))
489
+ if (isWideningCondProfitable (ChecksToHoist, ChecksToWiden))
457
490
return HoistingOutOfLoop ? WS_VeryPositive : WS_Positive;
458
491
459
492
if (HoistingOutOfLoop)
@@ -489,7 +522,7 @@ GuardWideningImpl::computeWideningScore(Instruction *DominatedInstr,
489
522
// control flow (guards, calls which throw, etc...). That choice appears
490
523
// arbitrary (we assume that implicit control flow exits are all rare).
491
524
auto MaybeHoistingToHotterBlock = [&]() {
492
- const auto *DominatingBlock = DominatingGuard ->getParent ();
525
+ const auto *DominatingBlock = WideningPoint ->getParent ();
493
526
const auto *DominatedBlock = DominatedInstr->getParent ();
494
527
495
528
// Descend as low as we can, always taking the likely successor.
@@ -515,7 +548,8 @@ GuardWideningImpl::computeWideningScore(Instruction *DominatedInstr,
515
548
if (!DT.dominates (DominatingBlock, DominatedBlock))
516
549
return true ;
517
550
// TODO: diamond, triangle cases
518
- if (!PDT) return true ;
551
+ if (!PDT)
552
+ return true ;
519
553
return !PDT->dominates (DominatedBlock, DominatingBlock);
520
554
};
521
555
@@ -661,9 +695,10 @@ Value *GuardWideningImpl::freezeAndPush(Value *Orig, Instruction *InsertPt) {
661
695
return Result;
662
696
}
663
697
664
- std::optional<Value *> GuardWideningImpl::mergeChecks (Value *Cond0,
665
- Value *Cond1,
666
- Instruction *InsertPt) {
698
+ std::optional<Value *>
699
+ GuardWideningImpl::mergeChecks (SmallVectorImpl<Value *> &ChecksToHoist,
700
+ SmallVectorImpl<Value *> &ChecksToWiden,
701
+ Instruction *InsertPt) {
667
702
using namespace llvm ::PatternMatch;
668
703
669
704
Value *Result = nullptr ;
@@ -672,8 +707,13 @@ std::optional<Value *> GuardWideningImpl::mergeChecks(Value *Cond0,
672
707
ConstantInt *RHS0, *RHS1;
673
708
Value *LHS;
674
709
ICmpInst::Predicate Pred0, Pred1;
675
- if (match (Cond0, m_ICmp (Pred0, m_Value (LHS), m_ConstantInt (RHS0))) &&
676
- match (Cond1, m_ICmp (Pred1, m_Specific (LHS), m_ConstantInt (RHS1)))) {
710
+ // TODO: Support searching for pairs to merge from both whole lists of
711
+ // ChecksToHoist and ChecksToWiden.
712
+ if (ChecksToWiden.size () == 1 && ChecksToHoist.size () == 1 &&
713
+ match (ChecksToWiden.front (),
714
+ m_ICmp (Pred0, m_Value (LHS), m_ConstantInt (RHS0))) &&
715
+ match (ChecksToHoist.front (),
716
+ m_ICmp (Pred1, m_Specific (LHS), m_ConstantInt (RHS1)))) {
677
717
678
718
ConstantRange CR0 =
679
719
ConstantRange::makeExactICmpRegion (Pred0, RHS0->getValue ());
@@ -690,7 +730,7 @@ std::optional<Value *> GuardWideningImpl::mergeChecks(Value *Cond0,
690
730
if (Intersect->getEquivalentICmp (Pred, NewRHSAP)) {
691
731
if (InsertPt) {
692
732
ConstantInt *NewRHS =
693
- ConstantInt::get (Cond0 ->getContext (), NewRHSAP);
733
+ ConstantInt::get (InsertPt ->getContext (), NewRHSAP);
694
734
assert (canBeHoistedTo (LHS, InsertPt) && " must be" );
695
735
makeAvailableAt (LHS, InsertPt);
696
736
Result = new ICmpInst (InsertPt, Pred, LHS, NewRHS, " wide.chk" );
@@ -703,7 +743,8 @@ std::optional<Value *> GuardWideningImpl::mergeChecks(Value *Cond0,
703
743
704
744
{
705
745
SmallVector<GuardWideningImpl::RangeCheck, 4 > Checks, CombinedChecks;
706
- if (parseRangeChecks (Cond0, Checks) && parseRangeChecks (Cond1, Checks) &&
746
+ if (parseRangeChecks (ChecksToWiden, Checks) &&
747
+ parseRangeChecks (ChecksToHoist, Checks) &&
707
748
combineRangeChecks (Checks, CombinedChecks)) {
708
749
if (InsertPt) {
709
750
for (auto &RC : CombinedChecks) {
@@ -721,33 +762,29 @@ std::optional<Value *> GuardWideningImpl::mergeChecks(Value *Cond0,
721
762
return Result;
722
763
}
723
764
}
724
- // We were not able to compute Cond0 AND Cond1 for the price of one.
765
+ // We were not able to compute ChecksToHoist AND ChecksToWiden for the price
766
+ // of one.
725
767
return std::nullopt;
726
768
}
727
769
728
- Value *GuardWideningImpl::hoistChecks (Value *Cond0, Value *Cond1,
770
+ Value *GuardWideningImpl::hoistChecks (SmallVectorImpl<Value *> &ChecksToHoist,
771
+ Value *OldCondition,
729
772
Instruction *InsertPt) {
730
- makeAvailableAt (Cond0, InsertPt);
731
- makeAvailableAt (Cond1, InsertPt);
732
- Cond1 = freezeAndPush (Cond1, InsertPt);
733
- return BinaryOperator::CreateAnd (Cond0, Cond1, " wide.chk" , InsertPt);
773
+ assert (!ChecksToHoist.empty ());
774
+ IRBuilder<> Builder (InsertPt);
775
+ makeAvailableAt (ChecksToHoist, InsertPt);
776
+ makeAvailableAt (OldCondition, InsertPt);
777
+ Value *Result = Builder.CreateAnd (ChecksToHoist);
778
+ Result = freezeAndPush (Result, InsertPt);
779
+ Result = Builder.CreateAnd (OldCondition, Result);
780
+ Result->setName (" wide.chk" );
781
+ return Result;
734
782
}
735
783
736
784
bool GuardWideningImpl::parseRangeChecks (
737
- Value *CheckCond, SmallVectorImpl<GuardWideningImpl::RangeCheck> &Checks,
738
- SmallPtrSetImpl<const Value *> &Visited) {
739
- if (!Visited.insert (CheckCond).second )
740
- return true ;
741
-
785
+ Value *CheckCond, SmallVectorImpl<GuardWideningImpl::RangeCheck> &Checks) {
742
786
using namespace llvm ::PatternMatch;
743
787
744
- {
745
- Value *AndLHS, *AndRHS;
746
- if (match (CheckCond, m_And (m_Value (AndLHS), m_Value (AndRHS))))
747
- return parseRangeChecks (AndLHS, Checks) &&
748
- parseRangeChecks (AndRHS, Checks);
749
- }
750
-
751
788
auto *IC = dyn_cast<ICmpInst>(CheckCond);
752
789
if (!IC || !IC->getOperand (0 )->getType ()->isIntegerTy () ||
753
790
(IC->getPredicate () != ICmpInst::ICMP_ULT &&
0 commit comments