-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[SCEVExpander] Expand UDiv avoiding UB when in seq_min/max. #92177
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
Changes from 4 commits
bff4e5a
16a4b00
32833a7
b0d098c
d6d8655
4ace524
70f2ef7
fa12ea4
5b1a789
c2dc23d
1468d8b
c12b25c
5f31e85
9c4b76d
b699ddd
5469289
d5c8931
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -124,6 +124,11 @@ class SCEVExpander : public SCEVVisitor<SCEVExpander, Value *> { | |
| /// "expanded" form. | ||
| bool LSRMode; | ||
|
|
||
| /// When true, rewrite any divisors of UDiv expressions that may be 0 to | ||
| /// umax(Divisor, 1) to avoid introducing UB. If the divisor may be poison, | ||
| /// freeze it first. | ||
| bool SafeUDivMode = false; | ||
|
|
||
| typedef IRBuilder<InstSimplifyFolder, IRBuilderCallbackInserter> BuilderType; | ||
| BuilderType Builder; | ||
|
|
||
|
|
@@ -300,6 +305,9 @@ class SCEVExpander : public SCEVVisitor<SCEVExpander, Value *> { | |
| /// location and their operands are defined at this location. | ||
| bool isSafeToExpandAt(const SCEV *S, const Instruction *InsertionPoint) const; | ||
|
|
||
| static bool isSafeToExpand(const SCEV *S, bool CanonicalMode, | ||
| ScalarEvolution &SE); | ||
|
|
||
| /// Insert code to directly compute the specified SCEV expression into the | ||
| /// program. The code is inserted into the specified block. | ||
| Value *expandCodeFor(const SCEV *SH, Type *Ty, BasicBlock::iterator I); | ||
|
|
@@ -418,6 +426,11 @@ class SCEVExpander : public SCEVVisitor<SCEVExpander, Value *> { | |
| BasicBlock::iterator findInsertPointAfter(Instruction *I, | ||
| Instruction *MustDominate) const; | ||
|
|
||
| static const SCEV *rewriteExpressionToRemoveUB(const SCEV *BTC, Loop *L, | ||
| ScalarEvolution &SE); | ||
|
||
|
|
||
| void setSafeUDivMode() { SafeUDivMode = true; } | ||
|
|
||
| private: | ||
| LLVMContext &getContext() const { return SE.getContext(); } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4304,12 +4304,22 @@ ScalarEvolution::getSequentialMinMaxExpr(SCEVTypes Kind, | |
| } | ||
|
|
||
| for (unsigned i = 1, e = Ops.size(); i != e; ++i) { | ||
| bool MayBeUB = SCEVExprContains(Ops[i], [this](const SCEV *S) { | ||
| auto *UDiv = dyn_cast<SCEVUDivExpr>(S); | ||
| // The UDiv may be UB if the divisor is poison or zero. Unless the divisor | ||
| // is a non-zero constant, we have to assume the UDiv may be UB. | ||
| return UDiv && (!isa<SCEVConstant>(UDiv->getOperand(1)) || | ||
| !isKnownNonZero(UDiv->getOperand(1))); | ||
| }); | ||
|
|
||
| if (MayBeUB) | ||
| continue; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should also change the doc comment on SCEVSequentialMinMaxExpr for the new semantics introduced here.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added thanks! |
||
| // We can replace %x umin_seq %y with %x umin %y if either: | ||
| // * %y being poison implies %x is also poison. | ||
| // * %x cannot be the saturating value (e.g. zero for umin). | ||
| if (::impliesPoison(Ops[i], Ops[i - 1]) || | ||
| isKnownViaNonRecursiveReasoning(ICmpInst::ICMP_NE, Ops[i - 1], | ||
| SaturationPoint)) { | ||
| (isKnownViaNonRecursiveReasoning(ICmpInst::ICMP_NE, Ops[i - 1], | ||
| SaturationPoint))) { | ||
|
||
| SmallVector<const SCEV *> SeqOps = {Ops[i - 1], Ops[i]}; | ||
| Ops[i - 1] = getMinMaxExpr( | ||
| SCEVSequentialMinMaxExpr::getEquivalentNonSequentialSCEVType(Kind), | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -665,6 +665,12 @@ Value *SCEVExpander::visitUDivExpr(const SCEVUDivExpr *S) { | |
| } | ||
|
|
||
| Value *RHS = expand(S->getRHS()); | ||
| if (SafeUDivMode && !SE.isKnownNonZero(S->getRHS())) { | ||
|
||
| if (!isa<SCEVConstant>(S->getRHS())) | ||
|
||
| RHS = Builder.CreateFreeze(RHS); | ||
| RHS = Builder.CreateIntrinsic(RHS->getType(), Intrinsic::umax, | ||
| {RHS, ConstantInt::get(RHS->getType(), 1)}); | ||
| } | ||
| return InsertBinop(Instruction::UDiv, LHS, RHS, SCEV::FlagAnyWrap, | ||
| /*IsSafeToHoist*/ SE.isKnownNonZero(S->getRHS())); | ||
| } | ||
|
|
@@ -1358,11 +1364,14 @@ Value *SCEVExpander::visitSignExtendExpr(const SCEVSignExtendExpr *S) { | |
| Value *SCEVExpander::expandMinMaxExpr(const SCEVNAryExpr *S, | ||
| Intrinsic::ID IntrinID, Twine Name, | ||
| bool IsSequential) { | ||
| bool PrevSafeMode = SafeUDivMode; | ||
| SafeUDivMode |= IsSequential; | ||
| Value *LHS = expand(S->getOperand(S->getNumOperands() - 1)); | ||
| Type *Ty = LHS->getType(); | ||
| if (IsSequential) | ||
| LHS = Builder.CreateFreeze(LHS); | ||
| for (int i = S->getNumOperands() - 2; i >= 0; --i) { | ||
| SafeUDivMode = (IsSequential && i != 0) || PrevSafeMode; | ||
| Value *RHS = expand(S->getOperand(i)); | ||
| if (IsSequential && i != 0) | ||
| RHS = Builder.CreateFreeze(RHS); | ||
|
|
@@ -1377,6 +1386,7 @@ Value *SCEVExpander::expandMinMaxExpr(const SCEVNAryExpr *S, | |
| } | ||
| LHS = Sel; | ||
| } | ||
| SafeUDivMode = PrevSafeMode; | ||
| return LHS; | ||
| } | ||
|
|
||
|
|
@@ -2315,12 +2325,17 @@ struct SCEVFindUnsafe { | |
| }; | ||
| } // namespace | ||
|
|
||
| bool SCEVExpander::isSafeToExpand(const SCEV *S) const { | ||
| bool SCEVExpander::isSafeToExpand(const SCEV *S, bool CanonicalMode, | ||
| ScalarEvolution &SE) { | ||
| SCEVFindUnsafe Search(SE, CanonicalMode); | ||
| visitAll(S, Search); | ||
| return !Search.IsUnsafe; | ||
| } | ||
|
|
||
| bool SCEVExpander::isSafeToExpand(const SCEV *S) const { | ||
| return isSafeToExpand(S, CanonicalMode, SE); | ||
| } | ||
|
|
||
| bool SCEVExpander::isSafeToExpandAt(const SCEV *S, | ||
|
||
| const Instruction *InsertionPoint) const { | ||
| if (!isSafeToExpand(S)) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see where this new method is used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left over from earlier versions, removed, thanks