1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -S -irce -verify-loop-info -verify < %s 2>&1 | FileCheck %s 3; RUN: opt -S -verify-loop-info -passes=irce,verify < %s 2>&1 | FileCheck %s 4 5define i32 @test_01(i32 %A, i64 %Len, i32 *%array) { 6; CHECK-LABEL: @test_01( 7; CHECK-NEXT: preheader: 8; CHECK-NEXT: [[TRIPCHECK:%.*]] = icmp sgt i64 [[LEN:%.*]], 2 9; CHECK-NEXT: br i1 [[TRIPCHECK]], label [[LOOP_PREHEADER:%.*]], label [[ZERO:%.*]] 10; CHECK: loop.preheader: 11; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[A:%.*]] to i64 12; CHECK-NEXT: [[TMP1:%.*]] = add nuw nsw i64 [[TMP0]], 1 13; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i64 [[LEN]], 0 14; CHECK-NEXT: [[SMIN:%.*]] = select i1 [[TMP2]], i64 [[LEN]], i64 0 15; CHECK-NEXT: [[TMP3:%.*]] = sub i64 [[LEN]], [[SMIN]] 16; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], [[TMP1]] 17; CHECK-NEXT: [[UMIN:%.*]] = select i1 [[TMP4]], i64 [[TMP3]], i64 [[TMP1]] 18; CHECK-NEXT: [[TMP5:%.*]] = icmp ugt i64 [[UMIN]], 1 19; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = select i1 [[TMP5]], i64 [[UMIN]], i64 1 20; CHECK-NEXT: [[TMP6:%.*]] = icmp ult i64 1, [[EXIT_MAINLOOP_AT]] 21; CHECK-NEXT: br i1 [[TMP6]], label [[LOOP_PREHEADER2:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]] 22; CHECK: loop.preheader2: 23; CHECK-NEXT: br label [[LOOP:%.*]] 24; CHECK: loop: 25; CHECK-NEXT: [[INDVAR:%.*]] = phi i64 [ [[INDVAR_NEXT:%.*]], [[LATCH:%.*]] ], [ 1, [[LOOP_PREHEADER2]] ] 26; CHECK-NEXT: [[TMP7:%.*]] = icmp ult i64 [[INDVAR]], [[LEN]] 27; CHECK-NEXT: br i1 true, label [[GUARDED:%.*]], label [[DEOPT_LOOPEXIT3:%.*]] 28; CHECK: guarded: 29; CHECK-NEXT: [[ADDR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY:%.*]], i64 [[INDVAR]] 30; CHECK-NEXT: [[RES:%.*]] = load i32, i32* [[ADDR]] 31; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[RES]], 0 32; CHECK-NEXT: br i1 [[CMP]], label [[ZERO_LOOPEXIT_LOOPEXIT4:%.*]], label [[LATCH]] 33; CHECK: latch: 34; CHECK-NEXT: [[INDVAR_NEXT]] = add nuw nsw i64 [[INDVAR]], 2 35; CHECK-NEXT: [[RES2:%.*]] = mul i32 [[RES]], 3 36; CHECK-NEXT: [[TMP8:%.*]] = zext i32 [[A]] to i64 37; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i64 [[INDVAR_NEXT]], [[TMP8]] 38; CHECK-NEXT: [[TMP9:%.*]] = icmp ult i64 [[INDVAR_NEXT]], [[EXIT_MAINLOOP_AT]] 39; CHECK-NEXT: [[TMP10:%.*]] = xor i1 [[TMP9]], true 40; CHECK-NEXT: br i1 [[TMP10]], label [[MAIN_EXIT_SELECTOR:%.*]], label [[LOOP]] 41; CHECK: main.exit.selector: 42; CHECK-NEXT: [[INDVAR_NEXT_LCSSA:%.*]] = phi i64 [ [[INDVAR_NEXT]], [[LATCH]] ] 43; CHECK-NEXT: [[RES2_LCSSA1:%.*]] = phi i32 [ [[RES2]], [[LATCH]] ] 44; CHECK-NEXT: [[TMP11:%.*]] = icmp ult i64 [[INDVAR_NEXT_LCSSA]], [[TMP1]] 45; CHECK-NEXT: br i1 [[TMP11]], label [[MAIN_PSEUDO_EXIT]], label [[LOOPEXIT:%.*]] 46; CHECK: main.pseudo.exit: 47; CHECK-NEXT: [[INDVAR_COPY:%.*]] = phi i64 [ 1, [[LOOP_PREHEADER]] ], [ [[INDVAR_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] 48; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i64 [ 1, [[LOOP_PREHEADER]] ], [ [[INDVAR_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] 49; CHECK-NEXT: br label [[POSTLOOP:%.*]] 50; CHECK: loopexit.loopexit: 51; CHECK-NEXT: [[RES2_LCSSA_PH:%.*]] = phi i32 [ [[RES2_POSTLOOP:%.*]], [[LATCH_POSTLOOP:%.*]] ] 52; CHECK-NEXT: br label [[LOOPEXIT]] 53; CHECK: loopexit: 54; CHECK-NEXT: [[RES2_LCSSA:%.*]] = phi i32 [ [[RES2_LCSSA1]], [[MAIN_EXIT_SELECTOR]] ], [ [[RES2_LCSSA_PH]], [[LOOPEXIT_LOOPEXIT:%.*]] ] 55; CHECK-NEXT: ret i32 [[RES2_LCSSA]] 56; CHECK: zero.loopexit.loopexit: 57; CHECK-NEXT: br label [[ZERO_LOOPEXIT:%.*]] 58; CHECK: zero.loopexit.loopexit4: 59; CHECK-NEXT: br label [[ZERO_LOOPEXIT]] 60; CHECK: zero.loopexit: 61; CHECK-NEXT: br label [[ZERO]] 62; CHECK: zero: 63; CHECK-NEXT: ret i32 0 64; CHECK: deopt.loopexit: 65; CHECK-NEXT: br label [[DEOPT:%.*]] 66; CHECK: deopt.loopexit3: 67; CHECK-NEXT: br label [[DEOPT]] 68; CHECK: deopt: 69; CHECK-NEXT: ret i32 1 70; CHECK: postloop: 71; CHECK-NEXT: br label [[LOOP_POSTLOOP:%.*]] 72; CHECK: loop.postloop: 73; CHECK-NEXT: [[INDVAR_POSTLOOP:%.*]] = phi i64 [ [[INDVAR_NEXT_POSTLOOP:%.*]], [[LATCH_POSTLOOP]] ], [ [[INDVAR_COPY]], [[POSTLOOP]] ] 74; CHECK-NEXT: [[TMP12:%.*]] = icmp ult i64 [[INDVAR_POSTLOOP]], [[LEN]] 75; CHECK-NEXT: br i1 [[TMP12]], label [[GUARDED_POSTLOOP:%.*]], label [[DEOPT_LOOPEXIT:%.*]] 76; CHECK: guarded.postloop: 77; CHECK-NEXT: [[ADDR_POSTLOOP:%.*]] = getelementptr inbounds i32, i32* [[ARRAY]], i64 [[INDVAR_POSTLOOP]] 78; CHECK-NEXT: [[RES_POSTLOOP:%.*]] = load i32, i32* [[ADDR_POSTLOOP]] 79; CHECK-NEXT: [[CMP_POSTLOOP:%.*]] = icmp eq i32 [[RES_POSTLOOP]], 0 80; CHECK-NEXT: br i1 [[CMP_POSTLOOP]], label [[ZERO_LOOPEXIT_LOOPEXIT:%.*]], label [[LATCH_POSTLOOP]] 81; CHECK: latch.postloop: 82; CHECK-NEXT: [[INDVAR_NEXT_POSTLOOP]] = add nuw nsw i64 [[INDVAR_POSTLOOP]], 2 83; CHECK-NEXT: [[RES2_POSTLOOP]] = mul i32 [[RES_POSTLOOP]], 3 84; CHECK-NEXT: [[TMP13:%.*]] = zext i32 [[A]] to i64 85; CHECK-NEXT: [[CMP2_POSTLOOP:%.*]] = icmp ugt i64 [[INDVAR_NEXT_POSTLOOP]], [[TMP13]] 86; CHECK-NEXT: br i1 [[CMP2_POSTLOOP]], label [[LOOPEXIT_LOOPEXIT]], label [[LOOP_POSTLOOP]], !llvm.loop !0, !irce.loop.clone !5 87; 88preheader: 89 %tripcheck = icmp sgt i64 %Len, 2 90 br i1 %tripcheck, label %loop, label %zero 91 92loop: 93 %indvar = phi i64 [ 1, %preheader ], [ %indvar.next, %latch ] 94 %0 = icmp ult i64 %indvar, %Len 95 br i1 %0, label %guarded, label %deopt 96 97guarded: 98 %addr = getelementptr inbounds i32, i32* %array, i64 %indvar 99 %res = load i32, i32* %addr 100 %cmp = icmp eq i32 %res, 0 101 br i1 %cmp, label %zero, label %latch 102 103latch: 104 %indvar.next = add nuw nsw i64 %indvar, 2 105 %res2 = mul i32 %res, 3 106; NOTE: this is loop invariant value, but not loop invariant instruction! 107 %1 = zext i32 %A to i64 108 %cmp2 = icmp ugt i64 %indvar.next, %1 109 br i1 %cmp2, label %loopexit, label %loop 110 111loopexit: 112 ret i32 %res2 113 114zero: 115 ret i32 0 116 117deopt: 118 ret i32 1 119 120} 121