1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -aa-pipeline=basic-aa,globals-aa -S -passes='require<globals-aa>,function(loop-mssa(licm))' | FileCheck %s 3 4;Reference C code: 5;struct str { 6; void **p; 7;}; 8;static struct str obj; 9;extern void nocapture_nocallback_func(struct str *); 10;void test(void *p) { 11; nocapture_nocallback_func(&obj); 12; for (int i = 0; i < 1000; ++i) { 13; unknown_call(); // optional 14; obj.p[i] = p; 15; } 16;} 17 18target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" 19 20%struct.str = type { ptr } 21 22@obj0 = internal global %struct.str zeroinitializer, align 8 23@obj1 = internal global %struct.str zeroinitializer, align 8 24@obj2 = internal global %struct.str zeroinitializer, align 8 25@obj3 = internal global %struct.str zeroinitializer, align 8 26@obj4 = internal global %struct.str zeroinitializer, align 8 27@obj5 = internal global %struct.str zeroinitializer, align 8 28 29define dso_local void @test0(ptr %p) { 30; Check that load from @obj0 is hoisted from the loop, meaning 31; that it does not conflict with the store inside the loop: 32; CHECK-LABEL: @test0( 33; CHECK-NEXT: entry: 34; CHECK-NEXT: call void @nocapture_nocallback_func(ptr @obj0) 35; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @obj0, align 8 36; CHECK-NEXT: br label [[FOR_COND:%.*]] 37; CHECK: for.cond: 38; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ] 39; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], 1000 40; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]] 41; CHECK: for.body: 42; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I_0]] to i64 43; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP0]], i64 [[IDXPROM]] 44; CHECK-NEXT: store ptr [[P:%.*]], ptr [[ARRAYIDX]], align 8 45; CHECK-NEXT: br label [[FOR_INC]] 46; CHECK: for.inc: 47; CHECK-NEXT: [[INC]] = add nsw i32 [[I_0]], 1 48; CHECK-NEXT: br label [[FOR_COND]] 49; CHECK: for.end: 50; CHECK-NEXT: ret void 51; 52 53entry: 54 call void @nocapture_nocallback_func(ptr @obj0) 55 br label %for.cond 56 57for.cond: ; preds = %for.inc, %entry 58 %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ] 59 %cmp = icmp slt i32 %i.0, 1000 60 br i1 %cmp, label %for.body, label %for.end 61 62for.body: ; preds = %for.cond 63 %0 = load ptr, ptr @obj0, align 8 64 %idxprom = sext i32 %i.0 to i64 65 %arrayidx = getelementptr inbounds ptr, ptr %0, i64 %idxprom 66 store ptr %p, ptr %arrayidx, align 8 67 br label %for.inc 68 69for.inc: ; preds = %for.body 70 %inc = add nsw i32 %i.0, 1 71 br label %for.cond 72 73for.end: ; preds = %for.cond 74 ret void 75} 76 77define dso_local void @test1(ptr %p) { 78; Check that load from @obj1 is not hoisted from the loop, 79; because 'nocallback' is missing: 80; CHECK-LABEL: @test1( 81; CHECK-NEXT: entry: 82; CHECK-NEXT: call void @nocapture_func(ptr @obj1) 83; CHECK-NEXT: br label [[FOR_COND:%.*]] 84; CHECK: for.cond: 85; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ] 86; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], 1000 87; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]] 88; CHECK: for.body: 89; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @obj1, align 8 90; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I_0]] to i64 91; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP0]], i64 [[IDXPROM]] 92; CHECK-NEXT: store ptr [[P:%.*]], ptr [[ARRAYIDX]], align 8 93; CHECK-NEXT: br label [[FOR_INC]] 94; CHECK: for.inc: 95; CHECK-NEXT: [[INC]] = add nsw i32 [[I_0]], 1 96; CHECK-NEXT: br label [[FOR_COND]] 97; CHECK: for.end: 98; CHECK-NEXT: ret void 99; 100 101entry: 102 call void @nocapture_func(ptr @obj1) 103 br label %for.cond 104 105for.cond: ; preds = %for.inc, %entry 106 %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ] 107 %cmp = icmp slt i32 %i.0, 1000 108 br i1 %cmp, label %for.body, label %for.end 109 110for.body: ; preds = %for.cond 111 %0 = load ptr, ptr @obj1, align 8 112 %idxprom = sext i32 %i.0 to i64 113 %arrayidx = getelementptr inbounds ptr, ptr %0, i64 %idxprom 114 store ptr %p, ptr %arrayidx, align 8 115 br label %for.inc 116 117for.inc: ; preds = %for.body 118 %inc = add nsw i32 %i.0, 1 119 br label %for.cond 120 121for.end: ; preds = %for.cond 122 ret void 123} 124 125define dso_local void @test2(ptr %p) { 126; Check that load from @obj2 is not hoisted from the loop, 127; because 'nocapture' is missing: 128; CHECK-LABEL: @test2( 129; CHECK-NEXT: entry: 130; CHECK-NEXT: call void @nocallback_func(ptr @obj2) 131; CHECK-NEXT: br label [[FOR_COND:%.*]] 132; CHECK: for.cond: 133; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ] 134; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], 1000 135; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]] 136; CHECK: for.body: 137; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @obj2, align 8 138; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I_0]] to i64 139; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP0]], i64 [[IDXPROM]] 140; CHECK-NEXT: store ptr [[P:%.*]], ptr [[ARRAYIDX]], align 8 141; CHECK-NEXT: br label [[FOR_INC]] 142; CHECK: for.inc: 143; CHECK-NEXT: [[INC]] = add nsw i32 [[I_0]], 1 144; CHECK-NEXT: br label [[FOR_COND]] 145; CHECK: for.end: 146; CHECK-NEXT: ret void 147; 148 149entry: 150 call void @nocallback_func(ptr @obj2) 151 br label %for.cond 152 153for.cond: ; preds = %for.inc, %entry 154 %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ] 155 %cmp = icmp slt i32 %i.0, 1000 156 br i1 %cmp, label %for.body, label %for.end 157 158for.body: ; preds = %for.cond 159 %0 = load ptr, ptr @obj2, align 8 160 %idxprom = sext i32 %i.0 to i64 161 %arrayidx = getelementptr inbounds ptr, ptr %0, i64 %idxprom 162 store ptr %p, ptr %arrayidx, align 8 163 br label %for.inc 164 165for.inc: ; preds = %for.body 166 %inc = add nsw i32 %i.0, 1 167 br label %for.cond 168 169for.end: ; preds = %for.cond 170 ret void 171} 172 173define dso_local void @test3(ptr %p) { 174; Check that load from @obj3 is hoisted from the loop, even though 175; there is unknown call in the loop. 176; CHECK-LABEL: @test3( 177; CHECK-NEXT: entry: 178; CHECK-NEXT: call void @nocapture_nocallback_func(ptr @obj3) 179; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @obj3, align 8 180; CHECK-NEXT: br label [[FOR_COND:%.*]] 181; CHECK: for.cond: 182; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ] 183; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], 1000 184; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]] 185; CHECK: for.body: 186; CHECK-NEXT: call void @unknown_call() 187; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I_0]] to i64 188; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP0]], i64 [[IDXPROM]] 189; CHECK-NEXT: store ptr [[P:%.*]], ptr [[ARRAYIDX]], align 8 190; CHECK-NEXT: br label [[FOR_INC]] 191; CHECK: for.inc: 192; CHECK-NEXT: [[INC]] = add nsw i32 [[I_0]], 1 193; CHECK-NEXT: br label [[FOR_COND]] 194; CHECK: for.end: 195; CHECK-NEXT: ret void 196; 197 198entry: 199 call void @nocapture_nocallback_func(ptr @obj3) 200 br label %for.cond 201 202for.cond: ; preds = %for.inc, %entry 203 %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ] 204 %cmp = icmp slt i32 %i.0, 1000 205 br i1 %cmp, label %for.body, label %for.end 206 207for.body: ; preds = %for.cond 208 %0 = load ptr, ptr @obj3, align 8 209 call void @unknown_call() 210 %idxprom = sext i32 %i.0 to i64 211 %arrayidx = getelementptr inbounds ptr, ptr %0, i64 %idxprom 212 store ptr %p, ptr %arrayidx, align 8 213 br label %for.inc 214 215for.inc: ; preds = %for.body 216 %inc = add nsw i32 %i.0, 1 217 br label %for.cond 218 219for.end: ; preds = %for.cond 220 ret void 221} 222 223define dso_local void @test4(ptr %p) { 224; Check that load from @obj4 is not hoisted from the loop, 225; because 'nocallback' is missing: 226; CHECK-LABEL: @test4( 227; CHECK-NEXT: entry: 228; CHECK-NEXT: call void @nocapture_func(ptr @obj4) 229; CHECK-NEXT: br label [[FOR_COND:%.*]] 230; CHECK: for.cond: 231; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ] 232; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], 1000 233; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]] 234; CHECK: for.body: 235; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @obj4, align 8 236; CHECK-NEXT: call void @unknown_call() 237; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I_0]] to i64 238; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP0]], i64 [[IDXPROM]] 239; CHECK-NEXT: store ptr [[P:%.*]], ptr [[ARRAYIDX]], align 8 240; CHECK-NEXT: br label [[FOR_INC]] 241; CHECK: for.inc: 242; CHECK-NEXT: [[INC]] = add nsw i32 [[I_0]], 1 243; CHECK-NEXT: br label [[FOR_COND]] 244; CHECK: for.end: 245; CHECK-NEXT: ret void 246; 247 248entry: 249 call void @nocapture_func(ptr @obj4) 250 br label %for.cond 251 252for.cond: ; preds = %for.inc, %entry 253 %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ] 254 %cmp = icmp slt i32 %i.0, 1000 255 br i1 %cmp, label %for.body, label %for.end 256 257for.body: ; preds = %for.cond 258 %0 = load ptr, ptr @obj4, align 8 259 call void @unknown_call() 260 %idxprom = sext i32 %i.0 to i64 261 %arrayidx = getelementptr inbounds ptr, ptr %0, i64 %idxprom 262 store ptr %p, ptr %arrayidx, align 8 263 br label %for.inc 264 265for.inc: ; preds = %for.body 266 %inc = add nsw i32 %i.0, 1 267 br label %for.cond 268 269for.end: ; preds = %for.cond 270 ret void 271} 272 273define dso_local void @test5(ptr %p) { 274; Check that load from @obj5 is not hoisted from the loop, 275; because 'nocapture' is missing: 276; CHECK-LABEL: @test5( 277; CHECK-NEXT: entry: 278; CHECK-NEXT: call void @nocallback_func(ptr @obj5) 279; CHECK-NEXT: br label [[FOR_COND:%.*]] 280; CHECK: for.cond: 281; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ] 282; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], 1000 283; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]] 284; CHECK: for.body: 285; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @obj5, align 8 286; CHECK-NEXT: call void @unknown_call() 287; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I_0]] to i64 288; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP0]], i64 [[IDXPROM]] 289; CHECK-NEXT: store ptr [[P:%.*]], ptr [[ARRAYIDX]], align 8 290; CHECK-NEXT: br label [[FOR_INC]] 291; CHECK: for.inc: 292; CHECK-NEXT: [[INC]] = add nsw i32 [[I_0]], 1 293; CHECK-NEXT: br label [[FOR_COND]] 294; CHECK: for.end: 295; CHECK-NEXT: ret void 296; 297 298entry: 299 call void @nocallback_func(ptr @obj5) 300 br label %for.cond 301 302for.cond: ; preds = %for.inc, %entry 303 %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ] 304 %cmp = icmp slt i32 %i.0, 1000 305 br i1 %cmp, label %for.body, label %for.end 306 307for.body: ; preds = %for.cond 308 %0 = load ptr, ptr @obj5, align 8 309 call void @unknown_call() 310 %idxprom = sext i32 %i.0 to i64 311 %arrayidx = getelementptr inbounds ptr, ptr %0, i64 %idxprom 312 store ptr %p, ptr %arrayidx, align 8 313 br label %for.inc 314 315for.inc: ; preds = %for.body 316 %inc = add nsw i32 %i.0, 1 317 br label %for.cond 318 319for.end: ; preds = %for.cond 320 ret void 321} 322 323declare void @nocapture_nocallback_func(ptr nocapture) nocallback 324declare void @nocapture_func(ptr nocapture) 325declare void @nocallback_func(ptr) nocallback 326; nosync and nocallback are required, otherwise the call 327; will by ModRef for any global: 328declare void @unknown_call() nosync nocallback 329