This patch moves the validation logic of delinearization results from DA to Delinearization. Also call it in `printDelinearization` to test its behavior. The motivation is as follows: - Almost the same code exists in `tryDelinearizeFixedSize` and `tryDelinearizeParametricSize`. Consolidating it in Delinearization avoids code duplication. - Currently this validation logic is not well tested. Moving it to Delinearization allows us to write regression tests easily. This patch changes the test outputs and debug messages, but otherwise NFCI.
538 lines
16 KiB
LLVM
538 lines
16 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 5
|
|
; RUN: opt < %s -passes='print<delinearization>' -disable-output -delinearize-use-fixed-size-array-heuristic 2>&1 | FileCheck %s
|
|
|
|
; void f(int A[][8][32]) {
|
|
; for (i = 0; i < 42; i++)
|
|
; for (j = 0; j < 8; j++)
|
|
; for (k = 0; k < 32; k++)
|
|
; A[i][j][k] = 1;
|
|
; }
|
|
|
|
define void @a_i_j_k(ptr %a) {
|
|
; CHECK-LABEL: 'a_i_j_k'
|
|
; CHECK-NEXT: Inst: store i32 1, ptr %idx, align 4
|
|
; CHECK-NEXT: AccessFunction: {{\{\{\{}}0,+,1024}<nuw><nsw><%for.i.header>,+,128}<nw><%for.j.header>,+,4}<nw><%for.k>
|
|
; CHECK-NEXT: Base offset: %a
|
|
; CHECK-NEXT: ArrayDecl[UnknownSize][8][32] with elements of 4 bytes.
|
|
; CHECK-NEXT: ArrayRef[{0,+,1}<nuw><nsw><%for.i.header>][{0,+,1}<nuw><nsw><%for.j.header>][{0,+,1}<nuw><nsw><%for.k>]
|
|
; CHECK-NEXT: Delinearization validation: Succeeded
|
|
;
|
|
entry:
|
|
br label %for.i.header
|
|
|
|
for.i.header:
|
|
%i = phi i32 [ 0, %entry ], [ %i.inc, %for.i.latch ]
|
|
br label %for.j.header
|
|
|
|
for.j.header:
|
|
%j = phi i32 [ 0, %for.i.header ], [ %j.inc, %for.j.latch ]
|
|
br label %for.k
|
|
|
|
for.k:
|
|
%k = phi i32 [ 0, %for.j.header ], [ %k.inc, %for.k ]
|
|
%idx = getelementptr [8 x [32 x i32]], ptr %a, i32 %i, i32 %j, i32 %k
|
|
store i32 1, ptr %idx
|
|
%k.inc = add i32 %k, 1
|
|
%cmp.k = icmp slt i32 %k.inc, 32
|
|
br i1 %cmp.k, label %for.k, label %for.j.latch
|
|
|
|
for.j.latch:
|
|
%j.inc = add i32 %j, 1
|
|
%cmp.j = icmp slt i32 %j.inc, 8
|
|
br i1 %cmp.j, label %for.j.header, label %for.i.latch
|
|
|
|
for.i.latch:
|
|
%i.inc = add i32 %i, 1
|
|
%cmp.i = icmp slt i32 %i.inc, 42
|
|
br i1 %cmp.i, label %for.i.header, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; void f(int A[][8][32]) {
|
|
; for (i = 0; i < 42; i++)
|
|
; for (j = 0; j < 8; j++)
|
|
; for (k = 0; k < 32; k++)
|
|
; A[i][7-j][k] = 1;
|
|
; }
|
|
|
|
define void @a_i_nj_k(ptr %a) {
|
|
; CHECK-LABEL: 'a_i_nj_k'
|
|
; CHECK-NEXT: Inst: store i32 1, ptr %idx, align 4
|
|
; CHECK-NEXT: AccessFunction: {{\{\{\{}}896,+,1024}<nuw><nsw><%for.i.header>,+,-128}<nw><%for.j.header>,+,4}<nw><%for.k>
|
|
; CHECK-NEXT: Base offset: %a
|
|
; CHECK-NEXT: ArrayDecl[UnknownSize][8][32] with elements of 4 bytes.
|
|
; CHECK-NEXT: ArrayRef[{0,+,1}<nuw><nsw><%for.i.header>][{7,+,-1}<nsw><%for.j.header>][{0,+,1}<nuw><nsw><%for.k>]
|
|
; CHECK-NEXT: Delinearization validation: Succeeded
|
|
;
|
|
entry:
|
|
br label %for.i.header
|
|
|
|
for.i.header:
|
|
%i = phi i32 [ 0, %entry ], [ %i.inc, %for.i.latch ]
|
|
br label %for.j.header
|
|
|
|
for.j.header:
|
|
%j = phi i32 [ 0, %for.i.header ], [ %j.inc, %for.j.latch ]
|
|
%j.subscript = sub i32 7, %j
|
|
br label %for.k
|
|
|
|
for.k:
|
|
%k = phi i32 [ 0, %for.j.header ], [ %k.inc, %for.k ]
|
|
%idx = getelementptr [8 x [32 x i32]], ptr %a, i32 %i, i32 %j.subscript, i32 %k
|
|
store i32 1, ptr %idx
|
|
%k.inc = add i32 %k, 1
|
|
%cmp.k = icmp slt i32 %k.inc, 32
|
|
br i1 %cmp.k, label %for.k, label %for.j.latch
|
|
|
|
for.j.latch:
|
|
%j.inc = add i32 %j, 1
|
|
%cmp.j = icmp slt i32 %j.inc, 8
|
|
br i1 %cmp.j, label %for.j.header, label %for.i.latch
|
|
|
|
for.i.latch:
|
|
%i.inc = add i32 %i, 1
|
|
%cmp.i = icmp slt i32 %i.inc, 42
|
|
br i1 %cmp.i, label %for.i.header, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; In the following code, the access functions for both stores are represented
|
|
; in the same way in SCEV, so the delinearization results are also the same. We
|
|
; don't have any type information of the underlying objects.
|
|
;
|
|
; void f(int A[][4][64], int B[][8][32]) {
|
|
; for (i = 0; i < 42; i++)
|
|
; for (j = 0; j < 4; j++)
|
|
; for (k = 0; k < 32; k++) {
|
|
; A[i][j][k] = 1;
|
|
; B[i][2*j][k] = 1;
|
|
; }
|
|
; }
|
|
|
|
define void @a_ijk_b_i2jk(ptr %a, ptr %b) {
|
|
; CHECK-LABEL: 'a_ijk_b_i2jk'
|
|
; CHECK-NEXT: Inst: store i32 1, ptr %a.idx, align 4
|
|
; CHECK-NEXT: AccessFunction: {{\{\{\{}}0,+,1024}<nuw><nsw><%for.i.header>,+,256}<nw><%for.j.header>,+,4}<nw><%for.k>
|
|
; CHECK-NEXT: Base offset: %a
|
|
; CHECK-NEXT: ArrayDecl[UnknownSize][4][64] with elements of 4 bytes.
|
|
; CHECK-NEXT: ArrayRef[{0,+,1}<nuw><nsw><%for.i.header>][{0,+,1}<nuw><nsw><%for.j.header>][{0,+,1}<nuw><nsw><%for.k>]
|
|
; CHECK-NEXT: Delinearization validation: Succeeded
|
|
; CHECK-EMPTY:
|
|
; CHECK-NEXT: Inst: store i32 1, ptr %b.idx, align 4
|
|
; CHECK-NEXT: AccessFunction: {{\{\{\{}}0,+,1024}<nuw><nsw><%for.i.header>,+,256}<nw><%for.j.header>,+,4}<nw><%for.k>
|
|
; CHECK-NEXT: Base offset: %b
|
|
; CHECK-NEXT: ArrayDecl[UnknownSize][4][64] with elements of 4 bytes.
|
|
; CHECK-NEXT: ArrayRef[{0,+,1}<nuw><nsw><%for.i.header>][{0,+,1}<nuw><nsw><%for.j.header>][{0,+,1}<nuw><nsw><%for.k>]
|
|
; CHECK-NEXT: Delinearization validation: Succeeded
|
|
;
|
|
entry:
|
|
br label %for.i.header
|
|
|
|
for.i.header:
|
|
%i = phi i32 [ 0, %entry ], [ %i.inc, %for.i.latch ]
|
|
br label %for.j.header
|
|
|
|
for.j.header:
|
|
%j = phi i32 [ 0, %for.i.header ], [ %j.inc, %for.j.latch ]
|
|
%j2 = shl i32 %j, 1
|
|
br label %for.k
|
|
|
|
for.k:
|
|
%k = phi i32 [ 0, %for.j.header ], [ %k.inc, %for.k ]
|
|
%a.idx = getelementptr [4 x [64 x i32]], ptr %a, i32 %i, i32 %j, i32 %k
|
|
%b.idx = getelementptr [8 x [32 x i32]], ptr %b, i32 %i, i32 %j2, i32 %k
|
|
store i32 1, ptr %a.idx
|
|
store i32 1, ptr %b.idx
|
|
%k.inc = add i32 %k, 1
|
|
%cmp.k = icmp slt i32 %k.inc, 32
|
|
br i1 %cmp.k, label %for.k, label %for.j.latch
|
|
|
|
for.j.latch:
|
|
%j.inc = add i32 %j, 1
|
|
%cmp.j = icmp slt i32 %j.inc, 4
|
|
br i1 %cmp.j, label %for.j.header, label %for.i.latch
|
|
|
|
for.i.latch:
|
|
%i.inc = add i32 %i, 1
|
|
%cmp.i = icmp slt i32 %i.inc, 42
|
|
br i1 %cmp.i, label %for.i.header, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; The type information of the underlying object is not available, so the
|
|
; delinearization result is different from the original array size. In this
|
|
; case, the underlying object is a type of int[][8][32], but the
|
|
; delinearization result is like int[][4][64].
|
|
;
|
|
; void f(int A[][8][32]) {
|
|
; for (i = 0; i < 42; i++)
|
|
; for (j = 0; j < 3; j++)
|
|
; for (k = 0; k < 32; k++)
|
|
; A[i][2*j+1][k] = 1;
|
|
; }
|
|
|
|
define void @a_i_2j1_k(ptr %a) {
|
|
; CHECK-LABEL: 'a_i_2j1_k'
|
|
; CHECK-NEXT: Inst: store i32 1, ptr %idx, align 4
|
|
; CHECK-NEXT: AccessFunction: {{\{\{\{}}128,+,1024}<nuw><nsw><%for.i.header>,+,256}<nw><%for.j.header>,+,4}<nw><%for.k>
|
|
; CHECK-NEXT: Base offset: %a
|
|
; CHECK-NEXT: ArrayDecl[UnknownSize][4][64] with elements of 4 bytes.
|
|
; CHECK-NEXT: ArrayRef[{0,+,1}<nuw><nsw><%for.i.header>][{0,+,1}<nuw><%for.j.header>][{32,+,1}<nw><%for.k>]
|
|
; CHECK-NEXT: Delinearization validation: Succeeded
|
|
;
|
|
entry:
|
|
br label %for.i.header
|
|
|
|
for.i.header:
|
|
%i = phi i32 [ 0, %entry ], [ %i.inc, %for.i.latch ]
|
|
br label %for.j.header
|
|
|
|
for.j.header:
|
|
%j = phi i32 [ 0, %for.i.header ], [ %j.inc, %for.j.latch ]
|
|
%j2 = shl i32 %j, 1
|
|
%j.subscript = add i32 %j2, 1
|
|
br label %for.k
|
|
|
|
for.k:
|
|
%k = phi i32 [ 0, %for.j.header ], [ %k.inc, %for.k ]
|
|
%idx = getelementptr [8 x [32 x i32]], ptr %a, i32 %i, i32 %j.subscript, i32 %k
|
|
store i32 1, ptr %idx
|
|
%k.inc = add i32 %k, 1
|
|
%cmp.k = icmp slt i32 %k.inc, 32
|
|
br i1 %cmp.k, label %for.k, label %for.j.latch
|
|
|
|
for.j.latch:
|
|
%j.inc = add i32 %j, 1
|
|
%cmp.j = icmp slt i32 %j.inc, 3
|
|
br i1 %cmp.j, label %for.j.header, label %for.i.latch
|
|
|
|
for.i.latch:
|
|
%i.inc = add i32 %i, 1
|
|
%cmp.i = icmp slt i32 %i.inc, 42
|
|
br i1 %cmp.i, label %for.i.header, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Fail to delinearize because the step recurrence value of the i-loop is not
|
|
; divisible by that of the j-loop.
|
|
;
|
|
; void f(int A[][8][32]) {
|
|
; for (i = 0; i < 42; i++)
|
|
; for (j = 0; j < 2; j++)
|
|
; for (k = 0; k < 42; k++)
|
|
; A[i][3*j][k] = 1;
|
|
; }
|
|
|
|
define void @a_i_3j_k(ptr %a) {
|
|
; CHECK-LABEL: 'a_i_3j_k'
|
|
; CHECK-NEXT: Inst: store i32 1, ptr %idx, align 4
|
|
; CHECK-NEXT: AccessFunction: {{\{\{\{}}0,+,1024}<nuw><nsw><%for.i.header>,+,384}<nw><%for.j.header>,+,4}<nw><%for.k>
|
|
; CHECK-NEXT: failed to delinearize
|
|
;
|
|
entry:
|
|
br label %for.i.header
|
|
|
|
for.i.header:
|
|
%i = phi i32 [ 0, %entry ], [ %i.inc, %for.i.latch ]
|
|
br label %for.j.header
|
|
|
|
for.j.header:
|
|
%j = phi i32 [ 0, %for.i.header ], [ %j.inc, %for.j.latch ]
|
|
%j.subscript = mul i32 %j, 3
|
|
br label %for.k
|
|
|
|
for.k:
|
|
%k = phi i32 [ 0, %for.j.header ], [ %k.inc, %for.k ]
|
|
%idx = getelementptr [8 x [32 x i32]], ptr %a, i32 %i, i32 %j.subscript, i32 %k
|
|
store i32 1, ptr %idx
|
|
%k.inc = add i32 %k, 1
|
|
%cmp.k = icmp slt i32 %k.inc, 42
|
|
br i1 %cmp.k, label %for.k, label %for.j.latch
|
|
|
|
for.j.latch:
|
|
%j.inc = add i32 %j, 1
|
|
%cmp.j = icmp slt i32 %j.inc, 2
|
|
br i1 %cmp.j, label %for.j.header, label %for.i.latch
|
|
|
|
for.i.latch:
|
|
%i.inc = add i32 %i, 1
|
|
%cmp.i = icmp slt i32 %i.inc, 42
|
|
br i1 %cmp.i, label %for.i.header, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Although the step recurrence value of j-loop is not divisible by that of the
|
|
; k-loop, delinearization is possible because we know that the "actual" stride
|
|
; width for the last dimension is 4 instead of 12.
|
|
;
|
|
; void f(int A[][8][32]) {
|
|
; for (i = 0; i < 42; i++)
|
|
; for (j = 0; j < 8; j++)
|
|
; for (k = 0; k < 10; k++)
|
|
; A[i][j][3*k] = 1;
|
|
; }
|
|
|
|
define void @a_i_j_3k(ptr %a) {
|
|
; CHECK-LABEL: 'a_i_j_3k'
|
|
; CHECK-NEXT: Inst: store i32 1, ptr %idx, align 4
|
|
; CHECK-NEXT: AccessFunction: {{\{\{\{}}0,+,1024}<nuw><nsw><%for.i.header>,+,128}<nw><%for.j.header>,+,12}<nw><%for.k>
|
|
; CHECK-NEXT: Base offset: %a
|
|
; CHECK-NEXT: ArrayDecl[UnknownSize][8][32] with elements of 4 bytes.
|
|
; CHECK-NEXT: ArrayRef[{0,+,1}<nuw><nsw><%for.i.header>][{0,+,1}<nuw><nsw><%for.j.header>][{0,+,3}<nuw><nsw><%for.k>]
|
|
; CHECK-NEXT: Delinearization validation: Succeeded
|
|
;
|
|
entry:
|
|
br label %for.i.header
|
|
|
|
for.i.header:
|
|
%i = phi i32 [ 0, %entry ], [ %i.inc, %for.i.latch ]
|
|
br label %for.j.header
|
|
|
|
for.j.header:
|
|
%j = phi i32 [ 0, %for.i.header ], [ %j.inc, %for.j.latch ]
|
|
br label %for.k
|
|
|
|
for.k:
|
|
%k = phi i32 [ 0, %for.j.header ], [ %k.inc, %for.k ]
|
|
%k.subscript = mul i32 %k, 3
|
|
%idx = getelementptr [8 x [32 x i32]], ptr %a, i32 %i, i32 %j, i32 %k.subscript
|
|
store i32 1, ptr %idx
|
|
%k.inc = add i32 %k, 1
|
|
%cmp.k = icmp slt i32 %k.inc, 10
|
|
br i1 %cmp.k, label %for.k, label %for.j.latch
|
|
|
|
for.j.latch:
|
|
%j.inc = add i32 %j, 1
|
|
%cmp.j = icmp slt i32 %j.inc, 8
|
|
br i1 %cmp.j, label %for.j.header, label %for.i.latch
|
|
|
|
for.i.latch:
|
|
%i.inc = add i32 %i, 1
|
|
%cmp.i = icmp slt i32 %i.inc, 42
|
|
br i1 %cmp.i, label %for.i.header, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Fail to delinearize because i is used in multiple subscripts that are not adjacent.
|
|
;
|
|
; void f(int A[][8][32]) {
|
|
; for (i = 0; i < 32; i++)
|
|
; for (j = 0; j < 2; j++)
|
|
; for (k = 0; k < 4; k++)
|
|
; A[i][2*j+k][i] = 1;
|
|
; }
|
|
|
|
define void @a_i_j2k_i(ptr %a) {
|
|
; CHECK-LABEL: 'a_i_j2k_i'
|
|
; CHECK-NEXT: Inst: store i32 1, ptr %idx, align 4
|
|
; CHECK-NEXT: AccessFunction: {{\{\{\{}}0,+,1028}<%for.i.header>,+,256}<nw><%for.j.header>,+,128}<nw><%for.k>
|
|
; CHECK-NEXT: failed to delinearize
|
|
;
|
|
entry:
|
|
br label %for.i.header
|
|
|
|
for.i.header:
|
|
%i = phi i32 [ 0, %entry ], [ %i.inc, %for.i.latch ]
|
|
br label %for.j.header
|
|
|
|
for.j.header:
|
|
%j = phi i32 [ 0, %for.i.header ], [ %j.inc, %for.j.latch ]
|
|
br label %for.k
|
|
|
|
for.k:
|
|
%k = phi i32 [ 0, %for.j.header ], [ %k.inc, %for.k ]
|
|
%j2 = shl i32 %j, 1
|
|
%j2.k = add i32 %j2, %k
|
|
%idx = getelementptr [8 x [32 x i32]], ptr %a, i32 %i, i32 %j2.k, i32 %i
|
|
store i32 1, ptr %idx
|
|
%k.inc = add i32 %k, 1
|
|
%cmp.k = icmp slt i32 %k.inc, 4
|
|
br i1 %cmp.k, label %for.k, label %for.j.latch
|
|
|
|
for.j.latch:
|
|
%j.inc = add i32 %j, 1
|
|
%cmp.j = icmp slt i32 %j.inc, 2
|
|
br i1 %cmp.j, label %for.j.header, label %for.i.latch
|
|
|
|
for.i.latch:
|
|
%i.inc = add i32 %i, 1
|
|
%cmp.i = icmp slt i32 %i.inc, 32
|
|
br i1 %cmp.i, label %for.i.header, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Can delinearize, but the result is different from the original array size. In
|
|
; this case, the outermost two dimensions are melded into one.
|
|
;
|
|
; void f(int A[][8][32]) {
|
|
; for (i = 0; i < 8; i++)
|
|
; for (j = 0; j < 10; j++)
|
|
; for (k = 0; k < 10; k++)
|
|
; A[i][i][j+k] = 1;
|
|
; }
|
|
|
|
define void @a_i_i_jk(ptr %a) {
|
|
; CHECK-LABEL: 'a_i_i_jk'
|
|
; CHECK-NEXT: Inst: store i32 1, ptr %idx, align 4
|
|
; CHECK-NEXT: AccessFunction: {{\{\{\{}}0,+,1152}<%for.i.header>,+,4}<nw><%for.j.header>,+,4}<nw><%for.k>
|
|
; CHECK-NEXT: Base offset: %a
|
|
; CHECK-NEXT: ArrayDecl[UnknownSize][288] with elements of 4 bytes.
|
|
; CHECK-NEXT: ArrayRef[{0,+,1}<nuw><nsw><%for.i.header>][{{\{\{}}0,+,1}<nuw><nsw><%for.j.header>,+,1}<nuw><nsw><%for.k>]
|
|
; CHECK-NEXT: Delinearization validation: Succeeded
|
|
;
|
|
entry:
|
|
br label %for.i.header
|
|
|
|
for.i.header:
|
|
%i = phi i32 [ 0, %entry ], [ %i.inc, %for.i.latch ]
|
|
br label %for.j.header
|
|
|
|
for.j.header:
|
|
%j = phi i32 [ 0, %for.i.header ], [ %j.inc, %for.j.latch ]
|
|
br label %for.k
|
|
|
|
for.k:
|
|
%k = phi i32 [ 0, %for.j.header ], [ %k.inc, %for.k ]
|
|
%jk = add i32 %j, %k
|
|
%idx = getelementptr [8 x [32 x i32]], ptr %a, i32 %i, i32 %i, i32 %jk
|
|
store i32 1, ptr %idx
|
|
%k.inc = add i32 %k, 1
|
|
%cmp.k = icmp slt i32 %k.inc, 10
|
|
br i1 %cmp.k, label %for.k, label %for.j.latch
|
|
|
|
for.j.latch:
|
|
%j.inc = add i32 %j, 1
|
|
%cmp.j = icmp slt i32 %j.inc, 10
|
|
br i1 %cmp.j, label %for.j.header, label %for.i.latch
|
|
|
|
for.i.latch:
|
|
%i.inc = add i32 %i, 1
|
|
%cmp.i = icmp slt i32 %i.inc, 8
|
|
br i1 %cmp.i, label %for.i.header, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; void f(int A[][8][32]) {
|
|
; for (i = 0; i < 8; i++)
|
|
; for (j = 0; j < 4; j++)
|
|
; for (k = 0; k < 4; k++)
|
|
; for (l = 0; l < 32; l++)
|
|
; A[i][j+k][l] = 1;
|
|
; }
|
|
|
|
define void @a_i_jk_l(ptr %a) {
|
|
; CHECK-LABEL: 'a_i_jk_l'
|
|
; CHECK-NEXT: Inst: store i32 1, ptr %idx, align 4
|
|
; CHECK-NEXT: AccessFunction: {{\{\{\{\{}}0,+,1024}<nuw><nsw><%for.i.header>,+,128}<nw><%for.j.header>,+,128}<nw><%for.k.header>,+,4}<nw><%for.l>
|
|
; CHECK-NEXT: Base offset: %a
|
|
; CHECK-NEXT: ArrayDecl[UnknownSize][8][32] with elements of 4 bytes.
|
|
; CHECK-NEXT: ArrayRef[{0,+,1}<nuw><nsw><%for.i.header>][{{\{\{}}0,+,1}<nuw><nsw><%for.j.header>,+,1}<nuw><nsw><%for.k.header>][{0,+,1}<nuw><nsw><%for.l>]
|
|
; CHECK-NEXT: Delinearization validation: Succeeded
|
|
;
|
|
entry:
|
|
br label %for.i.header
|
|
|
|
for.i.header:
|
|
%i = phi i32 [ 0, %entry ], [ %i.inc, %for.i.latch ]
|
|
br label %for.j.header
|
|
|
|
for.j.header:
|
|
%j = phi i32 [ 0, %for.i.header ], [ %j.inc, %for.j.latch ]
|
|
br label %for.k.header
|
|
|
|
for.k.header:
|
|
%k = phi i32 [ 0, %for.j.header ], [ %k.inc, %for.k.latch ]
|
|
%jk = add i32 %j, %k
|
|
br label %for.l
|
|
|
|
for.l:
|
|
%l = phi i32 [ 0, %for.k.header ], [ %l.inc, %for.l ]
|
|
%idx = getelementptr [8 x [32 x i32]], ptr %a, i32 %i, i32 %jk, i32 %l
|
|
store i32 1, ptr %idx
|
|
%l.inc = add i32 %l, 1
|
|
%cmp.l = icmp slt i32 %l.inc, 32
|
|
br i1 %cmp.l, label %for.l, label %for.k.latch
|
|
|
|
for.k.latch:
|
|
%k.inc = add i32 %k, 1
|
|
%cmp.k = icmp slt i32 %k.inc, 4
|
|
br i1 %cmp.k, label %for.k.header, label %for.j.latch
|
|
|
|
for.j.latch:
|
|
%j.inc = add i32 %j, 1
|
|
%cmp.j = icmp slt i32 %j.inc, 4
|
|
br i1 %cmp.j, label %for.j.header, label %for.i.latch
|
|
|
|
for.i.latch:
|
|
%i.inc = add i32 %i, 1
|
|
%cmp.i = icmp slt i32 %i.inc, 8
|
|
br i1 %cmp.i, label %for.i.header, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Reject if the address is not a multiple of the element size.
|
|
;
|
|
; void f(int *A) {
|
|
; for (i = 0; i < 42; i++)
|
|
; for (j = 0; j < 8; j++)
|
|
; for (k = 0; k < 32; k++)
|
|
; *((int *)((char *)A + i*256 + j*32 + k)) = 1;
|
|
; }
|
|
|
|
define void @non_divisible_by_element_size(ptr %a) {
|
|
; CHECK-LABEL: 'non_divisible_by_element_size'
|
|
; CHECK-NEXT: Inst: store i32 1, ptr %idx, align 4
|
|
; CHECK-NEXT: AccessFunction: {{\{\{\{}}0,+,256}<nuw><nsw><%for.i.header>,+,32}<nw><%for.j.header>,+,1}<nw><%for.k>
|
|
; CHECK-NEXT: failed to delinearize
|
|
;
|
|
entry:
|
|
br label %for.i.header
|
|
|
|
for.i.header:
|
|
%i = phi i32 [ 0, %entry ], [ %i.inc, %for.i.latch ]
|
|
br label %for.j.header
|
|
|
|
for.j.header:
|
|
%j = phi i32 [ 0, %for.i.header ], [ %j.inc, %for.j.latch ]
|
|
br label %for.k
|
|
|
|
for.k:
|
|
%k = phi i32 [ 0, %for.j.header ], [ %k.inc, %for.k ]
|
|
%idx = getelementptr [8 x [32 x i8]], ptr %a, i32 %i, i32 %j, i32 %k
|
|
store i32 1, ptr %idx
|
|
%k.inc = add i32 %k, 1
|
|
%cmp.k = icmp slt i32 %k.inc, 32
|
|
br i1 %cmp.k, label %for.k, label %for.j.latch
|
|
|
|
for.j.latch:
|
|
%j.inc = add i32 %j, 1
|
|
%cmp.j = icmp slt i32 %j.inc, 8
|
|
br i1 %cmp.j, label %for.j.header, label %for.i.latch
|
|
|
|
for.i.latch:
|
|
%i.inc = add i32 %i, 1
|
|
%cmp.i = icmp slt i32 %i.inc, 42
|
|
br i1 %cmp.i, label %for.i.header, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|