blob: 76e328329ea74ad1a462e633cf0bd631e6409829 [file]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt -passes="default<O3>" -enable-loop-flatten -loop-flatten-cost-threshold=3 -S %s | FileCheck %s
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
target triple = "aarch64"
; TODO: @foo_32_bit_iv is no longer flattened, because its i32 bit IV gets
; widened and LoopFlatten does not recognize the wide form.
define void @foo_32_bit_iv(ptr %A, i32 %N, i32 %M) {
; CHECK-LABEL: define void @foo_32_bit_iv(
; CHECK-SAME: ptr nofree readonly captures(none) [[A:%.*]], i32 [[N:%.*]], i32 [[M:%.*]]) local_unnamed_addr {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[CMP3:%.*]] = icmp sgt i32 [[N]], 0
; CHECK-NEXT: [[CMP21:%.*]] = icmp sgt i32 [[M]], 0
; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[CMP3]], i1 [[CMP21]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label %[[INNER_HEADER_PREHEADER_LR_PH_SPLIT:.*]], label %[[EXIT:.*]]
; CHECK: [[INNER_HEADER_PREHEADER_LR_PH_SPLIT]]:
; CHECK-NEXT: [[TMP0:%.*]] = zext nneg i32 [[M]] to i64
; CHECK-NEXT: [[TMP1:%.*]] = zext nneg i32 [[N]] to i64
; CHECK-NEXT: br label %[[INNER_HEADER_PREHEADER:.*]]
; CHECK: [[INNER_HEADER_PREHEADER]]:
; CHECK-NEXT: [[INDVAR6:%.*]] = phi i64 [ 0, %[[INNER_HEADER_PREHEADER_LR_PH_SPLIT]] ], [ [[INDVAR_NEXT7:%.*]], %[[INNER_HEADER_OUTER_LATCH_CRIT_EDGE:.*]] ]
; CHECK-NEXT: [[TMP5:%.*]] = trunc i64 [[INDVAR6]] to i32
; CHECK-NEXT: [[TMP3:%.*]] = mul i32 [[M]], [[TMP5]]
; CHECK-NEXT: [[TMP4:%.*]] = sext i32 [[TMP3]] to i64
; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr [4 x i8], ptr [[A]], i64 [[TMP4]]
; CHECK-NEXT: br label %[[INNER_LATCH:.*]]
; CHECK: [[INNER_LATCH]]:
; CHECK-NEXT: [[INDVAR:%.*]] = phi i64 [ 0, %[[INNER_HEADER_PREHEADER]] ], [ [[INDVAR_NEXT:%.*]], %[[INNER_LATCH]] ]
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr [4 x i8], ptr [[INVARIANT_GEP]], i64 [[INDVAR]]
; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
; CHECK-NEXT: tail call void @_Z1fi(i32 [[TMP2]])
; CHECK-NEXT: [[INDVAR_NEXT]] = add nuw nsw i64 [[INDVAR]], 1
; CHECK-NEXT: [[EXITCOND_NOT1:%.*]] = icmp eq i64 [[INDVAR_NEXT]], [[TMP0]]
; CHECK-NEXT: br i1 [[EXITCOND_NOT1]], label %[[INNER_HEADER_OUTER_LATCH_CRIT_EDGE]], label %[[INNER_LATCH]]
; CHECK: [[INNER_HEADER_OUTER_LATCH_CRIT_EDGE]]:
; CHECK-NEXT: [[INDVAR_NEXT7]] = add nuw nsw i64 [[INDVAR6]], 1
; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i64 [[INDVAR_NEXT7]], [[TMP1]]
; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label %[[EXIT]], label %[[INNER_HEADER_PREHEADER]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret void
;
entry:
br label %outer.header
outer.header:
%outer.iv = phi i32 [ 0, %entry ], [ %outer.iv.next, %outer.latch ]
%cmp = icmp slt i32 %outer.iv, %N
br i1 %cmp, label %outer.body, label %exit
outer.body:
br label %inner.header
inner.header:
%inner.iv = phi i32 [ 0, %outer.body ], [ %inner.iv.next, %inner.latch ]
%cmp2 = icmp slt i32 %inner.iv, %M
br i1 %cmp2, label %inner.latch, label %outer.latch
inner.latch:
%mul = mul nsw i32 %outer.iv, %M
%add = add nsw i32 %mul, %inner.iv
%idxprom = sext i32 %add to i64
%arrayidx = getelementptr inbounds i32, ptr %A, i64 %idxprom
%0 = load i32, ptr %arrayidx, align 4
call void @_Z1fi(i32 %0)
%inner.iv.next = add nsw i32 %inner.iv, 1
br label %inner.header
outer.latch:
%outer.iv.next = add nsw i32 %outer.iv, 1
br label %outer.header
exit:
ret void
}
declare dso_local void @_Z1fi(i32) #2
; Same nest, but with i64 induction variables.
define dso_local void @foo_64_bit_iv(ptr %A, i64 %N, i64 %M) {
; CHECK-LABEL: define dso_local void @foo_64_bit_iv(
; CHECK-SAME: ptr nofree readonly captures(none) [[A:%.*]], i64 [[N:%.*]], i64 [[M:%.*]]) local_unnamed_addr {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[CMP3:%.*]] = icmp sgt i64 [[N]], 0
; CHECK-NEXT: [[CMP21:%.*]] = icmp sgt i64 [[M]], 0
; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[CMP3]], i1 [[CMP21]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label %[[INNER_HEADER_PREHEADER_LVER_CHECK:.*]], label %[[EXIT:.*]]
; CHECK: [[INNER_HEADER_PREHEADER_LVER_CHECK]]:
; CHECK-NEXT: [[FLATTEN_MUL:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[N]], i64 [[M]])
; CHECK-NEXT: [[FLATTEN_OVERFLOW:%.*]] = extractvalue { i64, i1 } [[FLATTEN_MUL]], 1
; CHECK-NEXT: br i1 [[FLATTEN_OVERFLOW]], label %[[INNER_HEADER_PREHEADER_LVER_ORIG:.*]], label %[[INNER_HEADER_PREHEADER_PREHEADER:.*]]
; CHECK: [[INNER_HEADER_PREHEADER_PREHEADER]]:
; CHECK-NEXT: [[FLATTEN_TRIPCOUNT:%.*]] = extractvalue { i64, i1 } [[FLATTEN_MUL]], 0
; CHECK-NEXT: [[SMAX:%.*]] = tail call i64 @llvm.smax.i64(i64 [[FLATTEN_TRIPCOUNT]], i64 1)
; CHECK-NEXT: br label %[[INNER_HEADER_PREHEADER:.*]]
; CHECK: [[INNER_HEADER_PREHEADER_LVER_ORIG]]:
; CHECK-NEXT: [[OUTER_IV4_LVER_ORIG:%.*]] = phi i64 [ [[OUTER_IV_NEXT_LVER_ORIG:%.*]], %[[INNER_HEADER_OUTER_LATCH_CRIT_EDGE_LVER_ORIG:.*]] ], [ 0, %[[INNER_HEADER_PREHEADER_LVER_CHECK]] ]
; CHECK-NEXT: [[MUL_LVER_ORIG:%.*]] = mul nuw nsw i64 [[OUTER_IV4_LVER_ORIG]], [[M]]
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr [4 x i8], ptr [[A]], i64 [[MUL_LVER_ORIG]]
; CHECK-NEXT: br label %[[INNER_LATCH_LVER_ORIG:.*]]
; CHECK: [[INNER_LATCH_LVER_ORIG]]:
; CHECK-NEXT: [[INNER_IV2_LVER_ORIG:%.*]] = phi i64 [ 0, %[[INNER_HEADER_PREHEADER_LVER_ORIG]] ], [ [[INNER_IV_NEXT_LVER_ORIG:%.*]], %[[INNER_LATCH_LVER_ORIG]] ]
; CHECK-NEXT: [[ARRAYIDX_LVER_ORIG:%.*]] = getelementptr [4 x i8], ptr [[TMP0]], i64 [[INNER_IV2_LVER_ORIG]]
; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARRAYIDX_LVER_ORIG]], align 4
; CHECK-NEXT: tail call void @_Z1fi(i32 [[TMP1]])
; CHECK-NEXT: [[INNER_IV_NEXT_LVER_ORIG]] = add nuw nsw i64 [[INNER_IV2_LVER_ORIG]], 1
; CHECK-NEXT: [[EXITCOND7_NOT:%.*]] = icmp eq i64 [[INNER_IV_NEXT_LVER_ORIG]], [[M]]
; CHECK-NEXT: br i1 [[EXITCOND7_NOT]], label %[[INNER_HEADER_OUTER_LATCH_CRIT_EDGE_LVER_ORIG]], label %[[INNER_LATCH_LVER_ORIG]]
; CHECK: [[INNER_HEADER_OUTER_LATCH_CRIT_EDGE_LVER_ORIG]]:
; CHECK-NEXT: [[OUTER_IV_NEXT_LVER_ORIG]] = add nuw nsw i64 [[OUTER_IV4_LVER_ORIG]], 1
; CHECK-NEXT: [[EXITCOND8_NOT:%.*]] = icmp eq i64 [[OUTER_IV_NEXT_LVER_ORIG]], [[N]]
; CHECK-NEXT: br i1 [[EXITCOND8_NOT]], label %[[EXIT]], label %[[INNER_HEADER_PREHEADER_LVER_ORIG]]
; CHECK: [[INNER_HEADER_PREHEADER]]:
; CHECK-NEXT: [[OUTER_IV4:%.*]] = phi i64 [ [[OUTER_IV_NEXT:%.*]], %[[INNER_HEADER_PREHEADER]] ], [ 0, %[[INNER_HEADER_PREHEADER_PREHEADER]] ]
; CHECK-NEXT: [[FLATTEN_ARRAYIDX:%.*]] = getelementptr [4 x i8], ptr [[A]], i64 [[OUTER_IV4]]
; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[FLATTEN_ARRAYIDX]], align 4
; CHECK-NEXT: tail call void @_Z1fi(i32 [[TMP2]])
; CHECK-NEXT: [[OUTER_IV_NEXT]] = add nuw nsw i64 [[OUTER_IV4]], 1
; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i64 [[OUTER_IV_NEXT]], [[SMAX]]
; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label %[[EXIT]], label %[[INNER_HEADER_PREHEADER]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret void
;
entry:
br label %outer.header
outer.header:
%outer.iv = phi i64 [ 0, %entry ], [ %outer.iv.next, %outer.latch ]
%cmp = icmp slt i64 %outer.iv, %N
br i1 %cmp, label %outer.body, label %exit
outer.body:
br label %inner.header
inner.header:
%inner.iv = phi i64 [ 0, %outer.body ], [ %inner.iv.next, %inner.latch ]
%cmp2 = icmp slt i64 %inner.iv, %M
br i1 %cmp2, label %inner.latch, label %outer.latch
inner.latch:
%mul = mul nsw i64 %outer.iv, %M
%add = add nsw i64 %mul, %inner.iv
%arrayidx = getelementptr inbounds i32, ptr %A, i64 %add
%0 = load i32, ptr %arrayidx, align 4
call void @_Z1fi(i32 %0)
%inner.iv.next = add nsw i64 %inner.iv, 1
br label %inner.header
outer.latch:
%outer.iv.next = add nsw i64 %outer.iv, 1
br label %outer.header
exit:
ret void
}