aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Analysis/Loads.cpp
diff options
context:
space:
mode:
authorNikita Popov <npopov@redhat.com>2025-09-09 16:50:45 +0200
committerGitHub <noreply@github.com>2025-09-09 16:50:45 +0200
commit1cbb35e044e2902b049499116c93f98f9a30955e (patch)
treec1ccdffef6e7542521b6550f2e95e9225041c426 /llvm/lib/Analysis/Loads.cpp
parent6ef4a7bf16d2e1f960237a635ef114dd6fc07b16 (diff)
downloadllvm-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.cpp64
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;
+}