492 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt -passes=instcombine -S < %s | FileCheck %s3 4; Function Attrs: noinline uwtable5define i32 @foo(ptr nocapture writeonly %arg) {6; CHECK-LABEL: @foo(7; CHECK-NEXT: bb:8; CHECK-NEXT: [[VAR:%.*]] = call i32 @baz()9; CHECK-NEXT: store i32 [[VAR]], ptr [[ARG:%.*]], align 410; CHECK-NEXT: [[VAR1:%.*]] = call i32 @baz()11; CHECK-NEXT: ret i32 [[VAR1]]12;13bb:14 %var = call i32 @baz()15 store i32 %var, ptr %arg, align 416 %var1 = call i32 @baz()17 ret i32 %var118}19declare i32 @baz()20 21; Function Attrs: uwtable22; This is an equivalent IR for a c-style example with a large function (foo)23; with out-params which are unused in the caller(test8). Note that foo is24; marked noinline to prevent IPO transforms.25; int foo();26;27; extern int foo(int *out) __attribute__((noinline));28; int foo(int *out) {29; *out = baz();30; return baz();31; }32;33; int test() {34;35; int notdead;36; if (foo(¬dead))37; return 0;38;39; int dead;40; int tmp = foo(&dead);41; if (notdead)42; return tmp;43; return bar();44; }45 46; TODO: We should be able to sink the second call @foo at bb5 down to bb_crit_edge47define i32 @test() {48; CHECK-LABEL: @test(49; CHECK-NEXT: bb:50; CHECK-NEXT: [[VAR:%.*]] = alloca i32, align 451; CHECK-NEXT: [[VAR1:%.*]] = alloca i32, align 452; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[VAR]])53; CHECK-NEXT: [[VAR3:%.*]] = call i32 @foo(ptr nonnull writeonly [[VAR]])54; CHECK-NEXT: [[VAR4:%.*]] = icmp eq i32 [[VAR3]], 055; CHECK-NEXT: br i1 [[VAR4]], label [[BB5:%.*]], label [[BB14:%.*]]56; CHECK: bb5:57; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[VAR1]])58; CHECK-NEXT: [[VAR8:%.*]] = load i32, ptr [[VAR]], align 459; CHECK-NEXT: [[VAR9:%.*]] = icmp eq i32 [[VAR8]], 060; CHECK-NEXT: [[VAR7:%.*]] = call i32 @foo(ptr nonnull writeonly [[VAR1]])61; CHECK-NEXT: br i1 [[VAR9]], label [[BB10:%.*]], label [[BB_CRIT_EDGE:%.*]]62; CHECK: bb10:63; CHECK-NEXT: [[VAR11:%.*]] = call i32 @bar()64; CHECK-NEXT: br label [[BB12:%.*]]65; CHECK: bb_crit_edge:66; CHECK-NEXT: br label [[BB12]]67; CHECK: bb12:68; CHECK-NEXT: [[VAR13:%.*]] = phi i32 [ [[VAR11]], [[BB10]] ], [ [[VAR7]], [[BB_CRIT_EDGE]] ]69; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[VAR1]])70; CHECK-NEXT: br label [[BB14]]71; CHECK: bb14:72; CHECK-NEXT: [[VAR15:%.*]] = phi i32 [ [[VAR13]], [[BB12]] ], [ 0, [[BB:%.*]] ]73; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[VAR]])74; CHECK-NEXT: ret i32 [[VAR15]]75;76bb:77 %var = alloca i32, align 478 %var1 = alloca i32, align 479 call void @llvm.lifetime.start.p0(ptr nonnull %var) #480 %var3 = call i32 @foo(ptr nonnull writeonly %var)81 %var4 = icmp eq i32 %var3, 082 br i1 %var4, label %bb5, label %bb1483 84bb5: ; preds = %bb85 call void @llvm.lifetime.start.p0(ptr nonnull %var1) #486 %var8 = load i32, ptr %var, align 487 %var9 = icmp eq i32 %var8, 088 %var7 = call i32 @foo(ptr nonnull writeonly %var1)89 br i1 %var9, label %bb10, label %bb_crit_edge90 91bb10: ; preds = %bb592 %var11 = call i32 @bar()93 br label %bb1294 95bb_crit_edge:96 br label %bb1297 98bb12: ; preds = %bb10, %bb599 %var13 = phi i32 [ %var11, %bb10 ], [ %var7, %bb_crit_edge ]100 call void @llvm.lifetime.end.p0(ptr nonnull %var1) #4101 br label %bb14102 103bb14: ; preds = %bb12, %bb104 %var15 = phi i32 [ %var13, %bb12 ], [ 0, %bb ]105 call void @llvm.lifetime.end.p0(ptr nonnull %var)106 ret i32 %var15107}108 109declare i32 @unknown(ptr %dest)110declare i32 @unknown.as2(ptr addrspace(2) %dest)111 112define i32 @sink_write_to_use(i1 %c) {113; CHECK-LABEL: @sink_write_to_use(114; CHECK-NEXT: entry:115; CHECK-NEXT: [[VAR:%.*]] = alloca i32, align 4116; CHECK-NEXT: br i1 [[C:%.*]], label [[EARLY_RETURN:%.*]], label [[USE_BLOCK:%.*]]117; CHECK: early_return:118; CHECK-NEXT: ret i32 0119; CHECK: use_block:120; CHECK-NEXT: [[VAR3:%.*]] = call i32 @unknown(ptr nonnull writeonly [[VAR]]) #[[ATTR1:[0-9]+]]121; CHECK-NEXT: ret i32 [[VAR3]]122;123entry:124 %var = alloca i32, align 4125 %var3 = call i32 @unknown(ptr writeonly %var) argmemonly nounwind willreturn126 br i1 %c, label %early_return, label %use_block127 128early_return:129 ret i32 0130 131use_block:132 ret i32 %var3133}134 135define i32 @sink_readwrite_to_use(i1 %c) {136; CHECK-LABEL: @sink_readwrite_to_use(137; CHECK-NEXT: entry:138; CHECK-NEXT: [[VAR:%.*]] = alloca i32, align 4139; CHECK-NEXT: br i1 [[C:%.*]], label [[EARLY_RETURN:%.*]], label [[USE_BLOCK:%.*]]140; CHECK: early_return:141; CHECK-NEXT: ret i32 0142; CHECK: use_block:143; CHECK-NEXT: [[VAR3:%.*]] = call i32 @unknown(ptr nonnull [[VAR]]) #[[ATTR1]]144; CHECK-NEXT: ret i32 [[VAR3]]145;146entry:147 %var = alloca i32, align 4148 %var3 = call i32 @unknown(ptr %var) argmemonly nounwind willreturn149 br i1 %c, label %early_return, label %use_block150 151early_return:152 ret i32 0153 154use_block:155 ret i32 %var3156}157 158define i32 @sink_bitcast(i1 %c) {159; CHECK-LABEL: @sink_bitcast(160; CHECK-NEXT: entry:161; CHECK-NEXT: [[VAR:%.*]] = alloca i8, align 8162; CHECK-NEXT: br i1 [[C:%.*]], label [[EARLY_RETURN:%.*]], label [[USE_BLOCK:%.*]]163; CHECK: early_return:164; CHECK-NEXT: ret i32 0165; CHECK: use_block:166; CHECK-NEXT: [[VAR3:%.*]] = call i32 @unknown(ptr nonnull [[VAR]]) #[[ATTR1]]167; CHECK-NEXT: ret i32 [[VAR3]]168;169entry:170 %var = alloca i8, align 8171 %var3 = call i32 @unknown(ptr %var) argmemonly nounwind willreturn172 br i1 %c, label %early_return, label %use_block173 174early_return:175 ret i32 0176 177use_block:178 ret i32 %var3179}180 181 182define i32 @sink_gep1(i1 %c) {183; CHECK-LABEL: @sink_gep1(184; CHECK-NEXT: entry:185; CHECK-NEXT: [[VAR:%.*]] = alloca i64, align 8186; CHECK-NEXT: br i1 [[C:%.*]], label [[EARLY_RETURN:%.*]], label [[USE_BLOCK:%.*]]187; CHECK: early_return:188; CHECK-NEXT: ret i32 0189; CHECK: use_block:190; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[VAR]], i64 4191; CHECK-NEXT: [[VAR3:%.*]] = call i32 @unknown(ptr nonnull [[GEP]]) #[[ATTR1]]192; CHECK-NEXT: ret i32 [[VAR3]]193;194entry:195 %var = alloca i64, align 8196 %gep = getelementptr i32, ptr %var, i32 1197 %var3 = call i32 @unknown(ptr %gep) argmemonly nounwind willreturn198 br i1 %c, label %early_return, label %use_block199 200early_return:201 ret i32 0202 203use_block:204 ret i32 %var3205}206 207define i32 @sink_gep2(i1 %c) {208; CHECK-LABEL: @sink_gep2(209; CHECK-NEXT: entry:210; CHECK-NEXT: [[VAR:%.*]] = alloca i64, align 8211; CHECK-NEXT: br i1 [[C:%.*]], label [[EARLY_RETURN:%.*]], label [[USE_BLOCK:%.*]]212; CHECK: early_return:213; CHECK-NEXT: ret i32 0214; CHECK: use_block:215; CHECK-NEXT: [[VAR3:%.*]] = call i32 @unknown(ptr nonnull [[VAR]]) #[[ATTR1]]216; CHECK-NEXT: ret i32 [[VAR3]]217;218entry:219 %var = alloca i64, align 8220 %var3 = call i32 @unknown(ptr %var) argmemonly nounwind willreturn221 br i1 %c, label %early_return, label %use_block222 223early_return:224 ret i32 0225 226use_block:227 ret i32 %var3228}229 230define i32 @sink_addrspacecast(i1 %c) {231; CHECK-LABEL: @sink_addrspacecast(232; CHECK-NEXT: entry:233; CHECK-NEXT: [[VAR:%.*]] = alloca i32, align 8234; CHECK-NEXT: br i1 [[C:%.*]], label [[EARLY_RETURN:%.*]], label [[USE_BLOCK:%.*]]235; CHECK: early_return:236; CHECK-NEXT: ret i32 0237; CHECK: use_block:238; CHECK-NEXT: [[CAST:%.*]] = addrspacecast ptr [[VAR]] to ptr addrspace(2)239; CHECK-NEXT: [[VAR3:%.*]] = call i32 @unknown.as2(ptr addrspace(2) [[CAST]]) #[[ATTR1]]240; CHECK-NEXT: ret i32 [[VAR3]]241;242entry:243 %var = alloca i32, align 8244 %cast = addrspacecast ptr %var to ptr addrspace(2)245 %var3 = call i32 @unknown.as2(ptr addrspace(2) %cast) argmemonly nounwind willreturn246 br i1 %c, label %early_return, label %use_block247 248early_return:249 ret i32 0250 251use_block:252 ret i32 %var3253}254 255define i32 @neg_infinite_loop(i1 %c) {256; CHECK-LABEL: @neg_infinite_loop(257; CHECK-NEXT: entry:258; CHECK-NEXT: [[VAR:%.*]] = alloca i32, align 4259; CHECK-NEXT: [[VAR3:%.*]] = call i32 @unknown(ptr nonnull [[VAR]]) #[[ATTR2:[0-9]+]]260; CHECK-NEXT: br i1 [[C:%.*]], label [[EARLY_RETURN:%.*]], label [[USE_BLOCK:%.*]]261; CHECK: early_return:262; CHECK-NEXT: ret i32 0263; CHECK: use_block:264; CHECK-NEXT: ret i32 [[VAR3]]265;266entry:267 %var = alloca i32, align 4268 %var3 = call i32 @unknown(ptr %var) argmemonly nounwind269 br i1 %c, label %early_return, label %use_block270 271early_return:272 ret i32 0273 274use_block:275 ret i32 %var3276}277 278define i32 @neg_throw(i1 %c) {279; CHECK-LABEL: @neg_throw(280; CHECK-NEXT: entry:281; CHECK-NEXT: [[VAR:%.*]] = alloca i32, align 4282; CHECK-NEXT: [[VAR3:%.*]] = call i32 @unknown(ptr nonnull [[VAR]]) #[[ATTR3:[0-9]+]]283; CHECK-NEXT: br i1 [[C:%.*]], label [[EARLY_RETURN:%.*]], label [[USE_BLOCK:%.*]]284; CHECK: early_return:285; CHECK-NEXT: ret i32 0286; CHECK: use_block:287; CHECK-NEXT: ret i32 [[VAR3]]288;289entry:290 %var = alloca i32, align 4291 %var3 = call i32 @unknown(ptr %var) argmemonly willreturn292 br i1 %c, label %early_return, label %use_block293 294early_return:295 ret i32 0296 297use_block:298 ret i32 %var3299}300 301define i32 @neg_unknown_write(i1 %c) {302; CHECK-LABEL: @neg_unknown_write(303; CHECK-NEXT: entry:304; CHECK-NEXT: [[VAR:%.*]] = alloca i32, align 4305; CHECK-NEXT: [[VAR3:%.*]] = call i32 @unknown(ptr nonnull [[VAR]]) #[[ATTR4:[0-9]+]]306; CHECK-NEXT: br i1 [[C:%.*]], label [[EARLY_RETURN:%.*]], label [[USE_BLOCK:%.*]]307; CHECK: early_return:308; CHECK-NEXT: ret i32 0309; CHECK: use_block:310; CHECK-NEXT: ret i32 [[VAR3]]311;312entry:313 %var = alloca i32, align 4314 %var3 = call i32 @unknown(ptr %var) nounwind willreturn315 br i1 %c, label %early_return, label %use_block316 317early_return:318 ret i32 0319 320use_block:321 ret i32 %var3322}323 324define i32 @sink_lifetime1(i1 %c) {325; CHECK-LABEL: @sink_lifetime1(326; CHECK-NEXT: entry:327; CHECK-NEXT: [[VAR:%.*]] = alloca i32, align 4328; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[VAR]])329; CHECK-NEXT: [[VAR3:%.*]] = call i32 @unknown(ptr nonnull [[VAR]]) #[[ATTR1]]330; CHECK-NEXT: br i1 [[C:%.*]], label [[EARLY_RETURN:%.*]], label [[USE_BLOCK:%.*]]331; CHECK: early_return:332; CHECK-NEXT: ret i32 0333; CHECK: use_block:334; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[VAR]])335; CHECK-NEXT: ret i32 [[VAR3]]336;337entry:338 %var = alloca i32, align 4339 call void @llvm.lifetime.start.p0(ptr %var)340 %var3 = call i32 @unknown(ptr %var) argmemonly nounwind willreturn341 br i1 %c, label %early_return, label %use_block342 343early_return:344 ret i32 0345 346use_block:347 call void @llvm.lifetime.end.p0(ptr %var)348 ret i32 %var3349}350 351define i32 @sink_lifetime2(i1 %c) {352; CHECK-LABEL: @sink_lifetime2(353; CHECK-NEXT: entry:354; CHECK-NEXT: [[VAR:%.*]] = alloca i32, align 4355; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[VAR]])356; CHECK-NEXT: [[VAR3:%.*]] = call i32 @unknown(ptr nonnull [[VAR]]) #[[ATTR1]]357; CHECK-NEXT: br i1 [[C:%.*]], label [[MERGE:%.*]], label [[USE_BLOCK:%.*]]358; CHECK: merge:359; CHECK-NEXT: [[RET:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[VAR3]], [[USE_BLOCK]] ]360; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[VAR]])361; CHECK-NEXT: ret i32 [[RET]]362; CHECK: use_block:363; CHECK-NEXT: br label [[MERGE]]364;365entry:366 %var = alloca i32, align 4367 call void @llvm.lifetime.start.p0(ptr %var)368 %var3 = call i32 @unknown(ptr %var) argmemonly nounwind willreturn369 br i1 %c, label %merge, label %use_block370 371merge:372 %ret = phi i32 [0, %entry], [%var3, %use_block]373 call void @llvm.lifetime.end.p0(ptr %var)374 ret i32 %ret375 376use_block:377 br label %merge378}379 380define i32 @sink_lifetime3(i1 %c) {381; CHECK-LABEL: @sink_lifetime3(382; CHECK-NEXT: entry:383; CHECK-NEXT: [[VAR:%.*]] = alloca i32, align 4384; CHECK-NEXT: br i1 [[C:%.*]], label [[EARLY_RETURN:%.*]], label [[USE_BLOCK:%.*]]385; CHECK: early_return:386; CHECK-NEXT: ret i32 0387; CHECK: use_block:388; CHECK-NEXT: [[VAR3:%.*]] = call i32 @unknown(ptr nonnull [[VAR]]) #[[ATTR1]]389; CHECK-NEXT: ret i32 [[VAR3]]390;391entry:392 %var = alloca i32, align 4393 call void @llvm.lifetime.start.p0(ptr %var)394 call void @llvm.lifetime.end.p0(ptr %var)395 ; If unknown accesses %var, that's UB396 %var3 = call i32 @unknown(ptr %var) argmemonly nounwind willreturn397 br i1 %c, label %early_return, label %use_block398 399early_return:400 ret i32 0401 402use_block:403 ret i32 %var3404}405 406define i32 @sink_lifetime4a(i1 %c) {407; CHECK-LABEL: @sink_lifetime4a(408; CHECK-NEXT: entry:409; CHECK-NEXT: [[VAR:%.*]] = alloca i32, align 4410; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[VAR]])411; CHECK-NEXT: [[VAR3:%.*]] = call i32 @unknown(ptr nonnull [[VAR]]) #[[ATTR1]]412; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[VAR]])413; CHECK-NEXT: br i1 [[C:%.*]], label [[EARLY_RETURN:%.*]], label [[USE_BLOCK:%.*]]414; CHECK: early_return:415; CHECK-NEXT: ret i32 0416; CHECK: use_block:417; CHECK-NEXT: ret i32 [[VAR3]]418;419entry:420 %var = alloca i32, align 4421 call void @llvm.lifetime.start.p0(ptr %var)422 %var3 = call i32 @unknown(ptr %var) argmemonly nounwind willreturn423 call void @llvm.lifetime.end.p0(ptr %var)424 br i1 %c, label %early_return, label %use_block425 426early_return:427 ret i32 0428 429use_block:430 ret i32 %var3431}432 433; Version which only writes to var, and thus can't rely on may-read scan for434; clobbers to prevent the transform435define i32 @sink_lifetime4b(i1 %c) {436; CHECK-LABEL: @sink_lifetime4b(437; CHECK-NEXT: entry:438; CHECK-NEXT: [[VAR:%.*]] = alloca i32, align 4439; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[VAR]])440; CHECK-NEXT: [[VAR3:%.*]] = call i32 @unknown(ptr nonnull writeonly [[VAR]]) #[[ATTR1]]441; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[VAR]])442; CHECK-NEXT: br i1 [[C:%.*]], label [[EARLY_RETURN:%.*]], label [[USE_BLOCK:%.*]]443; CHECK: early_return:444; CHECK-NEXT: ret i32 0445; CHECK: use_block:446; CHECK-NEXT: ret i32 [[VAR3]]447;448entry:449 %var = alloca i32, align 4450 call void @llvm.lifetime.start.p0(ptr %var)451 %var3 = call i32 @unknown(ptr writeonly %var) argmemonly nounwind willreturn452 call void @llvm.lifetime.end.p0(ptr %var)453 br i1 %c, label %early_return, label %use_block454 455early_return:456 ret i32 0457 458use_block:459 ret i32 %var3460}461; Mostly checking that trying to sink a non-call doesn't crash (i.e. prior bug)462define i32 @sink_atomicrmw_to_use(i1 %c) {463; CHECK-LABEL: @sink_atomicrmw_to_use(464; CHECK-NEXT: entry:465; CHECK-NEXT: [[VAR:%.*]] = alloca i32, align 4466; CHECK-NEXT: store i32 0, ptr [[VAR]], align 4467; CHECK-NEXT: [[VAR3:%.*]] = atomicrmw add ptr [[VAR]], i32 1 seq_cst, align 4468; CHECK-NEXT: br i1 [[C:%.*]], label [[EARLY_RETURN:%.*]], label [[USE_BLOCK:%.*]]469; CHECK: early_return:470; CHECK-NEXT: ret i32 0471; CHECK: use_block:472; CHECK-NEXT: ret i32 [[VAR3]]473;474entry:475 %var = alloca i32, align 4476 store i32 0, ptr %var477 %var3 = atomicrmw add ptr %var, i32 1 seq_cst, align 4478 br i1 %c, label %early_return, label %use_block479 480early_return:481 ret i32 0482 483use_block:484 ret i32 %var3485}486 487 488declare i32 @bar()489declare void @llvm.lifetime.start.p0(ptr nocapture)490declare void @llvm.lifetime.end.p0(ptr nocapture)491 492