[llvm] b2d3db9 - [SCEV] Derive element size from the access's own pointer address space (#209824)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 20 08:17:44 PDT 2026
Author: Jinsong Ji
Date: 2026-07-20T11:17:38-04:00
New Revision: b2d3db9bfb01ceb821b38dfc57f7965b09f602cf
URL: https://github.com/llvm/llvm-project/commit/b2d3db9bfb01ceb821b38dfc57f7965b09f602cf
DIFF: https://github.com/llvm/llvm-project/commit/b2d3db9bfb01ceb821b38dfc57f7965b09f602cf.diff
LOG: [SCEV] Derive element size from the access's own pointer address space (#209824)
ScalarEvolution::getElementSize always derived the element-size SCEV
using a generic address-space-0 pointer index type. On targets whose
data layout uses different pointer index widths per address space (for
example, where some address spaces use 32-bit pointers and others
64-bit), a load/store through a narrow address space produced an access
function SCEV of one width but an element-size SCEV of another.
Delinearization then called SCEVDivision::divide with numerator and
denominator of mismatched types, tripping the assertion added in
a9d295d615a8 once the implicit sign-extension was removed in
23a32bcedb91.
Derive the index type from the memory access's actual pointer operand
address space so the element-size SCEV matches the width of the access
function's SCEV.
Added:
llvm/test/Analysis/Delinearization/multidim_pointer_addrspace.ll
Modified:
llvm/lib/Analysis/ScalarEvolution.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 2a3325052ec80..ce103e245284e 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -14100,14 +14100,18 @@ bool ScalarEvolution::containsErasedValue(const SCEV *S) const {
/// Return the size of an element read or written by Inst.
const SCEV *ScalarEvolution::getElementSize(Instruction *Inst) {
Type *Ty;
- if (StoreInst *Store = dyn_cast<StoreInst>(Inst))
+ Type *PtrTy;
+ if (StoreInst *Store = dyn_cast<StoreInst>(Inst)) {
Ty = Store->getValueOperand()->getType();
- else if (LoadInst *Load = dyn_cast<LoadInst>(Inst))
+ PtrTy = Store->getPointerOperandType();
+ } else if (LoadInst *Load = dyn_cast<LoadInst>(Inst)) {
Ty = Load->getType();
- else
+ PtrTy = Load->getPointerOperandType();
+ } else {
return nullptr;
+ }
- Type *ETy = getEffectiveSCEVType(PointerType::getUnqual(Inst->getContext()));
+ Type *ETy = getEffectiveSCEVType(PtrTy);
return getSizeOfExpr(ETy, Ty);
}
diff --git a/llvm/test/Analysis/Delinearization/multidim_pointer_addrspace.ll b/llvm/test/Analysis/Delinearization/multidim_pointer_addrspace.ll
new file mode 100644
index 0000000000000..cff1c6937d007
--- /dev/null
+++ b/llvm/test/Analysis/Delinearization/multidim_pointer_addrspace.ll
@@ -0,0 +1,62 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes='print<delinearization>' -disable-output 2>&1 | FileCheck %s
+
+; The element-size SCEV is derived from the index type of the access's actual
+; pointer operand. On a target whose data layout gives
diff erent pointer index
+; widths per address space, an access through a narrow (32-bit) address space
+; must not produce a 64-bit element size, otherwise delinearization would call
+; SCEVDivision::divide with mismatched operand types and trip an assertion.
+;
+; Derived from the following code (with A in a 32-bit address space):
+;
+; void foo(int n, int m, double A[n][m]) {
+; for (int i = 0; i < n; i++)
+; for (int j = 0; j < m; j++)
+; A[i][j] = 1.0;
+; }
+
+; Address space 3 uses 32-bit pointers; the default address space uses 64-bit.
+target datalayout = "e-p:64:64-p3:32:32-i64:64-n32:64"
+
+define void @foo(i32 %n, i32 %m, ptr addrspace(3) %A) {
+; CHECK-LABEL: 'foo'
+; CHECK-NEXT: Inst: %val = load double, ptr addrspace(3) %arrayidx, align 8
+; CHECK-NEXT: AccessFunction: {{\{\{}}0,+,(8 * %m)}<%for.i>,+,8}<%for.j>
+; CHECK-NEXT: Base offset: %A
+; CHECK-NEXT: ArrayDecl[UnknownSize][%m] with elements of 8 bytes.
+; CHECK-NEXT: ArrayRef[{0,+,1}<nuw><nsw><%for.i>][{0,+,1}<nuw><nsw><%for.j>]
+; CHECK-NEXT: Delinearization validation: Failed
+; CHECK-EMPTY:
+; CHECK-NEXT: Inst: store double %val, ptr addrspace(3) %arrayidx, align 8
+; CHECK-NEXT: AccessFunction: {{\{\{}}0,+,(8 * %m)}<%for.i>,+,8}<%for.j>
+; CHECK-NEXT: Base offset: %A
+; CHECK-NEXT: ArrayDecl[UnknownSize][%m] with elements of 8 bytes.
+; CHECK-NEXT: ArrayRef[{0,+,1}<nuw><nsw><%for.i>][{0,+,1}<nuw><nsw><%for.j>]
+; CHECK-NEXT: Delinearization validation: Failed
+;
+entry:
+ br label %for.i
+
+for.i:
+ %i = phi i32 [ 0, %entry ], [ %i.inc, %for.i.inc ]
+ %tmp = mul nsw i32 %i, %m
+ br label %for.j
+
+for.j:
+ %j = phi i32 [ 0, %for.i ], [ %j.inc, %for.j ]
+ %sum = add i32 %j, %tmp
+ %arrayidx = getelementptr inbounds double, ptr addrspace(3) %A, i32 %sum
+ %val = load double, ptr addrspace(3) %arrayidx
+ store double %val, ptr addrspace(3) %arrayidx
+ %j.inc = add nsw i32 %j, 1
+ %j.exitcond = icmp eq i32 %j.inc, %m
+ br i1 %j.exitcond, label %for.i.inc, label %for.j
+
+for.i.inc:
+ %i.inc = add nsw i32 %i, 1
+ %i.exitcond = icmp eq i32 %i.inc, %n
+ br i1 %i.exitcond, label %end, label %for.i
+
+end:
+ ret void
+}
More information about the llvm-commits
mailing list