[llvm] ef22d50 - [NFCI][SCEV] getPtrToIntExpr(): use SCEVRewriteVisitor<> for ptrtoint cast sinking
Roman Lebedev via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 30 07:05:39 PDT 2020
Author: Roman Lebedev
Date: 2020-10-30T17:05:14+03:00
New Revision: ef22d500f7505d02a3861a9acf7eaacb375c7652
URL: https://github.com/llvm/llvm-project/commit/ef22d500f7505d02a3861a9acf7eaacb375c7652
DIFF: https://github.com/llvm/llvm-project/commit/ef22d500f7505d02a3861a9acf7eaacb375c7652.diff
LOG: [NFCI][SCEV] getPtrToIntExpr(): use SCEVRewriteVisitor<> for ptrtoint cast sinking
This is functionally-identical to the previous implementation,
just using a generic interface to do that instead of hand-rolled one,
with caching as a bonus. Thought the sinking is still recursive..
Note that SCEVRewriteVisitor<>'s default implementations
don't preserve NoWrap flags on Add/Mul (but does on AddRec!),
but here we know we can preserve them,
so `visitAddExpr()`/`visitMulExpr()` are specialized.
Added:
Modified:
llvm/lib/Analysis/ScalarEvolution.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 91f3b947fc50..d214fcef09de 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -1036,81 +1036,110 @@ const SCEV *SCEVAddRecExpr::evaluateAtIteration(const SCEV *It,
const SCEV *ScalarEvolution::getPtrToIntExpr(const SCEV *Op, Type *Ty,
unsigned Depth) {
assert(Ty->isIntegerTy() && "Target type must be an integer type!");
+ assert(Depth <= 1 && "getPtrToIntExpr() should self-recurse at most once.");
// We could be called with an integer-typed operands during SCEV rewrites.
// Since the operand is an integer already, just perform zext/trunc/self cast.
if (!Op->getType()->isPointerTy())
return getTruncateOrZeroExtend(Op, Ty);
+ // What would be an ID for such a SCEV cast expression?
FoldingSetNodeID ID;
ID.AddInteger(scPtrToInt);
ID.AddPointer(Op);
+
void *IP = nullptr;
+
+ // Is there already an expression for such a cast?
if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP))
- return getTruncateOrZeroExtend(S, Ty, Depth);
-
- assert((isa<SCEVNAryExpr>(Op) || isa<SCEVUnknown>(Op)) &&
- "We can only gen an nary expression, or an unknown here.");
-
- Type *IntPtrTy = getDataLayout().getIntPtrType(Op->getType());
-
- // If the input operand is not an unknown (and thus is an nary expression),
- // sink the cast to operands, so that the operation is performed on integers,
- // and we eventually end up with just an ptrtoint(unknown).
- if (const SCEVNAryExpr *NaryExpr = dyn_cast<SCEVNAryExpr>(Op)) {
- SmallVector<const SCEV *, 2> NewOps;
- NewOps.reserve(NaryExpr->getNumOperands());
- for (const SCEV *Op : NaryExpr->operands())
- NewOps.push_back(Op->getType()->isPointerTy()
- ? getPtrToIntExpr(Op, IntPtrTy, Depth + 1)
- : Op);
- const SCEV *NewNaryExpr = nullptr;
- switch (SCEVTypes SCEVType = NaryExpr->getSCEVType()) {
- case scAddExpr:
- NewNaryExpr = getAddExpr(NewOps, NaryExpr->getNoWrapFlags(), Depth + 1);
- break;
- case scAddRecExpr:
- NewNaryExpr =
- getAddRecExpr(NewOps, cast<SCEVAddRecExpr>(NaryExpr)->getLoop(),
- NaryExpr->getNoWrapFlags());
- break;
- case scUMaxExpr:
- case scSMaxExpr:
- case scUMinExpr:
- case scSMinExpr:
- NewNaryExpr = getMinMaxExpr(SCEVType, NewOps);
- break;
+ return getTruncateOrZeroExtend(S, Ty);
+
+ // If not, is this expression something we can't reduce any further?
+ if (isa<SCEVUnknown>(Op)) {
+ // Create an explicit cast node.
+ // We can reuse the existing insert position since if we get here,
+ // we won't have made any changes which would invalidate it.
+ Type *IntPtrTy = getDataLayout().getIntPtrType(Op->getType());
+ assert(getDataLayout().getTypeSizeInBits(getEffectiveSCEVType(
+ Op->getType())) == getDataLayout().getTypeSizeInBits(IntPtrTy) &&
+ "We can only model ptrtoint if SCEV's effective (integer) type is "
+ "sufficiently wide to represent all possible pointer values.");
+ SCEV *S = new (SCEVAllocator)
+ SCEVPtrToIntExpr(ID.Intern(SCEVAllocator), Op, IntPtrTy);
+ UniqueSCEVs.InsertNode(S, IP);
+ addToLoopUseLists(S);
+ return getTruncateOrZeroExtend(S, Ty);
+ }
- case scMulExpr:
- NewNaryExpr = getMulExpr(NewOps, NaryExpr->getNoWrapFlags(), Depth + 1);
- break;
- case scUDivExpr:
- NewNaryExpr = getUDivExpr(NewOps[0], NewOps[1]);
- break;
- case scConstant:
- case scTruncate:
- case scZeroExtend:
- case scSignExtend:
- case scPtrToInt:
- case scUnknown:
- case scCouldNotCompute:
- llvm_unreachable("We can't get these types here.");
+ assert(Depth == 0 &&
+ "getPtrToIntExpr() should not self-recurse for non-SCEVUnknown's.");
+
+ // Otherwise, we've got some expression that is more complex than just a
+ // single SCEVUnknown. But we don't want to have a SCEVPtrToIntExpr of an
+ // arbitrary expression, we want to have SCEVPtrToIntExpr of an SCEVUnknown
+ // only, and the expressions must otherwise be integer-typed.
+ // So sink the cast down to the SCEVUnknown's.
+
+ /// The SCEVPtrToIntSinkingRewriter takes a scalar evolution expression,
+ /// which computes a pointer-typed value, and rewrites the whole expression
+ /// tree so that *all* the computations are done on integers, and the only
+ /// pointer-typed operands in the expression are SCEVUnknown.
+ class SCEVPtrToIntSinkingRewriter
+ : public SCEVRewriteVisitor<SCEVPtrToIntSinkingRewriter> {
+ using Base = SCEVRewriteVisitor<SCEVPtrToIntSinkingRewriter>;
+
+ public:
+ SCEVPtrToIntSinkingRewriter(ScalarEvolution &SE) : SCEVRewriteVisitor(SE) {}
+
+ static const SCEV *rewrite(const SCEV *Scev, ScalarEvolution &SE) {
+ SCEVPtrToIntSinkingRewriter Rewriter(SE);
+ return Rewriter.visit(Scev);
}
- return getTruncateOrZeroExtend(NewNaryExpr, Ty, Depth);
- }
- // The cast wasn't folded; create an explicit cast node. We can reuse
- // the existing insert position since if we get here, we won't have
- // made any changes which would invalidate it.
- assert(getDataLayout().getTypeSizeInBits(getEffectiveSCEVType(
- Op->getType())) == getDataLayout().getTypeSizeInBits(IntPtrTy) &&
- "We can only model ptrtoint if SCEV's effective (integer) type is "
- "sufficiently wide to represent all possible pointer values.");
- SCEV *S = new (SCEVAllocator)
- SCEVPtrToIntExpr(ID.Intern(SCEVAllocator), Op, IntPtrTy);
- UniqueSCEVs.InsertNode(S, IP);
- addToLoopUseLists(S);
- return getTruncateOrZeroExtend(S, Ty, Depth);
+ const SCEV *visit(const SCEV *S) {
+ Type *STy = S->getType();
+ // If the expression is not pointer-typed, just keep it as-is.
+ if (!STy->isPointerTy())
+ return S;
+ // Else, recursively sink the cast down into it.
+ return Base::visit(S);
+ }
+
+ const SCEV *visitAddExpr(const SCEVAddExpr *Expr) {
+ SmallVector<const SCEV *, 2> Operands;
+ bool Changed = false;
+ for (auto *Op : Expr->operands()) {
+ Operands.push_back(visit(Op));
+ Changed |= Op != Operands.back();
+ }
+ return !Changed ? Expr : SE.getAddExpr(Operands, Expr->getNoWrapFlags());
+ }
+
+ const SCEV *visitMulExpr(const SCEVMulExpr *Expr) {
+ SmallVector<const SCEV *, 2> Operands;
+ bool Changed = false;
+ for (auto *Op : Expr->operands()) {
+ Operands.push_back(visit(Op));
+ Changed |= Op != Operands.back();
+ }
+ return !Changed ? Expr : SE.getMulExpr(Operands, Expr->getNoWrapFlags());
+ }
+
+ const SCEV *visitUnknown(const SCEVUnknown *Expr) {
+ Type *ExprPtrTy = Expr->getType();
+ assert(ExprPtrTy->isPointerTy() &&
+ "Should only reach pointer-typed SCEVUnknown's.");
+ Type *ExprIntPtrTy = SE.getDataLayout().getIntPtrType(ExprPtrTy);
+ return SE.getPtrToIntExpr(Expr, ExprIntPtrTy, /*Depth=*/1);
+ }
+ };
+
+ // And actually perform the cast sinking.
+ const SCEV *IntOp = SCEVPtrToIntSinkingRewriter::rewrite(Op, *this);
+ assert(IntOp->getType()->isIntegerTy() &&
+ "We must have succeeded in sinking the cast, "
+ "and ending up with an integer-typed expression!");
+ return getTruncateOrZeroExtend(IntOp, Ty);
}
const SCEV *ScalarEvolution::getTruncateExpr(const SCEV *Op, Type *Ty,
More information about the llvm-commits
mailing list