| ; 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 |
| } |