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