1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -S -passes=loop-rotate < %s -verify-loop-info -verify-dom-info -verify-memoryssa | FileCheck %s 3 4target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" 5target triple = "thumbv8m.base-arm-none-eabi" 6 7%struct.List = type { ptr, i32 } 8 9define void @list_add(ptr nocapture %list, ptr %data) { 10; CHECK-LABEL: @list_add( 11; CHECK-NEXT: entry: 12; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[LIST:%.*]], align 4 13; CHECK-NEXT: [[VAL2:%.*]] = getelementptr inbounds [[STRUCT_LIST:%.*]], ptr [[TMP0]], i32 0, i32 1 14; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[VAL2]], align 4 15; CHECK-NEXT: [[VAL1:%.*]] = getelementptr inbounds [[STRUCT_LIST]], ptr [[DATA:%.*]], i32 0, i32 1 16; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[VAL1]], align 4 17; CHECK-NEXT: [[CMP3:%.*]] = icmp slt i32 [[TMP1]], [[TMP2]] 18; CHECK-NEXT: br i1 [[CMP3]], label [[IF_THEN_LR_PH:%.*]], label [[IF_ELSE6:%.*]] 19; CHECK: if.then.lr.ph: 20; CHECK-NEXT: br label [[IF_THEN:%.*]] 21; CHECK: for.cond: 22; CHECK-NEXT: [[CURR_0:%.*]] = phi ptr [ [[TMP5:%.*]], [[IF_THEN]] ] 23; CHECK-NEXT: [[PREV_0:%.*]] = phi ptr [ [[CURR_04:%.*]], [[IF_THEN]] ] 24; CHECK-NEXT: [[VAL:%.*]] = getelementptr inbounds [[STRUCT_LIST]], ptr [[CURR_0]], i32 0, i32 1 25; CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[VAL]], align 4 26; CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[VAL1]], align 4 27; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[TMP3]], [[TMP4]] 28; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN]], label [[FOR_COND_IF_ELSE6_CRIT_EDGE:%.*]] 29; CHECK: if.then: 30; CHECK-NEXT: [[CURR_04]] = phi ptr [ [[TMP0]], [[IF_THEN_LR_PH]] ], [ [[CURR_0]], [[FOR_COND:%.*]] ] 31; CHECK-NEXT: [[TMP5]] = load ptr, ptr [[CURR_04]], align 4 32; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq ptr [[TMP5]], null 33; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_ELSE:%.*]], label [[FOR_COND]] 34; CHECK: if.else: 35; CHECK-NEXT: [[NEXT_LCSSA:%.*]] = phi ptr [ [[CURR_04]], [[IF_THEN]] ] 36; CHECK-NEXT: store ptr [[DATA]], ptr [[NEXT_LCSSA]], align 4 37; CHECK-NEXT: store ptr null, ptr [[DATA]], align 4 38; CHECK-NEXT: br label [[FOR_END:%.*]] 39; CHECK: for.cond.if.else6_crit_edge: 40; CHECK-NEXT: [[SPLIT:%.*]] = phi ptr [ [[PREV_0]], [[FOR_COND]] ] 41; CHECK-NEXT: br label [[IF_ELSE6]] 42; CHECK: if.else6: 43; CHECK-NEXT: [[PREV_0_LCSSA:%.*]] = phi ptr [ [[SPLIT]], [[FOR_COND_IF_ELSE6_CRIT_EDGE]] ], [ null, [[ENTRY:%.*]] ] 44; CHECK-NEXT: [[TOBOOL7:%.*]] = icmp eq ptr [[PREV_0_LCSSA]], null 45; CHECK-NEXT: br i1 [[TOBOOL7]], label [[IF_ELSE12:%.*]], label [[IF_THEN8:%.*]] 46; CHECK: if.then8: 47; CHECK-NEXT: [[TMP7:%.*]] = load i32, ptr [[PREV_0_LCSSA]], align 4 48; CHECK-NEXT: store i32 [[TMP7]], ptr [[DATA]], align 4 49; CHECK-NEXT: store ptr [[DATA]], ptr [[PREV_0_LCSSA]], align 4 50; CHECK-NEXT: br label [[FOR_END]] 51; CHECK: if.else12: 52; CHECK-NEXT: [[TMP10:%.*]] = load i32, ptr [[LIST]], align 4 53; CHECK-NEXT: store i32 [[TMP10]], ptr [[DATA]], align 4 54; CHECK-NEXT: store ptr [[DATA]], ptr [[LIST]], align 4 55; CHECK-NEXT: br label [[FOR_END]] 56; CHECK: for.end: 57; CHECK-NEXT: ret void 58; 59entry: 60 %0 = load ptr, ptr %list, align 4 61 br label %for.cond 62 63for.cond: ; preds = %if.then, %entry 64 %curr.0 = phi ptr [ %0, %entry ], [ %3, %if.then ] 65 %prev.0 = phi ptr [ null, %entry ], [ %curr.0, %if.then ] 66 %val = getelementptr inbounds %struct.List, ptr %curr.0, i32 0, i32 1 67 %1 = load i32, ptr %val, align 4 68 %val1 = getelementptr inbounds %struct.List, ptr %data, i32 0, i32 1 69 %2 = load i32, ptr %val1, align 4 70 %cmp = icmp slt i32 %1, %2 71 br i1 %cmp, label %if.then, label %if.else6 72 73if.then: ; preds = %for.cond 74 %3 = load ptr, ptr %curr.0, align 4 75 %tobool = icmp eq ptr %3, null 76 br i1 %tobool, label %if.else, label %for.cond 77 78if.else: ; preds = %if.then 79 %next.lcssa = phi ptr [ %curr.0, %if.then ] 80 store ptr %data, ptr %next.lcssa, align 4 81 store ptr null, ptr %data, align 4 82 br label %for.end 83 84if.else6: ; preds = %for.cond 85 %prev.0.lcssa = phi ptr [ %prev.0, %for.cond ] 86 %tobool7 = icmp eq ptr %prev.0.lcssa, null 87 br i1 %tobool7, label %if.else12, label %if.then8 88 89if.then8: ; preds = %if.else6 90 %4 = load i32, ptr %prev.0.lcssa, align 4 91 store i32 %4, ptr %data, align 4 92 store ptr %data, ptr %prev.0.lcssa, align 4 93 br label %for.end 94 95if.else12: ; preds = %if.else6 96 %5 = load i32, ptr %list, align 4 97 store i32 %5, ptr %data, align 4 98 store ptr %data, ptr %list, align 4 99 br label %for.end 100 101for.end: ; preds = %if.else12, %if.then8, %if.else 102 ret void 103} 104 105define i32 @test2(ptr %l) { 106; CHECK-LABEL: @test2( 107; CHECK-NEXT: entry: 108; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[L:%.*]], align 4 109; CHECK-NEXT: [[TOBOOL2:%.*]] = icmp eq i32 [[TMP0]], 0 110; CHECK-NEXT: br i1 [[TOBOOL2]], label [[CLEANUP:%.*]], label [[DO_COND_LR_PH:%.*]] 111; CHECK: do.cond.lr.ph: 112; CHECK-NEXT: br label [[DO_COND:%.*]] 113; CHECK: do.body: 114; CHECK-NEXT: [[A_0:%.*]] = phi i32 [ [[REM:%.*]], [[DO_COND]] ] 115; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[L]], align 4 116; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[TMP1]], 0 117; CHECK-NEXT: br i1 [[TOBOOL]], label [[DO_BODY_CLEANUP_CRIT_EDGE:%.*]], label [[DO_COND]] 118; CHECK: do.body.cleanup_crit_edge: 119; CHECK-NEXT: [[SPLIT:%.*]] = phi i32 [ [[A_0]], [[DO_BODY:%.*]] ] 120; CHECK-NEXT: br label [[CLEANUP]] 121; CHECK: cleanup: 122; CHECK-NEXT: [[A_0_LCSSA:%.*]] = phi i32 [ [[SPLIT]], [[DO_BODY_CLEANUP_CRIT_EDGE]] ], [ 100, [[ENTRY:%.*]] ] 123; CHECK-NEXT: store i32 10, ptr [[L]], align 4 124; CHECK-NEXT: br label [[CLEANUP2:%.*]] 125; CHECK: do.cond: 126; CHECK-NEXT: [[TMP2:%.*]] = phi i32 [ [[TMP0]], [[DO_COND_LR_PH]] ], [ [[TMP1]], [[DO_BODY]] ] 127; CHECK-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP2]], 13 128; CHECK-NEXT: [[REM]] = srem i32 [[MUL]], 27 129; CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[L]], align 4 130; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[TMP3]], 0 131; CHECK-NEXT: br i1 [[TOBOOL1]], label [[CLEANUP2_LOOPEXIT:%.*]], label [[DO_BODY]] 132; CHECK: cleanup2.loopexit: 133; CHECK-NEXT: br label [[CLEANUP2]] 134; CHECK: cleanup2: 135; CHECK-NEXT: [[RETVAL_2:%.*]] = phi i32 [ [[A_0_LCSSA]], [[CLEANUP]] ], [ 0, [[CLEANUP2_LOOPEXIT]] ] 136; CHECK-NEXT: ret i32 [[RETVAL_2]] 137; 138entry: 139 br label %do.body 140 141do.body: ; preds = %do.cond, %entry 142 %a.0 = phi i32 [ 100, %entry ], [ %rem, %do.cond ] 143 %0 = load i32, ptr %l, align 4 144 %tobool = icmp eq i32 %0, 0 145 br i1 %tobool, label %cleanup, label %do.cond 146 147cleanup: ; preds = %do.body 148 %a.0.lcssa = phi i32 [ %a.0, %do.body ] 149 store i32 10, ptr %l, align 4 150 br label %cleanup2 151 152do.cond: ; preds = %do.body 153 %mul = mul nsw i32 %0, 13 154 %rem = srem i32 %mul, 27 155 %1 = load i32, ptr %l, align 4 156 %tobool1 = icmp eq i32 %1, 0 157 br i1 %tobool1, label %cleanup2.loopexit, label %do.body 158 159cleanup2.loopexit: ; preds = %do.cond 160 br label %cleanup2 161 162cleanup2: ; preds = %cleanup2.loopexit, %cleanup 163 %retval.2 = phi i32 [ %a.0.lcssa, %cleanup ], [ 0, %cleanup2.loopexit ] 164 ret i32 %retval.2 165} 166 167define i32 @no_rotate(ptr %l) { 168; CHECK-LABEL: @no_rotate( 169; CHECK-NEXT: entry: 170; CHECK-NEXT: br label [[DO_BODY:%.*]] 171; CHECK: do.body: 172; CHECK-NEXT: [[A_0:%.*]] = phi i32 [ 100, [[ENTRY:%.*]] ], [ [[REM:%.*]], [[DO_COND:%.*]] ] 173; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[L:%.*]], align 4 174; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[TMP0]], 0 175; CHECK-NEXT: br i1 [[TOBOOL]], label [[CLEANUP:%.*]], label [[DO_COND]] 176; CHECK: cleanup: 177; CHECK-NEXT: [[A_0_LCSSA:%.*]] = phi i32 [ [[A_0]], [[DO_BODY]] ] 178; CHECK-NEXT: store i32 10, ptr [[L]], align 4 179; CHECK-NEXT: br label [[CLEANUP2:%.*]] 180; CHECK: do.cond: 181; CHECK-NEXT: [[MUL:%.*]] = mul nsw i32 [[A_0]], 13 182; CHECK-NEXT: [[REM]] = srem i32 [[MUL]], 27 183; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[L]], align 4 184; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[TMP1]], 0 185; CHECK-NEXT: br i1 [[TOBOOL1]], label [[CLEANUP2_LOOPEXIT:%.*]], label [[DO_BODY]] 186; CHECK: cleanup2.loopexit: 187; CHECK-NEXT: br label [[CLEANUP2]] 188; CHECK: cleanup2: 189; CHECK-NEXT: [[RETVAL_2:%.*]] = phi i32 [ [[A_0_LCSSA]], [[CLEANUP]] ], [ 0, [[CLEANUP2_LOOPEXIT]] ] 190; CHECK-NEXT: ret i32 [[RETVAL_2]] 191; 192entry: 193 br label %do.body 194 195do.body: ; preds = %do.cond, %entry 196 %a.0 = phi i32 [ 100, %entry ], [ %rem, %do.cond ] 197 %0 = load i32, ptr %l, align 4 198 %tobool = icmp eq i32 %0, 0 199 br i1 %tobool, label %cleanup, label %do.cond 200 201cleanup: ; preds = %do.body 202 %a.0.lcssa = phi i32 [ %a.0, %do.body ] 203 store i32 10, ptr %l, align 4 204 br label %cleanup2 205 206do.cond: ; preds = %do.body 207 %mul = mul nsw i32 %a.0, 13 208 %rem = srem i32 %mul, 27 209 %1 = load i32, ptr %l, align 4 210 %tobool1 = icmp eq i32 %1, 0 211 br i1 %tobool1, label %cleanup2.loopexit, label %do.body 212 213cleanup2.loopexit: ; preds = %do.cond 214 br label %cleanup2 215 216cleanup2: ; preds = %cleanup2.loopexit, %cleanup 217 %retval.2 = phi i32 [ %a.0.lcssa, %cleanup ], [ 0, %cleanup2.loopexit ] 218 ret i32 %retval.2 219} 220 221