[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