402 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt -S -passes=licm -use-dereferenceable-at-point-semantics=false < %s | FileCheck %s3; RUN: opt -S -passes=licm -use-dereferenceable-at-point-semantics < %s | FileCheck %s4 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(ptr 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 116; CHECK-NEXT: call void @init(ptr [[A]])17; CHECK-NEXT: br label [[FOR_BODY:%.*]]18; CHECK: for.body:19; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ]20; CHECK-NEXT: call void @unknown()21; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 122; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 20023; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_END:%.*]], label [[FOR_BODY]]24; CHECK: for.end:25; CHECK-NEXT: [[ADDR_LE:%.*]] = getelementptr i8, ptr [[A]], i32 3126; CHECK-NEXT: [[RES_LE:%.*]] = load i8, ptr [[ADDR_LE]], align 127; CHECK-NEXT: ret i8 [[RES_LE]]28;29entry:30 %a = alloca [32 x i8]31 call void @init(ptr %a)32 br label %for.body33 34for.body:35 %iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ]36 call void @unknown() ;; may throw37 %addr = getelementptr i8, ptr %a, i32 3138 %res = load i8, ptr %addr39 %iv.next = add nuw nsw i64 %iv, 140 %exitcond = icmp eq i64 %iv.next, 20041 br i1 %exitcond, label %for.end, label %for.body42 43for.end:44 ret i8 %res45}46 47define i8 @test_hoist_alloca() {48; CHECK-LABEL: @test_hoist_alloca(49; CHECK-NEXT: entry:50; CHECK-NEXT: [[A:%.*]] = alloca [32 x i8], align 151; CHECK-NEXT: call void @init(ptr [[A]])52; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i8, ptr [[A]], i32 3153; CHECK-NEXT: [[RES:%.*]] = load i8, ptr [[ADDR]], align 154; CHECK-NEXT: br label [[FOR_BODY:%.*]]55; CHECK: for.body:56; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ]57; CHECK-NEXT: call void @unknown()58; CHECK-NEXT: call void @use(i8 [[RES]])59; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 160; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 20061; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_END:%.*]], label [[FOR_BODY]]62; CHECK: for.end:63; CHECK-NEXT: [[RES_LCSSA:%.*]] = phi i8 [ [[RES]], [[FOR_BODY]] ]64; CHECK-NEXT: ret i8 [[RES_LCSSA]]65;66entry:67 %a = alloca [32 x i8]68 call void @init(ptr %a)69 br label %for.body70 71for.body:72 %iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ]73 call void @unknown() ;; may throw74 %addr = getelementptr i8, ptr %a, i32 3175 %res = load i8, ptr %addr76 call void @use(i8 %res)77 %iv.next = add nuw nsw i64 %iv, 178 %exitcond = icmp eq i64 %iv.next, 20079 br i1 %exitcond, label %for.end, label %for.body80 81for.end:82 ret i8 %res83}84 85; The attributes listed here are a) inferred by -O3 from the names86; and b) required for a standalone test. We're very inconsistent about87; which decisions we drive from TLI vs assume attributes have been infered.88declare void @free(ptr nocapture)89declare noalias ptr @malloc(i64)90 91define i8 @test_sink_malloc() {92; CHECK-LABEL: @test_sink_malloc(93; CHECK-NEXT: entry:94; CHECK-NEXT: [[A_RAW:%.*]] = call nonnull ptr @malloc(i64 32)95; CHECK-NEXT: call void @init(ptr [[A_RAW]])96; CHECK-NEXT: br label [[FOR_BODY:%.*]]97; CHECK: for.body:98; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ]99; CHECK-NEXT: call void @unknown()100; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1101; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 200102; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_END:%.*]], label [[FOR_BODY]]103; CHECK: for.end:104; CHECK-NEXT: [[ADDR_LE:%.*]] = getelementptr i8, ptr [[A_RAW]], i32 31105; CHECK-NEXT: [[RES_LE:%.*]] = load i8, ptr [[ADDR_LE]], align 1106; CHECK-NEXT: call void @free(ptr [[A_RAW]])107; CHECK-NEXT: ret i8 [[RES_LE]]108;109entry:110 ; Mark as nonnull to simplify test111 %a.raw = call nonnull ptr @malloc(i64 32)112 call void @init(ptr %a.raw)113 br label %for.body114 115for.body:116 %iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ]117 call void @unknown() ;; may throw118 %addr = getelementptr i8, ptr %a.raw, i32 31119 %res = load i8, ptr %addr120 %iv.next = add nuw nsw i64 %iv, 1121 %exitcond = icmp eq i64 %iv.next, 200122 br i1 %exitcond, label %for.end, label %for.body123 124for.end:125 call void @free(ptr %a.raw)126 ret i8 %res127}128 129; TODO: We can hoist the load in this case, but only once we have130; some form of context sensitive free analysis.131define i8 @test_hoist_malloc() {132; CHECK-LABEL: @test_hoist_malloc(133; CHECK-NEXT: entry:134; CHECK-NEXT: [[A_RAW:%.*]] = call nonnull ptr @malloc(i64 32)135; CHECK-NEXT: call void @init(ptr [[A_RAW]])136; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i8, ptr [[A_RAW]], i32 31137; CHECK-NEXT: br label [[FOR_BODY:%.*]]138; CHECK: for.body:139; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ]140; CHECK-NEXT: call void @unknown()141; CHECK-NEXT: [[RES:%.*]] = load i8, ptr [[ADDR]], align 1142; CHECK-NEXT: call void @use(i8 [[RES]])143; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1144; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 200145; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_END:%.*]], label [[FOR_BODY]]146; CHECK: for.end:147; CHECK-NEXT: [[RES_LCSSA:%.*]] = phi i8 [ [[RES]], [[FOR_BODY]] ]148; CHECK-NEXT: call void @free(ptr [[A_RAW]])149; CHECK-NEXT: ret i8 [[RES_LCSSA]]150;151entry:152 %a.raw = call nonnull ptr @malloc(i64 32)153 call void @init(ptr %a.raw)154 br label %for.body155 156for.body:157 %iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ]158 call void @unknown() ;; may throw159 %addr = getelementptr i8, ptr %a.raw, i32 31160 %res = load i8, ptr %addr161 call void @use(i8 %res)162 %iv.next = add nuw nsw i64 %iv, 1163 %exitcond = icmp eq i64 %iv.next, 200164 br i1 %exitcond, label %for.end, label %for.body165 166for.end:167 call void @free(ptr %a.raw)168 ret i8 %res169}170 171define i8 @test_hoist_malloc_leak() nofree nosync {172; CHECK-LABEL: @test_hoist_malloc_leak(173; CHECK-NEXT: entry:174; CHECK-NEXT: [[A_RAW:%.*]] = call nonnull ptr @malloc(i64 32)175; CHECK-NEXT: call void @init(ptr [[A_RAW]])176; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i8, ptr [[A_RAW]], i32 31177; CHECK-NEXT: br label [[FOR_BODY:%.*]]178; CHECK: for.body:179; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ]180; CHECK-NEXT: call void @unknown()181; CHECK-NEXT: [[RES:%.*]] = load i8, ptr [[ADDR]], align 1182; CHECK-NEXT: call void @use(i8 [[RES]])183; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1184; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 200185; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_END:%.*]], label [[FOR_BODY]]186; CHECK: for.end:187; CHECK-NEXT: [[RES_LCSSA:%.*]] = phi i8 [ [[RES]], [[FOR_BODY]] ]188; CHECK-NEXT: ret i8 [[RES_LCSSA]]189;190entry:191 %a.raw = call nonnull ptr @malloc(i64 32)192 call void @init(ptr %a.raw)193 br label %for.body194 195for.body:196 %iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ]197 call void @unknown() ;; may throw198 %addr = getelementptr i8, ptr %a.raw, i32 31199 %res = load i8, ptr %addr200 call void @use(i8 %res)201 %iv.next = add nuw nsw i64 %iv, 1202 %exitcond = icmp eq i64 %iv.next, 200203 br i1 %exitcond, label %for.end, label %for.body204 205for.end:206 ret i8 %res207}208 209; In this case, we can't hoist the load out of the loop as the memory it210; accesses may have been conditionally freed in a manner correlated with211; whether the load is reached in the loop.212define void @test_hoist_malloc_cond_free(i1 %c) {213; CHECK-LABEL: @test_hoist_malloc_cond_free(214; CHECK-NEXT: entry:215; CHECK-NEXT: [[A_RAW:%.*]] = call nonnull ptr @malloc(i64 32)216; CHECK-NEXT: call void @init(ptr [[A_RAW]])217; CHECK-NEXT: br i1 [[C:%.*]], label [[COND_FREE:%.*]], label [[PREHEADER:%.*]]218; CHECK: cond.free:219; CHECK-NEXT: call void @free(ptr [[A_RAW]])220; CHECK-NEXT: br label [[PREHEADER]]221; CHECK: preheader:222; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i8, ptr [[A_RAW]], i32 31223; CHECK-NEXT: br label [[FOR_BODY:%.*]]224; CHECK: for.body:225; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ], [ 0, [[PREHEADER]] ]226; CHECK-NEXT: br i1 [[C]], label [[FOR_END:%.*]], label [[LOOP_LATCH]]227; CHECK: loop.latch:228; CHECK-NEXT: call void @unknown()229; CHECK-NEXT: [[RES:%.*]] = load i8, ptr [[ADDR]], align 1230; CHECK-NEXT: call void @use(i8 [[RES]])231; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1232; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 200233; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_END]], label [[FOR_BODY]]234; CHECK: for.end:235; CHECK-NEXT: ret void236;237entry:238 %a.raw = call nonnull ptr @malloc(i64 32)239 call void @init(ptr %a.raw)240 br i1 %c, label %cond.free, label %preheader241cond.free:242 call void @free(ptr %a.raw)243 br label %preheader244preheader:245 br label %for.body246 247for.body:248 %iv = phi i64 [ %iv.next, %loop.latch ], [ 0, %preheader ]249 br i1 %c, label %for.end, label %loop.latch250 251loop.latch:252 call void @unknown() ;; may throw253 %addr = getelementptr i8, ptr %a.raw, i32 31254 %res = load i8, ptr %addr255 call void @use(i8 %res)256 %iv.next = add nuw nsw i64 %iv, 1257 %exitcond = icmp eq i64 %iv.next, 200258 br i1 %exitcond, label %for.end, label %for.body259 260for.end:261 ret void262}263 264define i8 @test_sink_malloc_cond_free(i1 %c) {265; CHECK-LABEL: @test_sink_malloc_cond_free(266; CHECK-NEXT: entry:267; CHECK-NEXT: [[A_RAW:%.*]] = call nonnull ptr @malloc(i64 32)268; CHECK-NEXT: call void @init(ptr [[A_RAW]])269; CHECK-NEXT: br i1 [[C:%.*]], label [[COND_FREE:%.*]], label [[PREHEADER:%.*]]270; CHECK: cond.free:271; CHECK-NEXT: call void @free(ptr [[A_RAW]])272; CHECK-NEXT: br label [[PREHEADER]]273; CHECK: preheader:274; CHECK-NEXT: br label [[FOR_BODY:%.*]]275; CHECK: for.body:276; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ], [ 0, [[PREHEADER]] ]277; CHECK-NEXT: br i1 [[C]], label [[FOR_END_SPLIT_LOOP_EXIT1:%.*]], label [[LOOP_LATCH]]278; CHECK: loop.latch:279; CHECK-NEXT: call void @unknown()280; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1281; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 200282; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_END_SPLIT_LOOP_EXIT:%.*]], label [[FOR_BODY]]283; CHECK: for.end.split.loop.exit:284; CHECK-NEXT: [[ADDR_LE:%.*]] = getelementptr i8, ptr [[A_RAW]], i32 31285; CHECK-NEXT: [[RES_LE:%.*]] = load i8, ptr [[ADDR_LE]], align 1286; CHECK-NEXT: br label [[FOR_END:%.*]]287; CHECK: for.end.split.loop.exit1:288; CHECK-NEXT: [[PHI_PH2:%.*]] = phi i8 [ 0, [[FOR_BODY]] ]289; CHECK-NEXT: br label [[FOR_END]]290; CHECK: for.end:291; CHECK-NEXT: [[PHI:%.*]] = phi i8 [ [[RES_LE]], [[FOR_END_SPLIT_LOOP_EXIT]] ], [ [[PHI_PH2]], [[FOR_END_SPLIT_LOOP_EXIT1]] ]292; CHECK-NEXT: ret i8 [[PHI]]293;294entry:295 %a.raw = call nonnull ptr @malloc(i64 32)296 call void @init(ptr %a.raw)297 br i1 %c, label %cond.free, label %preheader298cond.free:299 call void @free(ptr %a.raw)300 br label %preheader301preheader:302 br label %for.body303 304for.body:305 %iv = phi i64 [ %iv.next, %loop.latch ], [ 0, %preheader ]306 br i1 %c, label %for.end, label %loop.latch307 308loop.latch:309 call void @unknown() ;; may throw310 %addr = getelementptr i8, ptr %a.raw, i32 31311 %res = load i8, ptr %addr312 %iv.next = add nuw nsw i64 %iv, 1313 %exitcond = icmp eq i64 %iv.next, 200314 br i1 %exitcond, label %for.end, label %for.body315 316for.end:317 %phi = phi i8 [%res, %loop.latch], [0, %for.body]318 ret i8 %phi319}320 321declare noalias ptr @my_alloc(i64) allocsize(0)322 323; We would need context sensitive reasoning about frees (which we don't324; don't currently have) to hoist the load in this example.325define i8 @test_hoist_allocsize() {326; CHECK-LABEL: @test_hoist_allocsize(327; CHECK-NEXT: entry:328; CHECK-NEXT: [[A_RAW:%.*]] = call nonnull ptr @my_alloc(i64 32)329; CHECK-NEXT: call void @init(ptr [[A_RAW]])330; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i8, ptr [[A_RAW]], i32 31331; CHECK-NEXT: br label [[FOR_BODY:%.*]]332; CHECK: for.body:333; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ]334; CHECK-NEXT: call void @unknown()335; CHECK-NEXT: [[RES:%.*]] = load i8, ptr [[ADDR]], align 1336; CHECK-NEXT: call void @use(i8 [[RES]])337; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1338; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 200339; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_END:%.*]], label [[FOR_BODY]]340; CHECK: for.end:341; CHECK-NEXT: [[RES_LCSSA:%.*]] = phi i8 [ [[RES]], [[FOR_BODY]] ]342; CHECK-NEXT: call void @free(ptr [[A_RAW]])343; CHECK-NEXT: ret i8 [[RES_LCSSA]]344;345entry:346 %a.raw = call nonnull ptr @my_alloc(i64 32)347 call void @init(ptr %a.raw)348 br label %for.body349 350for.body:351 %iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ]352 call void @unknown() ;; may throw353 %addr = getelementptr i8, ptr %a.raw, i32 31354 %res = load i8, ptr %addr355 call void @use(i8 %res)356 %iv.next = add nuw nsw i64 %iv, 1357 %exitcond = icmp eq i64 %iv.next, 200358 br i1 %exitcond, label %for.end, label %for.body359 360for.end:361 call void @free(ptr %a.raw)362 ret i8 %res363}364 365define i8 @test_hoist_allocsize_leak() nofree nosync {366; CHECK-LABEL: @test_hoist_allocsize_leak(367; CHECK-NEXT: entry:368; CHECK-NEXT: [[A_RAW:%.*]] = call nonnull ptr @my_alloc(i64 32)369; CHECK-NEXT: call void @init(ptr [[A_RAW]])370; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i8, ptr [[A_RAW]], i32 31371; CHECK-NEXT: br label [[FOR_BODY:%.*]]372; CHECK: for.body:373; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ]374; CHECK-NEXT: call void @unknown()375; CHECK-NEXT: [[RES:%.*]] = load i8, ptr [[ADDR]], align 1376; CHECK-NEXT: call void @use(i8 [[RES]])377; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1378; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 200379; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_END:%.*]], label [[FOR_BODY]]380; CHECK: for.end:381; CHECK-NEXT: [[RES_LCSSA:%.*]] = phi i8 [ [[RES]], [[FOR_BODY]] ]382; CHECK-NEXT: ret i8 [[RES_LCSSA]]383;384entry:385 %a.raw = call nonnull ptr @my_alloc(i64 32)386 call void @init(ptr %a.raw)387 br label %for.body388 389for.body:390 %iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ]391 call void @unknown() ;; may throw392 %addr = getelementptr i8, ptr %a.raw, i32 31393 %res = load i8, ptr %addr394 call void @use(i8 %res)395 %iv.next = add nuw nsw i64 %iv, 1396 %exitcond = icmp eq i64 %iv.next, 200397 br i1 %exitcond, label %for.end, label %for.body398 399for.end:400 ret i8 %res401}402