[llvm] [BasicAA] Decompose explicit truncation in GEP indices (PR #228781)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Oct 3 16:07:45 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-analysis
Author: Dávid Bolvanský (davidbolvansky)
<details>
<summary>Changes</summary>
BasicAA stops decomposing GEP indices at explicit `trunc` instructions, losing constant offset correlations. For example, four-byte accesses indexed by `trunc(x)` and `trunc(x + 1)` currently return `MayAlias`.
Track explicit truncation in `CastedValue` and compute the minimum offset distance at the truncated width. This proves `NoAlias` for the example while retaining `MayAlias` when truncation erases the difference. Real-world impact remains under investigation.
This change was developed with assistance from OpenAI Codex.
---
Full diff: https://github.com/llvm/llvm-project/pull/228781.diff
2 Files Affected:
- (modified) llvm/lib/Analysis/BasicAliasAnalysis.cpp (+17-4)
- (added) llvm/test/Analysis/BasicAA/gep-explicit-trunc.ll (+29)
``````````diff
diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
index 3aece3ca7d769..1a0d17baee246 100644
--- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -343,6 +343,14 @@ struct CastedValue {
return CastedValue(NewV, ZExtBits, SExtBits + ExtendBy, 0, IsNonNegative);
}
+ /// Replace V with trunc(NewV).
+ CastedValue withTruncOfValue(const Value *NewV) const {
+ unsigned TruncateBy = NewV->getType()->getPrimitiveSizeInBits() -
+ V->getType()->getPrimitiveSizeInBits();
+ return CastedValue(NewV, ZExtBits, SExtBits, TruncBits + TruncateBy,
+ IsNonNegative);
+ }
+
APInt evaluateWith(APInt N) const {
assert(N.getBitWidth() == V->getType()->getPrimitiveSizeInBits() &&
"Incompatible bit width");
@@ -517,6 +525,10 @@ static LinearExpression GetLinearExpression(
}
}
+ if (const auto *Trunc = dyn_cast<TruncInst>(Val.V))
+ return GetLinearExpression(Val.withTruncOfValue(Trunc->getOperand(0)), DL,
+ Depth + 1, AC, DT);
+
if (const auto *ZExt = dyn_cast<ZExtInst>(Val.V))
return GetLinearExpression(
Val.withZExtOfValue(ZExt->getOperand(0), ZExt->hasNonNeg()), DL,
@@ -2102,8 +2114,7 @@ bool BasicAAResult::computeConstantOffsetHeuristic(const DecomposedGEP &GEP,
const VariableGEPIndex &Var0 = GEP.VarIndices[0], &Var1 = GEP.VarIndices[1];
- if (Var0.Val.TruncBits != 0 || !Var0.Val.hasSameCastsAs(Var1.Val) ||
- !Var0.hasNegatedScaleOf(Var1) ||
+ if (!Var0.Val.hasSameCastsAs(Var1.Val) || !Var0.hasNegatedScaleOf(Var1) ||
Var0.Val.V->getType() != Var1.Val.V->getType())
return false;
@@ -2126,8 +2137,10 @@ bool BasicAAResult::computeConstantOffsetHeuristic(const DecomposedGEP &GEP,
// minimum difference between the two. The minimum distance may occur due to
// wrapping; consider "add i3 %i, 5": if %i == 7 then 7 + 5 mod 8 == 4, and so
// the minimum distance between %i and %i + 5 is 3.
- APInt MinDiff = E0.Offset - E1.Offset, Wrapped = -MinDiff;
- MinDiff = APIntOps::umin(MinDiff, Wrapped);
+ APInt MinDiff = E0.Offset - E1.Offset;
+ if (Var0.Val.TruncBits)
+ MinDiff = MinDiff.trunc(MinDiff.getBitWidth() - Var0.Val.TruncBits);
+ MinDiff = APIntOps::umin(MinDiff, -MinDiff);
APInt MinDiffBytes =
MinDiff.zextOrTrunc(Var0.Scale.getBitWidth()) * Var0.Scale.abs();
diff --git a/llvm/test/Analysis/BasicAA/gep-explicit-trunc.ll b/llvm/test/Analysis/BasicAA/gep-explicit-trunc.ll
new file mode 100644
index 0000000000000..97747fda29952
--- /dev/null
+++ b/llvm/test/Analysis/BasicAA/gep-explicit-trunc.ll
@@ -0,0 +1,29 @@
+; RUN: opt < %s -aa-pipeline=basic-aa -passes=aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+
+target datalayout = "e-p:64:64"
+
+; CHECK-LABEL: Function: trunc_offset
+; CHECK: NoAlias: i32* %p, i32* %q
+define void @trunc_offset(ptr %base, i64 %x) {
+ %next = add i64 %x, 1
+ %i = trunc i64 %x to i32
+ %j = trunc i64 %next to i32
+ %p = getelementptr i32, ptr %base, i32 %i
+ %q = getelementptr i32, ptr %base, i32 %j
+ store i32 0, ptr %p
+ store i32 0, ptr %q
+ ret void
+}
+
+; CHECK-LABEL: Function: trunc_wrap
+; CHECK: MayAlias: i32* %p, i32* %q
+define void @trunc_wrap(ptr %base, i64 %x) {
+ %next = add i64 %x, 4294967296
+ %i = trunc i64 %x to i32
+ %j = trunc i64 %next to i32
+ %p = getelementptr i32, ptr %base, i32 %i
+ %q = getelementptr i32, ptr %base, i32 %j
+ store i32 0, ptr %p
+ store i32 0, ptr %q
+ ret void
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/228781
More information about the llvm-commits
mailing list