[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 ina9d295d615once the implicit sign-extension was removed in23a32bcedb. 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.
This commit is contained in:
parent
7bbed7999d
commit
b2d3db9bfb
2 changed files with 70 additions and 4 deletions
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 different 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
|
||||
}
|
||||
Loading…
Reference in a new issue