1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -passes=loop-idiom < %s -S | FileCheck %s 3target datalayout = "e-p:40:64:64:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" 4 5%struct.foo = type { i32, i32 } 6%struct.foo1 = type { i32, i32, i32 } 7%struct.foo2 = type { i32, i16, i16 } 8 9;void bar1(foo_t *f, unsigned n) { 10; for (unsigned i = 0; i < n; ++i) { 11; f[i].a = 0; 12; f[i].b = 0; 13; } 14;} 15define void @bar1(ptr %f, i32 %n) nounwind ssp { 16; CHECK-LABEL: @bar1( 17; CHECK-NEXT: entry: 18; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[N:%.*]], 0 19; CHECK-NEXT: br i1 [[CMP1]], label [[FOR_END:%.*]], label [[FOR_BODY_PREHEADER:%.*]] 20; CHECK: for.body.preheader: 21; CHECK-NEXT: [[TMP0:%.*]] = shl nuw i32 [[N]], 3 22; CHECK-NEXT: call void @llvm.memset.p0.i32(ptr align 4 [[F:%.*]], i8 0, i32 [[TMP0]], i1 false) 23; CHECK-NEXT: br label [[FOR_BODY:%.*]] 24; CHECK: for.body: 25; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i32 [ 0, [[FOR_BODY_PREHEADER]] ], [ [[INDVARS_IV_NEXT:%.*]], [[FOR_BODY]] ] 26; CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_FOO:%.*]], ptr [[F]], i32 [[INDVARS_IV]], i32 0 27; CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_FOO]], ptr [[F]], i32 [[INDVARS_IV]], i32 1 28; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i32 [[INDVARS_IV]], 1 29; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[INDVARS_IV_NEXT]], [[N]] 30; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]] 31; CHECK: for.end.loopexit: 32; CHECK-NEXT: br label [[FOR_END]] 33; CHECK: for.end: 34; CHECK-NEXT: ret void 35; 36entry: 37 %cmp1 = icmp eq i32 %n, 0 38 br i1 %cmp1, label %for.end, label %for.body.preheader 39 40for.body.preheader: ; preds = %entry 41 br label %for.body 42 43for.body: ; preds = %for.body.preheader, %for.body 44 %indvars.iv = phi i32 [ 0, %for.body.preheader ], [ %indvars.iv.next, %for.body ] 45 %a = getelementptr inbounds %struct.foo, ptr %f, i32 %indvars.iv, i32 0 46 store i32 0, ptr %a, align 4 47 %b = getelementptr inbounds %struct.foo, ptr %f, i32 %indvars.iv, i32 1 48 store i32 0, ptr %b, align 4 49 %indvars.iv.next = add nuw nsw i32 %indvars.iv, 1 50 %exitcond = icmp ne i32 %indvars.iv.next, %n 51 br i1 %exitcond, label %for.body, label %for.end.loopexit 52 53for.end.loopexit: ; preds = %for.body 54 br label %for.end 55 56for.end: ; preds = %for.end.loopexit, %entry 57 ret void 58} 59 60;void bar2(foo_t *f, unsigned n) { 61; for (unsigned i = 0; i < n; ++i) { 62; f[i].b = 0; 63; f[i].a = 0; 64; } 65;} 66define void @bar2(ptr %f, i32 %n) nounwind ssp { 67; CHECK-LABEL: @bar2( 68; CHECK-NEXT: entry: 69; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[N:%.*]], 0 70; CHECK-NEXT: br i1 [[CMP1]], label [[FOR_END:%.*]], label [[FOR_BODY_PREHEADER:%.*]] 71; CHECK: for.body.preheader: 72; CHECK-NEXT: [[TMP0:%.*]] = shl nuw i32 [[N]], 3 73; CHECK-NEXT: call void @llvm.memset.p0.i32(ptr align 4 [[F:%.*]], i8 0, i32 [[TMP0]], i1 false) 74; CHECK-NEXT: br label [[FOR_BODY:%.*]] 75; CHECK: for.body: 76; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i32 [ 0, [[FOR_BODY_PREHEADER]] ], [ [[INDVARS_IV_NEXT:%.*]], [[FOR_BODY]] ] 77; CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_FOO:%.*]], ptr [[F]], i32 [[INDVARS_IV]], i32 1 78; CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_FOO]], ptr [[F]], i32 [[INDVARS_IV]], i32 0 79; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i32 [[INDVARS_IV]], 1 80; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[INDVARS_IV_NEXT]], [[N]] 81; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]] 82; CHECK: for.end.loopexit: 83; CHECK-NEXT: br label [[FOR_END]] 84; CHECK: for.end: 85; CHECK-NEXT: ret void 86; 87entry: 88 %cmp1 = icmp eq i32 %n, 0 89 br i1 %cmp1, label %for.end, label %for.body.preheader 90 91for.body.preheader: ; preds = %entry 92 br label %for.body 93 94for.body: ; preds = %for.body.preheader, %for.body 95 %indvars.iv = phi i32 [ 0, %for.body.preheader ], [ %indvars.iv.next, %for.body ] 96 %b = getelementptr inbounds %struct.foo, ptr %f, i32 %indvars.iv, i32 1 97 store i32 0, ptr %b, align 4 98 %a = getelementptr inbounds %struct.foo, ptr %f, i32 %indvars.iv, i32 0 99 store i32 0, ptr %a, align 4 100 %indvars.iv.next = add nuw nsw i32 %indvars.iv, 1 101 %exitcond = icmp ne i32 %indvars.iv.next, %n 102 br i1 %exitcond, label %for.body, label %for.end.loopexit 103 104for.end.loopexit: ; preds = %for.body 105 br label %for.end 106 107for.end: ; preds = %for.end.loopexit, %entry 108 ret void 109} 110 111;void bar3(foo_t *f, unsigned n) { 112; for (unsigned i = n; i > 0; --i) { 113; f[i].a = 0; 114; f[i].b = 0; 115; } 116;} 117define void @bar3(ptr nocapture %f, i32 %n) nounwind ssp { 118; CHECK-LABEL: @bar3( 119; CHECK-NEXT: entry: 120; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[N:%.*]], 0 121; CHECK-NEXT: br i1 [[CMP1]], label [[FOR_END:%.*]], label [[FOR_BODY_PREHEADER:%.*]] 122; CHECK: for.body.preheader: 123; CHECK-NEXT: [[UGLYGEP:%.*]] = getelementptr i8, ptr [[F:%.*]], i32 8 124; CHECK-NEXT: [[TMP0:%.*]] = shl nuw i32 [[N]], 3 125; CHECK-NEXT: call void @llvm.memset.p0.i32(ptr align 4 [[UGLYGEP]], i8 0, i32 [[TMP0]], i1 false) 126; CHECK-NEXT: br label [[FOR_BODY:%.*]] 127; CHECK: for.body: 128; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i32 [ [[N]], [[FOR_BODY_PREHEADER]] ], [ [[INDVARS_IV_NEXT:%.*]], [[FOR_BODY]] ] 129; CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_FOO:%.*]], ptr [[F]], i32 [[INDVARS_IV]], i32 0 130; CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_FOO]], ptr [[F]], i32 [[INDVARS_IV]], i32 1 131; CHECK-NEXT: [[DEC:%.*]] = add i32 [[INDVARS_IV]], -1 132; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[DEC]], 0 133; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nsw i32 [[INDVARS_IV]], -1 134; CHECK-NEXT: br i1 [[CMP]], label [[FOR_END_LOOPEXIT:%.*]], label [[FOR_BODY]] 135; CHECK: for.end.loopexit: 136; CHECK-NEXT: br label [[FOR_END]] 137; CHECK: for.end: 138; CHECK-NEXT: ret void 139; 140entry: 141 %cmp1 = icmp eq i32 %n, 0 142 br i1 %cmp1, label %for.end, label %for.body.preheader 143 144for.body.preheader: ; preds = %entry 145 br label %for.body 146 147for.body: ; preds = %for.body.preheader, %for.body 148 %indvars.iv = phi i32 [ %n, %for.body.preheader ], [ %indvars.iv.next, %for.body ] 149 %a = getelementptr inbounds %struct.foo, ptr %f, i32 %indvars.iv, i32 0 150 store i32 0, ptr %a, align 4 151 %b = getelementptr inbounds %struct.foo, ptr %f, i32 %indvars.iv, i32 1 152 store i32 0, ptr %b, align 4 153 %dec = add i32 %indvars.iv, -1 154 %cmp = icmp eq i32 %dec, 0 155 %indvars.iv.next = add nsw i32 %indvars.iv, -1 156 br i1 %cmp, label %for.end.loopexit, label %for.body 157 158for.end.loopexit: ; preds = %for.body 159 br label %for.end 160 161for.end: ; preds = %for.end.loopexit, %entry 162 ret void 163} 164 165;void bar4(foo_t *f, unsigned n) { 166; for (unsigned i = 0; i < n; ++i) { 167; f[i].a = 0; 168; f[i].b = 1; 169; } 170;} 171define void @bar4(ptr nocapture %f, i32 %n) nounwind ssp { 172; CHECK-LABEL: @bar4( 173; CHECK-NEXT: entry: 174; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[N:%.*]], 0 175; CHECK-NEXT: br i1 [[CMP1]], label [[FOR_END:%.*]], label [[FOR_BODY_PREHEADER:%.*]] 176; CHECK: for.body.preheader: 177; CHECK-NEXT: br label [[FOR_BODY:%.*]] 178; CHECK: for.body: 179; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i32 [ 0, [[FOR_BODY_PREHEADER]] ], [ [[INDVARS_IV_NEXT:%.*]], [[FOR_BODY]] ] 180; CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_FOO:%.*]], ptr [[F:%.*]], i32 [[INDVARS_IV]], i32 0 181; CHECK-NEXT: store i32 0, ptr [[A]], align 4 182; CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_FOO]], ptr [[F]], i32 [[INDVARS_IV]], i32 1 183; CHECK-NEXT: store i32 1, ptr [[B]], align 4 184; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i32 [[INDVARS_IV]], 1 185; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[INDVARS_IV_NEXT]], [[N]] 186; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]] 187; CHECK: for.end.loopexit: 188; CHECK-NEXT: br label [[FOR_END]] 189; CHECK: for.end: 190; CHECK-NEXT: ret void 191; 192entry: 193 %cmp1 = icmp eq i32 %n, 0 194 br i1 %cmp1, label %for.end, label %for.body.preheader 195 196for.body.preheader: ; preds = %entry 197 br label %for.body 198 199for.body: ; preds = %for.body.preheader, %for.body 200 %indvars.iv = phi i32 [ 0, %for.body.preheader ], [ %indvars.iv.next, %for.body ] 201 %a = getelementptr inbounds %struct.foo, ptr %f, i32 %indvars.iv, i32 0 202 store i32 0, ptr %a, align 4 203 %b = getelementptr inbounds %struct.foo, ptr %f, i32 %indvars.iv, i32 1 204 store i32 1, ptr %b, align 4 205 %indvars.iv.next = add nuw nsw i32 %indvars.iv, 1 206 %exitcond = icmp ne i32 %indvars.iv.next, %n 207 br i1 %exitcond, label %for.body, label %for.end.loopexit 208 209for.end.loopexit: ; preds = %for.body 210 br label %for.end 211 212for.end: ; preds = %for.end.loopexit, %entry 213 ret void 214} 215 216;void bar5(foo1_t *f, unsigned n) { 217; for (unsigned i = 0; i < n; ++i) { 218; f[i].a = 0; 219; f[i].b = 0; 220; } 221;} 222define void @bar5(ptr nocapture %f, i32 %n) nounwind ssp { 223; CHECK-LABEL: @bar5( 224; CHECK-NEXT: entry: 225; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[N:%.*]], 0 226; CHECK-NEXT: br i1 [[CMP1]], label [[FOR_END:%.*]], label [[FOR_BODY_PREHEADER:%.*]] 227; CHECK: for.body.preheader: 228; CHECK-NEXT: br label [[FOR_BODY:%.*]] 229; CHECK: for.body: 230; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i32 [ 0, [[FOR_BODY_PREHEADER]] ], [ [[INDVARS_IV_NEXT:%.*]], [[FOR_BODY]] ] 231; CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_FOO1:%.*]], ptr [[F:%.*]], i32 [[INDVARS_IV]], i32 0 232; CHECK-NEXT: store i32 0, ptr [[A]], align 4 233; CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_FOO1]], ptr [[F]], i32 [[INDVARS_IV]], i32 1 234; CHECK-NEXT: store i32 0, ptr [[B]], align 4 235; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i32 [[INDVARS_IV]], 1 236; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[INDVARS_IV_NEXT]], [[N]] 237; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]] 238; CHECK: for.end.loopexit: 239; CHECK-NEXT: br label [[FOR_END]] 240; CHECK: for.end: 241; CHECK-NEXT: ret void 242; 243entry: 244 %cmp1 = icmp eq i32 %n, 0 245 br i1 %cmp1, label %for.end, label %for.body.preheader 246 247for.body.preheader: ; preds = %entry 248 br label %for.body 249 250for.body: ; preds = %for.body.preheader, %for.body 251 %indvars.iv = phi i32 [ 0, %for.body.preheader ], [ %indvars.iv.next, %for.body ] 252 %a = getelementptr inbounds %struct.foo1, ptr %f, i32 %indvars.iv, i32 0 253 store i32 0, ptr %a, align 4 254 %b = getelementptr inbounds %struct.foo1, ptr %f, i32 %indvars.iv, i32 1 255 store i32 0, ptr %b, align 4 256 %indvars.iv.next = add nuw nsw i32 %indvars.iv, 1 257 %exitcond = icmp ne i32 %indvars.iv.next, %n 258 br i1 %exitcond, label %for.body, label %for.end.loopexit 259 260for.end.loopexit: ; preds = %for.body 261 br label %for.end 262 263for.end: ; preds = %for.end.loopexit, %entry 264 ret void 265} 266 267;void bar6(foo2_t *f, unsigned n) { 268; for (unsigned i = 0; i < n; ++i) { 269; f[i].a = 0; 270; f[i].b = 0; 271; f[i].c = 0; 272; } 273;} 274define void @bar6(ptr nocapture %f, i32 %n) nounwind ssp { 275; CHECK-LABEL: @bar6( 276; CHECK-NEXT: entry: 277; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[N:%.*]], 0 278; CHECK-NEXT: br i1 [[CMP1]], label [[FOR_END:%.*]], label [[FOR_BODY_PREHEADER:%.*]] 279; CHECK: for.body.preheader: 280; CHECK-NEXT: [[TMP0:%.*]] = shl nuw i32 [[N]], 3 281; CHECK-NEXT: call void @llvm.memset.p0.i32(ptr align 4 [[F:%.*]], i8 0, i32 [[TMP0]], i1 false) 282; CHECK-NEXT: br label [[FOR_BODY:%.*]] 283; CHECK: for.body: 284; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i32 [ 0, [[FOR_BODY_PREHEADER]] ], [ [[INDVARS_IV_NEXT:%.*]], [[FOR_BODY]] ] 285; CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_FOO2:%.*]], ptr [[F]], i32 [[INDVARS_IV]], i32 0 286; CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_FOO2]], ptr [[F]], i32 [[INDVARS_IV]], i32 1 287; CHECK-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_FOO2]], ptr [[F]], i32 [[INDVARS_IV]], i32 2 288; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i32 [[INDVARS_IV]], 1 289; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[INDVARS_IV_NEXT]], [[N]] 290; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]] 291; CHECK: for.end.loopexit: 292; CHECK-NEXT: br label [[FOR_END]] 293; CHECK: for.end: 294; CHECK-NEXT: ret void 295; 296entry: 297 %cmp1 = icmp eq i32 %n, 0 298 br i1 %cmp1, label %for.end, label %for.body.preheader 299 300for.body.preheader: ; preds = %entry 301 br label %for.body 302 303for.body: ; preds = %for.body.preheader, %for.body 304 %indvars.iv = phi i32 [ 0, %for.body.preheader ], [ %indvars.iv.next, %for.body ] 305 %a = getelementptr inbounds %struct.foo2, ptr %f, i32 %indvars.iv, i32 0 306 store i32 0, ptr %a, align 4 307 %b = getelementptr inbounds %struct.foo2, ptr %f, i32 %indvars.iv, i32 1 308 store i16 0, ptr %b, align 4 309 %c = getelementptr inbounds %struct.foo2, ptr %f, i32 %indvars.iv, i32 2 310 store i16 0, ptr %c, align 2 311 %indvars.iv.next = add nuw nsw i32 %indvars.iv, 1 312 %exitcond = icmp ne i32 %indvars.iv.next, %n 313 br i1 %exitcond, label %for.body, label %for.end.loopexit 314 315for.end.loopexit: ; preds = %for.body 316 br label %for.end 317 318for.end: ; preds = %for.end.loopexit, %entry 319 ret void 320} 321