1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -S -passes=loop-unroll < %s | FileCheck %s 3; RUN: opt -S -passes='require<opt-remark-emit>,loop(loop-unroll-full)' < %s | FileCheck %s 4 5; Unroll twice, with first loop exit kept 6define void @s32_max1(i32 %n, ptr %p) { 7; 8; CHECK-LABEL: @s32_max1( 9; CHECK-NEXT: entry: 10; CHECK-NEXT: [[ADD:%.*]] = add i32 [[N:%.*]], 1 11; CHECK-NEXT: br label [[DO_BODY:%.*]] 12; CHECK: do.body: 13; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[N]] 14; CHECK-NEXT: store i32 [[N]], ptr [[ARRAYIDX]], align 4 15; CHECK-NEXT: [[INC:%.*]] = add i32 [[N]], 1 16; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[N]], [[ADD]] 17; CHECK-NEXT: br i1 [[CMP]], label [[DO_BODY_1:%.*]], label [[DO_END:%.*]] 18; CHECK: do.body.1: 19; CHECK-NEXT: [[ARRAYIDX_1:%.*]] = getelementptr i32, ptr [[P]], i32 [[INC]] 20; CHECK-NEXT: store i32 [[INC]], ptr [[ARRAYIDX_1]], align 4 21; CHECK-NEXT: br label [[DO_END]] 22; CHECK: do.end: 23; CHECK-NEXT: ret void 24; 25entry: 26 %add = add i32 %n, 1 27 br label %do.body 28 29do.body: 30 %i.0 = phi i32 [ %n, %entry ], [ %inc, %do.body ] 31 %arrayidx = getelementptr i32, ptr %p, i32 %i.0 32 store i32 %i.0, ptr %arrayidx, align 4 33 %inc = add i32 %i.0, 1 34 %cmp = icmp slt i32 %i.0, %add 35 br i1 %cmp, label %do.body, label %do.end ; taken either 0 or 1 times 36 37do.end: 38 ret void 39} 40 41; Unroll thrice, with first loop exit kept 42define void @s32_max2(i32 %n, ptr %p) { 43; 44; CHECK-LABEL: @s32_max2( 45; CHECK-NEXT: entry: 46; CHECK-NEXT: [[ADD:%.*]] = add i32 [[N:%.*]], 2 47; CHECK-NEXT: br label [[DO_BODY:%.*]] 48; CHECK: do.body: 49; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[N]] 50; CHECK-NEXT: store i32 [[N]], ptr [[ARRAYIDX]], align 4 51; CHECK-NEXT: [[INC:%.*]] = add i32 [[N]], 1 52; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[N]], [[ADD]] 53; CHECK-NEXT: br i1 [[CMP]], label [[DO_BODY_1:%.*]], label [[DO_END:%.*]] 54; CHECK: do.body.1: 55; CHECK-NEXT: [[ARRAYIDX_1:%.*]] = getelementptr i32, ptr [[P]], i32 [[INC]] 56; CHECK-NEXT: store i32 [[INC]], ptr [[ARRAYIDX_1]], align 4 57; CHECK-NEXT: [[INC_1:%.*]] = add i32 [[N]], 2 58; CHECK-NEXT: [[ARRAYIDX_2:%.*]] = getelementptr i32, ptr [[P]], i32 [[INC_1]] 59; CHECK-NEXT: store i32 [[INC_1]], ptr [[ARRAYIDX_2]], align 4 60; CHECK-NEXT: br label [[DO_END]] 61; CHECK: do.end: 62; CHECK-NEXT: ret void 63; 64entry: 65 %add = add i32 %n, 2 66 br label %do.body 67 68do.body: 69 %i.0 = phi i32 [ %n, %entry ], [ %inc, %do.body ] 70 %arrayidx = getelementptr i32, ptr %p, i32 %i.0 71 store i32 %i.0, ptr %arrayidx, align 4 72 %inc = add i32 %i.0, 1 73 %cmp = icmp slt i32 %i.0, %add 74 br i1 %cmp, label %do.body, label %do.end ; taken either 0 or 2 times 75 76do.end: 77 ret void 78} 79 80; Should not be unrolled 81define void @s32_maxx(i32 %n, i32 %x, ptr %p) { 82; 83; CHECK-LABEL: @s32_maxx( 84; CHECK-NEXT: entry: 85; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X:%.*]], [[N:%.*]] 86; CHECK-NEXT: br label [[DO_BODY:%.*]] 87; CHECK: do.body: 88; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ [[N]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[DO_BODY]] ] 89; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[I_0]] 90; CHECK-NEXT: store i32 [[I_0]], ptr [[ARRAYIDX]], align 4 91; CHECK-NEXT: [[INC]] = add i32 [[I_0]], 1 92; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], [[ADD]] 93; CHECK-NEXT: br i1 [[CMP]], label [[DO_BODY]], label [[DO_END:%.*]] 94; CHECK: do.end: 95; CHECK-NEXT: ret void 96; 97entry: 98 %add = add i32 %x, %n 99 br label %do.body 100 101do.body: 102 %i.0 = phi i32 [ %n, %entry ], [ %inc, %do.body ] 103 %arrayidx = getelementptr i32, ptr %p, i32 %i.0 104 store i32 %i.0, ptr %arrayidx, align 4 105 %inc = add i32 %i.0, 1 106 %cmp = icmp slt i32 %i.0, %add 107 br i1 %cmp, label %do.body, label %do.end ; taken either 0 or x times 108 109do.end: 110 ret void 111} 112 113; Should not be unrolled 114define void @s32_max2_unpredictable_exit(i32 %n, i32 %x, ptr %p) { 115; 116; CHECK-LABEL: @s32_max2_unpredictable_exit( 117; CHECK-NEXT: entry: 118; CHECK-NEXT: [[ADD:%.*]] = add i32 [[N:%.*]], 2 119; CHECK-NEXT: br label [[DO_BODY:%.*]] 120; CHECK: do.body: 121; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ [[N]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[IF_END:%.*]] ] 122; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I_0]], [[X:%.*]] 123; CHECK-NEXT: br i1 [[CMP]], label [[DO_END:%.*]], label [[IF_END]] 124; CHECK: if.end: 125; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[I_0]] 126; CHECK-NEXT: store i32 [[I_0]], ptr [[ARRAYIDX]], align 4 127; CHECK-NEXT: [[INC]] = add i32 [[I_0]], 1 128; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[I_0]], [[ADD]] 129; CHECK-NEXT: br i1 [[CMP1]], label [[DO_BODY]], label [[DO_END]] 130; CHECK: do.end: 131; CHECK-NEXT: ret void 132; 133entry: 134 %add = add i32 %n, 2 135 br label %do.body 136 137do.body: 138 %i.0 = phi i32 [ %n, %entry ], [ %inc, %if.end ] 139 %cmp = icmp eq i32 %i.0, %x 140 br i1 %cmp, label %do.end, label %if.end ; unpredictable 141 142if.end: 143 %arrayidx = getelementptr i32, ptr %p, i32 %i.0 144 store i32 %i.0, ptr %arrayidx, align 4 145 %inc = add i32 %i.0, 1 146 %cmp1 = icmp slt i32 %i.0, %add 147 br i1 %cmp1, label %do.body, label %do.end ; taken either 0 or 2 times 148 149do.end: 150 ret void 151} 152 153; Unroll twice, with first loop exit kept 154define void @u32_max1(i32 %n, ptr %p) { 155; 156; CHECK-LABEL: @u32_max1( 157; CHECK-NEXT: entry: 158; CHECK-NEXT: [[ADD:%.*]] = add i32 [[N:%.*]], 1 159; CHECK-NEXT: br label [[DO_BODY:%.*]] 160; CHECK: do.body: 161; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[N]] 162; CHECK-NEXT: store i32 [[N]], ptr [[ARRAYIDX]], align 4 163; CHECK-NEXT: [[INC:%.*]] = add i32 [[N]], 1 164; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[N]], [[ADD]] 165; CHECK-NEXT: br i1 [[CMP]], label [[DO_BODY_1:%.*]], label [[DO_END:%.*]] 166; CHECK: do.body.1: 167; CHECK-NEXT: [[ARRAYIDX_1:%.*]] = getelementptr i32, ptr [[P]], i32 [[INC]] 168; CHECK-NEXT: store i32 [[INC]], ptr [[ARRAYIDX_1]], align 4 169; CHECK-NEXT: br label [[DO_END]] 170; CHECK: do.end: 171; CHECK-NEXT: ret void 172; 173entry: 174 %add = add i32 %n, 1 175 br label %do.body 176 177do.body: 178 %i.0 = phi i32 [ %n, %entry ], [ %inc, %do.body ] 179 %arrayidx = getelementptr i32, ptr %p, i32 %i.0 180 store i32 %i.0, ptr %arrayidx, align 4 181 %inc = add i32 %i.0, 1 182 %cmp = icmp ult i32 %i.0, %add 183 br i1 %cmp, label %do.body, label %do.end ; taken either 0 or 1 times 184 185do.end: 186 ret void 187} 188 189; Unroll thrice, with first loop exit kept 190define void @u32_max2(i32 %n, ptr %p) { 191; 192; CHECK-LABEL: @u32_max2( 193; CHECK-NEXT: entry: 194; CHECK-NEXT: [[ADD:%.*]] = add i32 [[N:%.*]], 2 195; CHECK-NEXT: br label [[DO_BODY:%.*]] 196; CHECK: do.body: 197; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[N]] 198; CHECK-NEXT: store i32 [[N]], ptr [[ARRAYIDX]], align 4 199; CHECK-NEXT: [[INC:%.*]] = add i32 [[N]], 1 200; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[N]], [[ADD]] 201; CHECK-NEXT: br i1 [[CMP]], label [[DO_BODY_1:%.*]], label [[DO_END:%.*]] 202; CHECK: do.body.1: 203; CHECK-NEXT: [[ARRAYIDX_1:%.*]] = getelementptr i32, ptr [[P]], i32 [[INC]] 204; CHECK-NEXT: store i32 [[INC]], ptr [[ARRAYIDX_1]], align 4 205; CHECK-NEXT: [[INC_1:%.*]] = add i32 [[N]], 2 206; CHECK-NEXT: [[ARRAYIDX_2:%.*]] = getelementptr i32, ptr [[P]], i32 [[INC_1]] 207; CHECK-NEXT: store i32 [[INC_1]], ptr [[ARRAYIDX_2]], align 4 208; CHECK-NEXT: br label [[DO_END]] 209; CHECK: do.end: 210; CHECK-NEXT: ret void 211; 212entry: 213 %add = add i32 %n, 2 214 br label %do.body 215 216do.body: 217 %i.0 = phi i32 [ %n, %entry ], [ %inc, %do.body ] 218 %arrayidx = getelementptr i32, ptr %p, i32 %i.0 219 store i32 %i.0, ptr %arrayidx, align 4 220 %inc = add i32 %i.0, 1 221 %cmp = icmp ult i32 %i.0, %add 222 br i1 %cmp, label %do.body, label %do.end ; taken either 0 or 2 times 223 224do.end: 225 ret void 226} 227 228; Should not be unrolled 229define void @u32_maxx(i32 %n, i32 %x, ptr %p) { 230; 231; CHECK-LABEL: @u32_maxx( 232; CHECK-NEXT: entry: 233; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X:%.*]], [[N:%.*]] 234; CHECK-NEXT: br label [[DO_BODY:%.*]] 235; CHECK: do.body: 236; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ [[N]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[DO_BODY]] ] 237; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[I_0]] 238; CHECK-NEXT: store i32 [[I_0]], ptr [[ARRAYIDX]], align 4 239; CHECK-NEXT: [[INC]] = add i32 [[I_0]], 1 240; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[I_0]], [[ADD]] 241; CHECK-NEXT: br i1 [[CMP]], label [[DO_BODY]], label [[DO_END:%.*]] 242; CHECK: do.end: 243; CHECK-NEXT: ret void 244; 245entry: 246 %add = add i32 %x, %n 247 br label %do.body 248 249do.body: 250 %i.0 = phi i32 [ %n, %entry ], [ %inc, %do.body ] 251 %arrayidx = getelementptr i32, ptr %p, i32 %i.0 252 store i32 %i.0, ptr %arrayidx, align 4 253 %inc = add i32 %i.0, 1 254 %cmp = icmp ult i32 %i.0, %add 255 br i1 %cmp, label %do.body, label %do.end ; taken either 0 or x times 256 257do.end: 258 ret void 259} 260 261; Should not be unrolled 262define void @u32_max2_unpredictable_exit(i32 %n, i32 %x, ptr %p) { 263; 264; CHECK-LABEL: @u32_max2_unpredictable_exit( 265; CHECK-NEXT: entry: 266; CHECK-NEXT: [[ADD:%.*]] = add i32 [[N:%.*]], 2 267; CHECK-NEXT: br label [[DO_BODY:%.*]] 268; CHECK: do.body: 269; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ [[N]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[IF_END:%.*]] ] 270; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I_0]], [[X:%.*]] 271; CHECK-NEXT: br i1 [[CMP]], label [[DO_END:%.*]], label [[IF_END]] 272; CHECK: if.end: 273; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[I_0]] 274; CHECK-NEXT: store i32 [[I_0]], ptr [[ARRAYIDX]], align 4 275; CHECK-NEXT: [[INC]] = add i32 [[I_0]], 1 276; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[I_0]], [[ADD]] 277; CHECK-NEXT: br i1 [[CMP1]], label [[DO_BODY]], label [[DO_END]] 278; CHECK: do.end: 279; CHECK-NEXT: ret void 280; 281entry: 282 %add = add i32 %n, 2 283 br label %do.body 284 285do.body: 286 %i.0 = phi i32 [ %n, %entry ], [ %inc, %if.end ] 287 %cmp = icmp eq i32 %i.0, %x 288 br i1 %cmp, label %do.end, label %if.end ; unpredictable 289 290if.end: 291 %arrayidx = getelementptr i32, ptr %p, i32 %i.0 292 store i32 %i.0, ptr %arrayidx, align 4 293 %inc = add i32 %i.0, 1 294 %cmp1 = icmp ult i32 %i.0, %add 295 br i1 %cmp1, label %do.body, label %do.end ; taken either 0 or 2 times 296 297do.end: 298 ret void 299} 300