1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -S -basic-aa -licm -use-dereferenceable-at-point-semantics=0 < %s | FileCheck %s 3; RUN: opt -S -basic-aa -licm -use-dereferenceable-at-point-semantics=1 < %s | FileCheck %s 4 5target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 6target triple = "x86_64-unknown-linux-gnu" 7 8declare void @unknown() 9declare void @init(i8* nocapture) 10declare void @use(i8) 11 12define i8 @test_sink_alloca() { 13; CHECK-LABEL: @test_sink_alloca( 14; CHECK-NEXT: entry: 15; CHECK-NEXT: [[A:%.*]] = alloca [32 x i8], align 1 16; CHECK-NEXT: [[A_RAW:%.*]] = bitcast [32 x i8]* [[A]] to i8* 17; CHECK-NEXT: call void @init(i8* [[A_RAW]]) 18; CHECK-NEXT: br label [[FOR_BODY:%.*]] 19; CHECK: for.body: 20; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ] 21; CHECK-NEXT: call void @unknown() 22; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 23; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 200 24; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_END:%.*]], label [[FOR_BODY]] 25; CHECK: for.end: 26; CHECK-NEXT: [[ADDR_LE:%.*]] = getelementptr i8, i8* [[A_RAW]], i32 31 27; CHECK-NEXT: [[RES_LE:%.*]] = load i8, i8* [[ADDR_LE]], align 1 28; CHECK-NEXT: ret i8 [[RES_LE]] 29; 30entry: 31 %a = alloca [32 x i8] 32 %a.raw = bitcast [32 x i8]* %a to i8* 33 call void @init(i8* %a.raw) 34 br label %for.body 35 36for.body: 37 %iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ] 38 call void @unknown() ;; may throw 39 %addr = getelementptr i8, i8* %a.raw, i32 31 40 %res = load i8, i8* %addr 41 %iv.next = add nuw nsw i64 %iv, 1 42 %exitcond = icmp eq i64 %iv.next, 200 43 br i1 %exitcond, label %for.end, label %for.body 44 45for.end: 46 ret i8 %res 47} 48 49define i8 @test_hoist_alloca() { 50; CHECK-LABEL: @test_hoist_alloca( 51; CHECK-NEXT: entry: 52; CHECK-NEXT: [[A:%.*]] = alloca [32 x i8], align 1 53; CHECK-NEXT: [[A_RAW:%.*]] = bitcast [32 x i8]* [[A]] to i8* 54; CHECK-NEXT: call void @init(i8* [[A_RAW]]) 55; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i8, i8* [[A_RAW]], i32 31 56; CHECK-NEXT: [[RES:%.*]] = load i8, i8* [[ADDR]], align 1 57; CHECK-NEXT: br label [[FOR_BODY:%.*]] 58; CHECK: for.body: 59; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ] 60; CHECK-NEXT: call void @unknown() 61; CHECK-NEXT: call void @use(i8 [[RES]]) 62; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 63; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 200 64; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_END:%.*]], label [[FOR_BODY]] 65; CHECK: for.end: 66; CHECK-NEXT: [[RES_LCSSA:%.*]] = phi i8 [ [[RES]], [[FOR_BODY]] ] 67; CHECK-NEXT: ret i8 [[RES_LCSSA]] 68; 69entry: 70 %a = alloca [32 x i8] 71 %a.raw = bitcast [32 x i8]* %a to i8* 72 call void @init(i8* %a.raw) 73 br label %for.body 74 75for.body: 76 %iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ] 77 call void @unknown() ;; may throw 78 %addr = getelementptr i8, i8* %a.raw, i32 31 79 %res = load i8, i8* %addr 80 call void @use(i8 %res) 81 %iv.next = add nuw nsw i64 %iv, 1 82 %exitcond = icmp eq i64 %iv.next, 200 83 br i1 %exitcond, label %for.end, label %for.body 84 85for.end: 86 ret i8 %res 87} 88 89; The attributes listed here are a) inferred by -O3 from the names 90; and b) required for a standalone test. We're very inconsistent about 91; which decisions we drive from TLI vs assume attributes have been infered. 92declare void @free(i8* nocapture) 93declare noalias i8* @malloc(i64) 94 95define i8 @test_sink_malloc() { 96; CHECK-LABEL: @test_sink_malloc( 97; CHECK-NEXT: entry: 98; CHECK-NEXT: [[A_RAW:%.*]] = call nonnull i8* @malloc(i64 32) 99; CHECK-NEXT: call void @init(i8* [[A_RAW]]) 100; CHECK-NEXT: br label [[FOR_BODY:%.*]] 101; CHECK: for.body: 102; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ] 103; CHECK-NEXT: call void @unknown() 104; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 105; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 200 106; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_END:%.*]], label [[FOR_BODY]] 107; CHECK: for.end: 108; CHECK-NEXT: [[ADDR_LE:%.*]] = getelementptr i8, i8* [[A_RAW]], i32 31 109; CHECK-NEXT: [[RES_LE:%.*]] = load i8, i8* [[ADDR_LE]], align 1 110; CHECK-NEXT: call void @free(i8* [[A_RAW]]) 111; CHECK-NEXT: ret i8 [[RES_LE]] 112; 113entry: 114 ; Mark as nonnull to simplify test 115 %a.raw = call nonnull i8* @malloc(i64 32) 116 call void @init(i8* %a.raw) 117 br label %for.body 118 119for.body: 120 %iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ] 121 call void @unknown() ;; may throw 122 %addr = getelementptr i8, i8* %a.raw, i32 31 123 %res = load i8, i8* %addr 124 %iv.next = add nuw nsw i64 %iv, 1 125 %exitcond = icmp eq i64 %iv.next, 200 126 br i1 %exitcond, label %for.end, label %for.body 127 128for.end: 129 call void @free(i8* %a.raw) 130 ret i8 %res 131} 132 133; TODO: We can hoist the load in this case, but only once we have 134; some form of context sensitive free analysis. 135define i8 @test_hoist_malloc() { 136; CHECK-LABEL: @test_hoist_malloc( 137; CHECK-NEXT: entry: 138; CHECK-NEXT: [[A_RAW:%.*]] = call nonnull i8* @malloc(i64 32) 139; CHECK-NEXT: call void @init(i8* [[A_RAW]]) 140; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i8, i8* [[A_RAW]], i32 31 141; CHECK-NEXT: br label [[FOR_BODY:%.*]] 142; CHECK: for.body: 143; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ] 144; CHECK-NEXT: call void @unknown() 145; CHECK-NEXT: [[RES:%.*]] = load i8, i8* [[ADDR]], align 1 146; CHECK-NEXT: call void @use(i8 [[RES]]) 147; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 148; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 200 149; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_END:%.*]], label [[FOR_BODY]] 150; CHECK: for.end: 151; CHECK-NEXT: [[RES_LCSSA:%.*]] = phi i8 [ [[RES]], [[FOR_BODY]] ] 152; CHECK-NEXT: call void @free(i8* [[A_RAW]]) 153; CHECK-NEXT: ret i8 [[RES_LCSSA]] 154; 155entry: 156 %a.raw = call nonnull i8* @malloc(i64 32) 157 call void @init(i8* %a.raw) 158 br label %for.body 159 160for.body: 161 %iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ] 162 call void @unknown() ;; may throw 163 %addr = getelementptr i8, i8* %a.raw, i32 31 164 %res = load i8, i8* %addr 165 call void @use(i8 %res) 166 %iv.next = add nuw nsw i64 %iv, 1 167 %exitcond = icmp eq i64 %iv.next, 200 168 br i1 %exitcond, label %for.end, label %for.body 169 170for.end: 171 call void @free(i8* %a.raw) 172 ret i8 %res 173} 174 175define i8 @test_hoist_malloc_leak() nofree nosync { 176; CHECK-LABEL: @test_hoist_malloc_leak( 177; CHECK-NEXT: entry: 178; CHECK-NEXT: [[A_RAW:%.*]] = call nonnull i8* @malloc(i64 32) 179; CHECK-NEXT: call void @init(i8* [[A_RAW]]) 180; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i8, i8* [[A_RAW]], i32 31 181; CHECK-NEXT: br label [[FOR_BODY:%.*]] 182; CHECK: for.body: 183; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ] 184; CHECK-NEXT: call void @unknown() 185; CHECK-NEXT: [[RES:%.*]] = load i8, i8* [[ADDR]], align 1 186; CHECK-NEXT: call void @use(i8 [[RES]]) 187; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 188; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 200 189; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_END:%.*]], label [[FOR_BODY]] 190; CHECK: for.end: 191; CHECK-NEXT: [[RES_LCSSA:%.*]] = phi i8 [ [[RES]], [[FOR_BODY]] ] 192; CHECK-NEXT: ret i8 [[RES_LCSSA]] 193; 194entry: 195 %a.raw = call nonnull i8* @malloc(i64 32) 196 call void @init(i8* %a.raw) 197 br label %for.body 198 199for.body: 200 %iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ] 201 call void @unknown() ;; may throw 202 %addr = getelementptr i8, i8* %a.raw, i32 31 203 %res = load i8, i8* %addr 204 call void @use(i8 %res) 205 %iv.next = add nuw nsw i64 %iv, 1 206 %exitcond = icmp eq i64 %iv.next, 200 207 br i1 %exitcond, label %for.end, label %for.body 208 209for.end: 210 ret i8 %res 211} 212 213; In this case, we can't hoist the load out of the loop as the memory it 214; accesses may have been conditionally freed in a manner correlated with 215; whether the load is reached in the loop. 216define void @test_hoist_malloc_cond_free(i1 %c) { 217; CHECK-LABEL: @test_hoist_malloc_cond_free( 218; CHECK-NEXT: entry: 219; CHECK-NEXT: [[A_RAW:%.*]] = call nonnull i8* @malloc(i64 32) 220; CHECK-NEXT: call void @init(i8* [[A_RAW]]) 221; CHECK-NEXT: br i1 [[C:%.*]], label [[COND_FREE:%.*]], label [[PREHEADER:%.*]] 222; CHECK: cond.free: 223; CHECK-NEXT: call void @free(i8* [[A_RAW]]) 224; CHECK-NEXT: br label [[PREHEADER]] 225; CHECK: preheader: 226; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i8, i8* [[A_RAW]], i32 31 227; CHECK-NEXT: br label [[FOR_BODY:%.*]] 228; CHECK: for.body: 229; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ], [ 0, [[PREHEADER]] ] 230; CHECK-NEXT: br i1 [[C]], label [[FOR_END:%.*]], label [[LOOP_LATCH]] 231; CHECK: loop.latch: 232; CHECK-NEXT: call void @unknown() 233; CHECK-NEXT: [[RES:%.*]] = load i8, i8* [[ADDR]], align 1 234; CHECK-NEXT: call void @use(i8 [[RES]]) 235; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 236; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 200 237; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_END]], label [[FOR_BODY]] 238; CHECK: for.end: 239; CHECK-NEXT: ret void 240; 241entry: 242 %a.raw = call nonnull i8* @malloc(i64 32) 243 call void @init(i8* %a.raw) 244 br i1 %c, label %cond.free, label %preheader 245cond.free: 246 call void @free(i8* %a.raw) 247 br label %preheader 248preheader: 249 br label %for.body 250 251for.body: 252 %iv = phi i64 [ %iv.next, %loop.latch ], [ 0, %preheader ] 253 br i1 %c, label %for.end, label %loop.latch 254 255loop.latch: 256 call void @unknown() ;; may throw 257 %addr = getelementptr i8, i8* %a.raw, i32 31 258 %res = load i8, i8* %addr 259 call void @use(i8 %res) 260 %iv.next = add nuw nsw i64 %iv, 1 261 %exitcond = icmp eq i64 %iv.next, 200 262 br i1 %exitcond, label %for.end, label %for.body 263 264for.end: 265 ret void 266} 267 268define i8 @test_sink_malloc_cond_free(i1 %c) { 269; CHECK-LABEL: @test_sink_malloc_cond_free( 270; CHECK-NEXT: entry: 271; CHECK-NEXT: [[A_RAW:%.*]] = call nonnull i8* @malloc(i64 32) 272; CHECK-NEXT: call void @init(i8* [[A_RAW]]) 273; CHECK-NEXT: br i1 [[C:%.*]], label [[COND_FREE:%.*]], label [[PREHEADER:%.*]] 274; CHECK: cond.free: 275; CHECK-NEXT: call void @free(i8* [[A_RAW]]) 276; CHECK-NEXT: br label [[PREHEADER]] 277; CHECK: preheader: 278; CHECK-NEXT: br label [[FOR_BODY:%.*]] 279; CHECK: for.body: 280; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ], [ 0, [[PREHEADER]] ] 281; CHECK-NEXT: br i1 [[C]], label [[FOR_END_SPLIT_LOOP_EXIT1:%.*]], label [[LOOP_LATCH]] 282; CHECK: loop.latch: 283; CHECK-NEXT: call void @unknown() 284; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 285; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 200 286; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_END_SPLIT_LOOP_EXIT:%.*]], label [[FOR_BODY]] 287; CHECK: for.end.split.loop.exit: 288; CHECK-NEXT: [[ADDR_LE:%.*]] = getelementptr i8, i8* [[A_RAW]], i32 31 289; CHECK-NEXT: [[RES_LE:%.*]] = load i8, i8* [[ADDR_LE]], align 1 290; CHECK-NEXT: br label [[FOR_END:%.*]] 291; CHECK: for.end.split.loop.exit1: 292; CHECK-NEXT: [[PHI_PH2:%.*]] = phi i8 [ 0, [[FOR_BODY]] ] 293; CHECK-NEXT: br label [[FOR_END]] 294; CHECK: for.end: 295; CHECK-NEXT: [[PHI:%.*]] = phi i8 [ [[RES_LE]], [[FOR_END_SPLIT_LOOP_EXIT]] ], [ [[PHI_PH2]], [[FOR_END_SPLIT_LOOP_EXIT1]] ] 296; CHECK-NEXT: ret i8 [[PHI]] 297; 298entry: 299 %a.raw = call nonnull i8* @malloc(i64 32) 300 call void @init(i8* %a.raw) 301 br i1 %c, label %cond.free, label %preheader 302cond.free: 303 call void @free(i8* %a.raw) 304 br label %preheader 305preheader: 306 br label %for.body 307 308for.body: 309 %iv = phi i64 [ %iv.next, %loop.latch ], [ 0, %preheader ] 310 br i1 %c, label %for.end, label %loop.latch 311 312loop.latch: 313 call void @unknown() ;; may throw 314 %addr = getelementptr i8, i8* %a.raw, i32 31 315 %res = load i8, i8* %addr 316 %iv.next = add nuw nsw i64 %iv, 1 317 %exitcond = icmp eq i64 %iv.next, 200 318 br i1 %exitcond, label %for.end, label %for.body 319 320for.end: 321 %phi = phi i8 [%res, %loop.latch], [0, %for.body] 322 ret i8 %phi 323} 324 325declare noalias i8* @my_alloc(i64) allocsize(0) 326 327; We would need context sensitive reasoning about frees (which we don't 328; don't currently have) to hoist the load in this example. 329define i8 @test_hoist_allocsize() { 330; CHECK-LABEL: @test_hoist_allocsize( 331; CHECK-NEXT: entry: 332; CHECK-NEXT: [[A_RAW:%.*]] = call nonnull i8* @my_alloc(i64 32) 333; CHECK-NEXT: call void @init(i8* [[A_RAW]]) 334; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i8, i8* [[A_RAW]], i32 31 335; CHECK-NEXT: br label [[FOR_BODY:%.*]] 336; CHECK: for.body: 337; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ] 338; CHECK-NEXT: call void @unknown() 339; CHECK-NEXT: [[RES:%.*]] = load i8, i8* [[ADDR]], align 1 340; CHECK-NEXT: call void @use(i8 [[RES]]) 341; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 342; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 200 343; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_END:%.*]], label [[FOR_BODY]] 344; CHECK: for.end: 345; CHECK-NEXT: [[RES_LCSSA:%.*]] = phi i8 [ [[RES]], [[FOR_BODY]] ] 346; CHECK-NEXT: call void @free(i8* [[A_RAW]]) 347; CHECK-NEXT: ret i8 [[RES_LCSSA]] 348; 349entry: 350 %a.raw = call nonnull i8* @my_alloc(i64 32) 351 call void @init(i8* %a.raw) 352 br label %for.body 353 354for.body: 355 %iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ] 356 call void @unknown() ;; may throw 357 %addr = getelementptr i8, i8* %a.raw, i32 31 358 %res = load i8, i8* %addr 359 call void @use(i8 %res) 360 %iv.next = add nuw nsw i64 %iv, 1 361 %exitcond = icmp eq i64 %iv.next, 200 362 br i1 %exitcond, label %for.end, label %for.body 363 364for.end: 365 call void @free(i8* %a.raw) 366 ret i8 %res 367} 368 369define i8 @test_hoist_allocsize_leak() nofree nosync { 370; CHECK-LABEL: @test_hoist_allocsize_leak( 371; CHECK-NEXT: entry: 372; CHECK-NEXT: [[A_RAW:%.*]] = call nonnull i8* @my_alloc(i64 32) 373; CHECK-NEXT: call void @init(i8* [[A_RAW]]) 374; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i8, i8* [[A_RAW]], i32 31 375; CHECK-NEXT: br label [[FOR_BODY:%.*]] 376; CHECK: for.body: 377; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ] 378; CHECK-NEXT: call void @unknown() 379; CHECK-NEXT: [[RES:%.*]] = load i8, i8* [[ADDR]], align 1 380; CHECK-NEXT: call void @use(i8 [[RES]]) 381; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 382; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 200 383; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_END:%.*]], label [[FOR_BODY]] 384; CHECK: for.end: 385; CHECK-NEXT: [[RES_LCSSA:%.*]] = phi i8 [ [[RES]], [[FOR_BODY]] ] 386; CHECK-NEXT: ret i8 [[RES_LCSSA]] 387; 388entry: 389 %a.raw = call nonnull i8* @my_alloc(i64 32) 390 call void @init(i8* %a.raw) 391 br label %for.body 392 393for.body: 394 %iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ] 395 call void @unknown() ;; may throw 396 %addr = getelementptr i8, i8* %a.raw, i32 31 397 %res = load i8, i8* %addr 398 call void @use(i8 %res) 399 %iv.next = add nuw nsw i64 %iv, 1 400 %exitcond = icmp eq i64 %iv.next, 200 401 br i1 %exitcond, label %for.end, label %for.body 402 403for.end: 404 ret i8 %res 405} 406