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