diff options
author | Nikita Popov <npopov@redhat.com> | 2025-09-09 16:50:45 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-09-09 16:50:45 +0200 |
commit | 1cbb35e044e2902b049499116c93f98f9a30955e (patch) | |
tree | c1ccdffef6e7542521b6550f2e95e9225041c426 /llvm/lib/Analysis/Loads.cpp | |
parent | 6ef4a7bf16d2e1f960237a635ef114dd6fc07b16 (diff) | |
download | llvm-1cbb35e044e2902b049499116c93f98f9a30955e.zip llvm-1cbb35e044e2902b049499116c93f98f9a30955e.tar.gz llvm-1cbb35e044e2902b049499116c93f98f9a30955e.tar.bz2 |
[InstCombine] Support GEP chains in foldCmpLoadFromIndexedGlobal() (#157447)
Currently this fold only supports a single GEP. However, in ptradd
representation, it may be split across multiple GEPs. In particular, PR
#151333 will split off constant offset GEPs.
To support this, add a new helper decomposeLinearExpression(), which
decomposes a pointer into a linear expression of the form BasePtr +
Index * Scale + Offset.
I plan to also extend this helper to look through mul/shl on the index
and use it in more places that currently use collectOffset() to extract
a single index * scale. This will make sure such optimizations are not
affected by the ptradd migration.
Diffstat (limited to 'llvm/lib/Analysis/Loads.cpp')
-rw-r--r-- | llvm/lib/Analysis/Loads.cpp | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/llvm/lib/Analysis/Loads.cpp b/llvm/lib/Analysis/Loads.cpp index 47fdb41..0c4e3a2 100644 --- a/llvm/lib/Analysis/Loads.cpp +++ b/llvm/lib/Analysis/Loads.cpp @@ -21,6 +21,7 @@ #include "llvm/Analysis/ScalarEvolutionExpressions.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/GetElementPtrTypeIterator.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Operator.h" @@ -876,3 +877,66 @@ bool llvm::isReadOnlyLoop( } return true; } + +LinearExpression llvm::decomposeLinearExpression(const DataLayout &DL, + Value *Ptr) { + assert(Ptr->getType()->isPointerTy() && "Must be called with pointer arg"); + + unsigned BitWidth = DL.getIndexTypeSizeInBits(Ptr->getType()); + LinearExpression Expr(Ptr, BitWidth); + + while (true) { + auto *GEP = dyn_cast<GEPOperator>(Expr.BasePtr); + if (!GEP || GEP->getSourceElementType()->isScalableTy()) + return Expr; + + Value *VarIndex = nullptr; + for (Value *Index : GEP->indices()) { + if (isa<ConstantInt>(Index)) + continue; + // Only allow a single variable index. We do not bother to handle the + // case of the same variable index appearing multiple times. + if (Expr.Index || VarIndex) + return Expr; + VarIndex = Index; + } + + // Don't return non-canonical indexes. + if (VarIndex && !VarIndex->getType()->isIntegerTy(BitWidth)) + return Expr; + + // We have verified that we can fully handle this GEP, so we can update Expr + // members past this point. + Expr.BasePtr = GEP->getPointerOperand(); + Expr.Flags = Expr.Flags.intersectForOffsetAdd(GEP->getNoWrapFlags()); + for (gep_type_iterator GTI = gep_type_begin(GEP), GTE = gep_type_end(GEP); + GTI != GTE; ++GTI) { + Value *Index = GTI.getOperand(); + if (auto *ConstOffset = dyn_cast<ConstantInt>(Index)) { + if (ConstOffset->isZero()) + continue; + if (StructType *STy = GTI.getStructTypeOrNull()) { + unsigned ElementIdx = ConstOffset->getZExtValue(); + const StructLayout *SL = DL.getStructLayout(STy); + Expr.Offset += SL->getElementOffset(ElementIdx); + continue; + } + // Truncate if type size exceeds index space. + APInt IndexedSize(BitWidth, GTI.getSequentialElementStride(DL), + /*isSigned=*/false, + /*implcitTrunc=*/true); + Expr.Offset += ConstOffset->getValue() * IndexedSize; + continue; + } + + // FIXME: Also look through a mul/shl in the index. + assert(Expr.Index == nullptr && "Shouldn't have index yet"); + Expr.Index = Index; + // Truncate if type size exceeds index space. + Expr.Scale = APInt(BitWidth, GTI.getSequentialElementStride(DL), + /*isSigned=*/false, /*implicitTrunc=*/true); + } + } + + return Expr; +} |