blob: c5c492ae7956a93c662342b7302314104b38b4cd [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt -S -passes=loop-interchange < %s | FileCheck %s
; The inner array dimension is indexed by a zero-extended i32 counter whose
; loop is governed by a separate countdown. Make sure SCEV can infer nsw here
; and the loops are interchanged.
; real :: A(5, 5)
; do i = 1, 5
; do j = 1, 5
; A(i, j) = A(i, j) + 1.0
; end do
; end do
define void @fixed_size_5x5(ptr noalias %A) {
; CHECK-LABEL: define void @fixed_size_5x5(
; CHECK-SAME: ptr noalias [[A:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: br label %[[OUTER_HEADER:.*]]
; CHECK: [[OUTER_HEADER_PREHEADER:.*]]:
; CHECK-NEXT: br label %[[OUTER_HEADER1:.*]]
; CHECK: [[OUTER_HEADER1]]:
; CHECK-NEXT: [[I_COUNT:%.*]] = phi i64 [ [[I_COUNT_NEXT:%.*]], %[[OUTER_LATCH:.*]] ], [ 5, %[[OUTER_HEADER_PREHEADER]] ]
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], %[[OUTER_LATCH]] ], [ 1, %[[OUTER_HEADER_PREHEADER]] ]
; CHECK-NEXT: [[I_EXT:%.*]] = zext nneg i32 [[I]] to i64
; CHECK-NEXT: [[ROW_GEP:%.*]] = getelementptr [4 x i8], ptr [[A]], i64 [[I_EXT]]
; CHECK-NEXT: br label %[[INNER:.*]]
; CHECK: [[OUTER_HEADER]]:
; CHECK-NEXT: br label %[[INNER1:.*]]
; CHECK: [[INNER1]]:
; CHECK-NEXT: [[J:%.*]] = phi i64 [ [[TMP0:%.*]], %[[INNER_SPLIT:.*]] ], [ 1, %[[OUTER_HEADER]] ]
; CHECK-NEXT: [[J_COUNT:%.*]] = phi i64 [ [[TMP1:%.*]], %[[INNER_SPLIT]] ], [ 5, %[[OUTER_HEADER]] ]
; CHECK-NEXT: br label %[[OUTER_HEADER_PREHEADER]]
; CHECK: [[INNER]]:
; CHECK-NEXT: [[COL_OFF:%.*]] = mul nuw nsw i64 [[J]], 20
; CHECK-NEXT: [[ELT_GEP:%.*]] = getelementptr i8, ptr [[ROW_GEP]], i64 [[COL_OFF]]
; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i8, ptr [[ELT_GEP]], i64 -24
; CHECK-NEXT: [[V:%.*]] = load float, ptr [[ADDR]], align 4
; CHECK-NEXT: [[INC:%.*]] = fadd contract float [[V]], 1.000000e+00
; CHECK-NEXT: store float [[INC]], ptr [[ADDR]], align 4
; CHECK-NEXT: [[J_NEXT:%.*]] = add nuw nsw i64 [[J]], 1
; CHECK-NEXT: [[J_COUNT_NEXT:%.*]] = add nsw i64 [[J_COUNT]], -1
; CHECK-NEXT: [[J_DONE:%.*]] = icmp eq i64 [[J_COUNT_NEXT]], 0
; CHECK-NEXT: br label %[[OUTER_LATCH]]
; CHECK: [[INNER_SPLIT]]:
; CHECK-NEXT: [[TMP0]] = add nuw nsw i64 [[J]], 1
; CHECK-NEXT: [[TMP1]] = add nsw i64 [[J_COUNT]], -1
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 0
; CHECK-NEXT: br i1 [[TMP2]], label %[[EXIT:.*]], label %[[INNER1]]
; CHECK: [[OUTER_LATCH]]:
; CHECK-NEXT: [[I_NEXT]] = add nuw nsw i32 [[I]], 1
; CHECK-NEXT: [[I_COUNT_NEXT]] = add nsw i64 [[I_COUNT]], -1
; CHECK-NEXT: [[I_CMP:%.*]] = icmp sgt i64 [[I_COUNT]], 1
; CHECK-NEXT: br i1 [[I_CMP]], label %[[OUTER_HEADER1]], label %[[INNER_SPLIT]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret void
;
entry:
br label %outer.header
outer.header:
%i.count = phi i64 [ 5, %entry ], [ %i.count.next, %outer.latch ]
%i = phi i32 [ 1, %entry ], [ %i.next, %outer.latch ]
%i.ext = zext nneg i32 %i to i64
%row.gep = getelementptr [4 x i8], ptr %A, i64 %i.ext
br label %inner
inner:
%j = phi i64 [ 1, %outer.header ], [ %j.next, %inner ]
%j.count = phi i64 [ 5, %outer.header ], [ %j.count.next, %inner ]
%col.off = mul nuw nsw i64 %j, 20
%elt.gep = getelementptr i8, ptr %row.gep, i64 %col.off
%addr = getelementptr i8, ptr %elt.gep, i64 -24
%v = load float, ptr %addr, align 4
%inc = fadd contract float %v, 1.000000e+00
store float %inc, ptr %addr, align 4
%j.next = add nuw nsw i64 %j, 1
%j.count.next = add nsw i64 %j.count, -1
%j.done = icmp eq i64 %j.count.next, 0
br i1 %j.done, label %outer.latch, label %inner
outer.latch:
%i.next = add nuw nsw i32 %i, 1
%i.count.next = add nsw i64 %i.count, -1
%i.cmp = icmp sgt i64 %i.count, 1
br i1 %i.cmp, label %outer.header, label %exit
exit:
ret void
}