978 lines · plain
1; Test that llvm-reduce can move intermediate values by inserting2; early returns3;4; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=instructions-to-return --test FileCheck --test-arg --check-prefixes=CHECK,INTERESTING --test-arg %s --test-arg --input-file %s -o %t5; RUN: FileCheck --check-prefixes=CHECK,RESULT %s < %t6 7@gv = global i32 0, align 48@gv_struct = global { i32, float } zeroinitializer, align 49@gv_array = global [3 x i32] zeroinitializer, align 410@gv_empty_struct = global { } zeroinitializer, align 411 12; CHECK: @global.func.user = global ptr @store_instruction_to_return_with_uses13@global.func.user = global ptr @store_instruction_to_return_with_uses14 15; INTERESTING-LABEL: @store_instruction_to_return_with_uses(16; INTERESTING-NEXT: = load17 18; RESULT-LABEL: define i32 @store_instruction_to_return_with_uses(ptr %arg) {19; RESULT-NEXT: %load = load i32, ptr %arg, align 420; RESULT-NEXT: ret i32 %load21define void @store_instruction_to_return_with_uses(ptr %arg) {22 %load = load i32, ptr %arg23 store i32 %load, ptr @gv24 ret void25}26 27; INTERESTING-LABEL: define void @user(28; INTERESTING: call29 30; RESULT-LABEL: define void @user(31; RESULT-NEXT: call i32 @store_instruction_to_return_with_uses(ptr %a, ptr %b)32; RESULT-NEXT: ret void33; RESULT-NEXT: }34define void @user(ptr %a, ptr %b) {35 call void @store_instruction_to_return_with_uses(ptr %a, ptr %b)36 ret void37}38 39; INTERESTING-LABEL: @store_instruction_to_return_no_uses(40; INTERESTING: = load i3241 42; RESULT-LABEL: define i32 @store_instruction_to_return_no_uses(43; RESULT-NEXT: %load = load i3244; RESULT-NEXT: ret i32 %load45define void @store_instruction_to_return_no_uses(ptr %arg) {46 %load = load i32, ptr %arg47 store i32 %load, ptr @gv48 ret void49}50 51; INTERESTING-LABEL: @store_instruction_to_return_preserve_attrs(52; INTERESTING: = load53 54; RESULT: ; Function Attrs: nounwind55; RESULT-NEXT: define weak i32 @store_instruction_to_return_preserve_attrs(ptr byref(i32) %arg) #0 {56; RESULT-NEXT: %load = load i32, ptr %arg, align 457; RESULT-NEXT: ret i32 %load58define weak void @store_instruction_to_return_preserve_attrs(ptr byref(i32) %arg) nounwind "some-attr" {59 %load = load i32, ptr %arg60 store i32 %load, ptr @gv61 ret void62}63 64; INTERESTING-LABEL: @store_instruction_to_return_preserve_addrspace(65; INTERESTING: = load66 67; RESULT-LABEL: define i32 @store_instruction_to_return_preserve_addrspace(ptr %arg) addrspace(1) {68; RESULT-NEXT: %load = load i32, ptr %arg, align 469; RESULT-NEXT: ret i32 %load70define void @store_instruction_to_return_preserve_addrspace(ptr %arg) addrspace(1) {71 %load = load i32, ptr %arg72 store i32 %load, ptr @gv73 ret void74}75 76; INTERESTING-LABEL: @store_instruction_to_return_no_uses_unreachable(77; INTERESTING: = load78 79; RESULT-LABEL: define i32 @store_instruction_to_return_no_uses_unreachable(ptr %arg) {80; RESULT-NEXT: %load = load i32, ptr %arg, align 481; RESULT-NEXT: ret i32 %load82define void @store_instruction_to_return_no_uses_unreachable(ptr %arg) {83 %load = load i32, ptr %arg84 store i32 %load, ptr @gv85 unreachable86}87 88; INTERESTING-LABEL: @store_instruction_to_return_with_non_callee_use(89; INTERESTING: = load90 91; RESULT-LABEL: define i32 @store_instruction_to_return_with_non_callee_use(ptr %arg) {92; RESULT-NEXT: %load = load i32, ptr %arg, align 493; RESULT-NEXT: ret i32 %load94define void @store_instruction_to_return_with_non_callee_use(ptr %arg) {95 %load = load i32, ptr %arg96 store i32 %load, ptr @gv97 ret void98}99 100declare void @takes_fptr(ptr)101 102; CHECK: @non_callee_user(103; CHECK: ret void104define void @non_callee_user(ptr %a, ptr %b) {105 call void @takes_fptr(ptr @store_instruction_to_return_with_non_callee_use)106 ret void107}108 109declare i32 @convergent_call() convergent110 111; CHECK-LABEL: @no_return_token_def(112; CHECK: call token113; RESULT: ret void114define void @no_return_token_def(ptr %arg) convergent {115 %t = call token @llvm.experimental.convergence.entry()116 ret void117}118 119; INTERESTING-LABEL: @no_return_token_def_other(120; INTERESTING: call token121 122; RESULT-LABEL: define i32 @no_return_token_def_other(123; RESULT: call token124; RESULT: call i32125; RESULT: ret i32126define void @no_return_token_def_other(ptr %arg) convergent {127 %t = call token @llvm.experimental.convergence.entry()128 %call = call i32 @convergent_call() [ "convergencectrl"(token %t) ]129 store i32 %call, ptr @gv130 ret void131}132 133; INTERESTING-LABEL: @store_instruction_to_return_variadic_func(134; INTERESTING: = load135 136; RESULT-LABEL: define i32 @store_instruction_to_return_variadic_func(ptr %arg, ...)137; RESULT-NEXT: %load = load i32, ptr %arg, align 4138; RESULT-NEXT: ret i32 %load139define void @store_instruction_to_return_variadic_func(ptr %arg, ...) {140 %load = load i32, ptr %arg141 store i32 %load, ptr @gv142 ret void143}144 145; Has a callsite use that is invoking the function with a non-void146; return type, that does not match the new return type.147 148; INTERESTING-LABEL: @inst_to_return_has_nonvoid_wrong_type_caller(149 150; RESULT-LABEL: define void @inst_to_return_has_nonvoid_wrong_type_caller(151; RESULT-NEXT: %load = load i32, ptr %arg152; RESULT-NEXT: store i32 %load, ptr @gv153; RESULT-NEXT: ret void154define void @inst_to_return_has_nonvoid_wrong_type_caller(ptr %arg) {155 %load = load i32, ptr %arg156 store i32 %load, ptr @gv157 ret void158}159 160; INTERESTING-LABEL: @wrong_callsite_return_type(161 162; RESULT-LABEL: define i64 @wrong_callsite_return_type(163; RESULT-NEXT: %ret = call i64 @inst_to_return_has_nonvoid_wrong_type_caller(ptr %arg)164; RESULT-NEXT: ret i64 %ret165define i64 @wrong_callsite_return_type(ptr %arg) {166 %ret = call i64 @inst_to_return_has_nonvoid_wrong_type_caller(ptr %arg)167 ret i64 %ret168}169 170; INTERESTING-LABEL: @inst_to_return_already_has_new_type_caller(171 172; RESULT-LABEL: define i32 @inst_to_return_already_has_new_type_caller(173; RESULT-NEXT: %load = load i32, ptr %arg, align 4174; RESULT-NEXT: ret i32 %load175define void @inst_to_return_already_has_new_type_caller(ptr %arg) {176 %load = load i32, ptr %arg177 store i32 %load, ptr @gv178 ret void179}180 181; Callsite has UB signature mismatch, but the return type happens to182; match the new return type.183;184; INTERESTING-LABEL: @callsite_already_new_return_type(185 186; RESULT-LABEL: define i32 @callsite_already_new_return_type(187; RESULT-NEXT: %ret = call i32 @inst_to_return_already_has_new_type_caller(ptr %arg)188; RESULT-NEXT: ret i32 %ret189define i32 @callsite_already_new_return_type(ptr %arg) {190 %ret = call i32 @inst_to_return_already_has_new_type_caller(ptr %arg)191 ret i32 %ret192}193 194; INTERESTING-LABEL: @non_void_no_op(195; INTERESTING: = load196; INTERESTING: ret197 198; RESULT-LABEL: define ptr @non_void_no_op(199; RESULT-NEXT: %load = load i32, ptr %arg200; RESULT-NEXT: store i32 %load, ptr @gv201; RESULT-NEXT: ret ptr null202define ptr @non_void_no_op(ptr %arg) {203 %load = load i32, ptr %arg204 store i32 %load, ptr @gv205 ret ptr null206}207 208; INTERESTING-LABEL: @non_void_no_op_caller(209 210; RESULT-LABEL: define ptr @non_void_no_op_caller(ptr %arg) {211; RESULT-NEXT: %call = call ptr @non_void_no_op(ptr %arg)212; RESULT-NEXT: ret ptr %call213define ptr @non_void_no_op_caller(ptr %arg) {214 %call = call ptr @non_void_no_op(ptr %arg)215 ret ptr %call216}217 218; INTERESTING-LABEL: @non_void_same_type_use(219; INTERESTING: = load220; INTERESTING: ret221 222; RESULT-LABEL: define i32 @non_void_same_type_use(223; RESULT-NEXT: %load = load i32, ptr %arg224; RESULT-NEXT: ret i32 %load225define i32 @non_void_same_type_use(ptr %arg) {226 %load = load i32, ptr %arg227 store i32 %load, ptr @gv228 ret i32 0229}230 231; INTERESTING-LABEL: @non_void_bitcastable_type_use(232; INTERESTING: = load233; INTERESTING: ret234 235; RESULT-LABEL: define i32 @non_void_bitcastable_type_use(236; RESULT-NEXT: %load = load float, ptr %arg237; RESULT-NEXT: store float %load,238; RESULT-NEXT: ret i32 0239define i32 @non_void_bitcastable_type_use(ptr %arg) {240 %load = load float, ptr %arg241 store float %load, ptr @gv242 ret i32 0243}244 245; INTERESTING-LABEL: @non_void_bitcastable_type_use_caller(246define i32 @non_void_bitcastable_type_use_caller(ptr %arg) {247 %ret = call i32 @non_void_bitcastable_type_use(ptr %arg)248 ret i32 %ret249}250 251; INTERESTING-LABEL: @form_return_struct(252; INTERESTING: = load { i32, float }253 254; RESULT-LABEL: define { i32, float } @form_return_struct(ptr %arg) {255; RESULT-NEXT: %load = load { i32, float }, ptr %arg, align 4256; RESULT-NEXT: ret { i32, float } %load257define void @form_return_struct(ptr %arg) {258 %load = load { i32, float }, ptr %arg259 store { i32, float } %load, ptr @gv_struct260 ret void261}262 263; INTERESTING-LABEL: define void @return_struct_user(264; INTERESTING-NEXT: call265; RESULT: call { i32, float } @form_return_struct(ptr %arg)266define void @return_struct_user(ptr %arg) {267 call void @form_return_struct(ptr %arg)268 ret void269}270 271; INTERESTING-LABEL: @form_return_array(272; INTERESTING: = load273 274; RESULT-LABEL: define [3 x i32] @form_return_array(275; RESULT-NEXT: %load = load [3 x i32]276; RESULT-NEXT: ret [3 x i32] %load277define void @form_return_array(ptr %arg) {278 %load = load [3 x i32], ptr %arg279 store [3 x i32] %load, ptr @gv_array280 ret void281}282 283; CHECK-LABEL: @return_array_user(284; RESULT: call [3 x i32] @form_return_array(ptr %arg)285define void @return_array_user(ptr %arg) {286 call void @form_return_array(ptr %arg)287 ret void288}289 290; INTERESTING-LABEL: @form_return_empty_struct(291; INTERESTING: = load292 293; RESULT: define {} @form_return_empty_struct(294; RESULT-NEXT: %load = load {}295; RESULT-NEXT: ret {} %load296define void @form_return_empty_struct(ptr %arg) {297 %load = load { }, ptr %arg298 store { } %load, ptr @gv_empty_struct299 ret void300}301 302; CHECK-LABEL: define void @return_empty_struct_user(303; RESULT: call {} @form_return_empty_struct(ptr %arg)304define void @return_empty_struct_user(ptr %arg) {305 call void @form_return_empty_struct(ptr %arg)306 ret void307}308 309define target("sometarget.sometype") @target_type_func() {310 ret target("sometarget.sometype") poison311}312 313define void @target_type_user(target("sometarget.sometype") %a) {314 ret void315}316 317; INTERESTING-LABEL: @form_return_target_ty(318; INTERESTING: call target("sometarget.sometype") @target_type_func()319 320; RESULT: define target("sometarget.sometype") @form_return_target_ty(321; RESULT-NEXT: %call = call target("sometarget.sometype") @target_type_func()322; RESULT-NEXT: ret target("sometarget.sometype") %call323define void @form_return_target_ty(ptr %arg) {324 %call = call target("sometarget.sometype") @target_type_func()325 call void @target_type_user(target("sometarget.sometype") %call)326 ret void327}328 329; CHECK-LABEL: define void @return_target_ty_user(330; RESULT-NEXT: %1 = call target("sometarget.sometype") @form_return_target_ty(ptr %arg)331; RESULT-NEXT: ret void332define void @return_target_ty_user(ptr %arg) {333 call void @form_return_target_ty(ptr %arg)334 ret void335}336 337; Make sure an invalid reduction isn't attempted for a function with338; an sret argument339 340; CHECK-LABEL: @no_sret_nonvoid_return341define void @no_sret_nonvoid_return(ptr sret(i32) %out.sret, ptr %arg) {342 %load = load i32, ptr %arg343 store i32 %load, ptr %out.sret344 ret void345}346 347; Test a calling convention where it's illegal to use a non-void348; return. No invalid reduction should be introduced.349 350; INTERESTING-LABEL: @no_void_return_callingconv(351; INTERESTING: = load i32352 353; RESULT-LABEL: define amdgpu_kernel void @no_void_return_callingconv(354; RESULT-NEXT: %load = load i32355; RESULT-NEXT: store i32 %load356; RESULT-NEXT: ret void357define amdgpu_kernel void @no_void_return_callingconv(ptr %arg) {358 %load = load i32, ptr %arg359 store i32 %load, ptr @gv360 ret void361}362 363; INTERESTING-LABEL: @keep_first_of_3(364; INTERESTING: %load0 = load i32, ptr %arg0365; INTERESTING: ret366 367; RESULT-LABEL: define i32 @keep_first_of_3(368; RESULT-NEXT: %load0 = load i32, ptr %arg0, align 4369; RESULT-NEXT: ret i32 %load0370define void @keep_first_of_3(ptr %arg0, ptr %arg1, ptr %arg2) {371 %load0 = load i32, ptr %arg0372 %load1 = load i32, ptr %arg1373 %load2 = load i32, ptr %arg2374 store i32 %load0, ptr @gv375 store i32 %load1, ptr @gv376 store i32 %load2, ptr @gv377 ret void378}379 380; INTERESTING-LABEL: @keep_second_of_3(381; INTERESTING: %load1 = load i32, ptr %arg1382 383; RESULT-LABEL: define i32 @keep_second_of_3(384; RESULT-NEXT: %load0 = load i32, ptr %arg0385; RESULT-NEXT: %load1 = load i32, ptr %arg1386; RESULT-NEXT: ret i32 %load1387define void @keep_second_of_3(ptr %arg0, ptr %arg1, ptr %arg2) {388 %load0 = load i32, ptr %arg0389 %load1 = load i32, ptr %arg1390 %load2 = load i32, ptr %arg2391 store i32 %load0, ptr @gv392 store i32 %load1, ptr @gv393 store i32 %load2, ptr @gv394 ret void395}396 397; INTERESTING-LABEL: @keep_third_of_3(398; INTERESTING: %load2 = load i32, ptr %arg2399 400; RESULT-LABEL: define i32 @keep_third_of_3(401; RESULT-NEXT: %load0 = load i32, ptr %arg0, align 4402; RESULT-NEXT: %load1 = load i32, ptr %arg1, align 4403; RESULT-NEXT: %load2 = load i32, ptr %arg2, align 4404; RESULT-NEXT: ret i32 %load2405define void @keep_third_of_3(ptr %arg0, ptr %arg1, ptr %arg2) {406 %load0 = load i32, ptr %arg0407 %load1 = load i32, ptr %arg1408 %load2 = load i32, ptr %arg2409 store i32 %load0, ptr @gv410 store i32 %load1, ptr @gv411 store i32 %load2, ptr @gv412 ret void413}414 415; INTERESTING-LABEL: @keep_first_2_of_3(416; INTERESTING: %load0 = load i32, ptr %arg0417; INTERESTING: %load1 = load i32, ptr %arg1418 419; RESULT-LABEL: define i32 @keep_first_2_of_3(420; RESULT-NEXT: %load0 = load i32, ptr %arg0421; RESULT-NEXT: %load1 = load i32, ptr %arg1422; RESULT-NEXT: ret i32 %load1423define void @keep_first_2_of_3(ptr %arg0, ptr %arg1, ptr %arg2) {424 %load0 = load i32, ptr %arg0425 %load1 = load i32, ptr %arg1426 %load2 = load i32, ptr %arg2427 store i32 %load0, ptr @gv428 store i32 %load1, ptr @gv429 store i32 %load2, ptr @gv430 ret void431}432 433; INTERESTING-LABEL: @keep_second_of_3_already_ret_constexpr(434; INTERESTING: %load1 = load i32, ptr %arg1435; INTERESTING: ret436 437; RESULT-LABEL: define i32 @keep_second_of_3_already_ret_constexpr(438; RESULT-NEXT: %load0 = load i32, ptr %arg0, align 4439; RESULT-NEXT: %load1 = load i32, ptr %arg1, align 4440; RESULT-NEXT: ret i32 %load1441define i32 @keep_second_of_3_already_ret_constexpr(ptr %arg0, ptr %arg1, ptr %arg2) {442 %load0 = load i32, ptr %arg0443 %load1 = load i32, ptr %arg1444 %load2 = load i32, ptr %arg2445 store i32 %load0, ptr @gv446 store i32 %load1, ptr @gv447 store i32 %load2, ptr @gv448 ret i32 ptrtoint (ptr @gv to i32)449}450 451; INTERESTING-LABEL: @self_recursive(452; INTERESTING: %load = load i32, ptr %arg453 454; RESULT-LABEL: define i32 @self_recursive(455; RESULT-NEXT: %load = load i32, ptr %arg, align 4456; RESULT-NEXT: ret i32 %load457define void @self_recursive(ptr %arg) {458 %load = load i32, ptr %arg459 store i32 %load, ptr @gv460 call void @self_recursive(ptr %arg)461 ret void462}463 464; INTERESTING-LABEL: @has_invoke_user(465 466; RESULT-LABEL: define i32 @has_invoke_user(467; RESULT-NEXT: %load = load i32, ptr %arg, align 4468; RESULT-NEXT: ret i32 %load469define void @has_invoke_user(ptr %arg) {470 %load = load i32, ptr %arg471 store i32 %load, ptr @gv472 ret void473}474 475declare i32 @__gxx_personality_v0(...)476 477; INTERESTING-LABEL: @invoker(478; RESULT: %0 = invoke i32 @has_invoke_user(ptr %arg)479define void @invoker(ptr %arg) personality ptr @__gxx_personality_v0 {480bb:481 invoke void @has_invoke_user(ptr %arg)482 to label %bb3 unwind label %bb1483 484bb1:485 landingpad { ptr, i32 }486 catch ptr null487 br label %bb3488 489bb3:490 ret void491}492 493; INTERESTING-LABEL: @return_from_nonentry_block(494 495; RESULT-LABEL: define i32 @return_from_nonentry_block(496; RESULT: br i1 %arg0, label %bb0, label %bb1497 498; RESULT: bb0:499; RESULT-NEXT: %load = load i32, ptr %arg1, align 4500; RESULT-NEXT: ret i32 %load501 502; RESULT: bb1:503; RESULT-NEXT: unreachable504define void @return_from_nonentry_block(i1 %arg0, ptr %arg1) {505entry:506 br i1 %arg0, label %bb0, label %bb1507 508bb0:509 %load = load i32, ptr %arg1510 store i32 %load, ptr @gv511 ret void512 513bb1:514 unreachable515}516 517; INTERESTING-LABEL: @multi_void_return(518; INTERESTING: %load = load i32, ptr %arg1519 520; RESULT-LABEL: define i32 @multi_void_return(i1 %arg0, ptr %arg1) {521; RESULT-NEXT: entry:522; RESULT-NEXT: br i1 %arg0, label %bb0, label %bb1523 524; RESULT: bb0:525; RESULT-NEXT: %load = load i32, ptr %arg1526; RESULT-NEXT: ret i32 %load527 528; RESULT: bb1:529; RESULT-NEXT: ret i32 0530define void @multi_void_return(i1 %arg0, ptr %arg1) {531entry:532 br i1 %arg0, label %bb0, label %bb1533 534bb0:535 %load = load i32, ptr %arg1536 store i32 %load, ptr @gv537 ret void538 539bb1:540 ret void541}542 543; INTERESTING-LABEL: @multi_void_return_dominates_all(544; INTERESTING: %load = load i32, ptr %arg1545 546; RESULT-LABEL: define i32 @multi_void_return_dominates_all(547; RESULT-NEXT: entry:548; RESULT-NEXT: %load = load i32, ptr %arg1, align 4549; RESULT-NEXT: ret i32 %load550; RESULT-NEXT: }551define void @multi_void_return_dominates_all(i1 %arg0, ptr %arg1) {552entry:553 %load = load i32, ptr %arg1554 br i1 %arg0, label %bb0, label %bb1555 556bb0:557 store i32 %load, ptr @gv558 ret void559 560bb1:561 ret void562}563 564; INTERESTING-LABEL: @multi_unreachable_dominates_all(565; INTERESTING: %load = load i32, ptr %arg1566 567; RESULT-LABEL: define i32 @multi_unreachable_dominates_all(568; RESULT-NEXT: entry:569; RESULT-NEXT: %load = load i32, ptr %arg1, align 4570; RESULT-NEXT: ret i32 %load571; RESULT-NEXT: }572define void @multi_unreachable_dominates_all(i1 %arg0, ptr %arg1) {573entry:574 %load = load i32, ptr %arg1575 br i1 %arg0, label %bb0, label %bb1576 577bb0:578 store i32 %load, ptr @gv579 unreachable580 581bb1:582 unreachable583}584 585; We want to mutate %bb0 to return %load0, and not break the ret in586; %bb1587 588; INTERESTING-LABEL: @multi_nonvoid_return(589; INTERESTING: %other = load i32, ptr %arg2590; INTERESTING: br i1 %arg0591; INTERESTING: %load = load i32, ptr %arg1592 593 594; RESULT-LABEL: define i32 @multi_nonvoid_return(595 596; RESULT: entry:597; RESULT-NEXT: %other = load i32, ptr %arg2598; RESULT-NEXT: br i1 %arg0, label %bb0, label %bb1599 600; RESULT: bb0:601; RESULT-NEXT: %load = load i32, ptr %arg1, align 4602; RESULT-NEXT: ret i32 %load603 604; RESULT: bb1:605; RESULT-NEXT: ret i32 99606define i32 @multi_nonvoid_return(i1 %arg0, ptr %arg1, ptr %arg2) {607entry:608 %other = load i32, ptr %arg2609 br i1 %arg0, label %bb0, label %bb1610 611bb0:612 %load = load i32, ptr %arg1613 store i32 %load, ptr @gv614 ret i32 %other615 616bb1:617 ret i32 99618}619 620; TODO: Could handle this better if we avoided eliminating code that621; was already dead622 623; INTERESTING-LABEL: @interesting_in_unreachable_code(624; INTERESTING: %load = load i32, ptr %arg625 626; RESULT-LABEL: define void @interesting_in_unreachable_code(627; RESULT-NEXT: entry:628; RESULT-NEXT: ret void629 630; RESULT: bb: ; No predecessors!631; RESULT-NEXT: %load = load i32, ptr %arg, align 4632; RESULT-NEXT: store i32 %load,633; RESULT-NEXT: ret void634define void @interesting_in_unreachable_code(ptr %arg) {635entry:636 ret void637 638bb:639 %load = load i32, ptr %arg640 store i32 %load, ptr @gv641 ret void642}643 644; INTERESTING-LABEL: @use_in_successor_phi(645; INTERESTING: %load0 = load i32, ptr %arg1646 647; RESULT-LABEL: define i32 @use_in_successor_phi(648; RESULT-NEXT: entry:649; RESULT-NEXT: %load0 = load i32, ptr %arg1, align 4650; RESULT-NEXT: ret i32 %load0651; RESULT-NEXT: }652define void @use_in_successor_phi(i1 %arg0, ptr %arg1, ptr %arg2) {653entry:654 %load0 = load i32, ptr %arg1655 br i1 %arg0, label %bb0, label %bb1656 657bb0:658 %phi = phi i32 [ %load0, %entry ], [ %load1, %bb1 ]659 store i32 %phi, ptr @gv660 br label %bb2661 662bb1:663 %load1 = load i32, ptr %arg2664 br label %bb0665 666bb2:667 ret void668}669 670; INTERESTING-LABEL: @use_in_successor_phi_repeated(671; INTERESTING: %load0 = load i32, ptr %arg1672 673; RESULT-LABEL: define i32 @use_in_successor_phi_repeated(674; RESULT-NEXT: entry:675; RESULT-NEXT: %load0 = load i32, ptr %arg1, align 4676; RESULT-NEXT: ret i32 %load0677; RESULT-NEXT: }678define void @use_in_successor_phi_repeated(i1 %arg0, ptr %arg1, ptr %arg2, i32 %switch.val) {679entry:680 %load0 = load i32, ptr %arg1681 br i1 %arg0, label %bb0, label %bb1682 683bb0:684 %phi = phi i32 [ %load0, %entry ], [ %load1, %bb1 ], [ %load1, %bb1 ]685 store i32 %phi, ptr @gv686 br label %bb2687 688bb1:689 %load1 = load i32, ptr %arg2690 switch i32 %switch.val, label %bb2 [691 i32 1, label %bb0692 i32 2, label %bb0693 ]694 695bb2:696 ret void697}698 699; INTERESTING-LABEL: @replace_cond_br_with_ret(700; INTERESTING: %load0 = load i32, ptr %arg1701 702; RESULT-LABEL: define i32 @replace_cond_br_with_ret(703; RESULT-NEXT: entry:704; RESULT-NEXT: %load0 = load i32, ptr %arg1, align 4705; RESULT-NEXT: ret i32 %load0706define void @replace_cond_br_with_ret(i1 %arg0, ptr %arg1, ptr %arg2) {707entry:708 %load0 = load i32, ptr %arg1709 br i1 %arg0, label %bb0, label %bb1710 711bb0:712 store i32 %load0, ptr %arg2713 ret void714 715bb1:716 store i32 %load0, ptr %arg2717 ret void718}719 720; INTERESTING-LABEL: @replace_switch_with_ret(721; INTERESTING: %load0 = load i32, ptr %arg1722 723; RESULT-LABEL: define i32 @replace_switch_with_ret(724; RESULT-NEXT: entry:725; RESULT-NEXT: %load0 = load i32, ptr %arg1, align 4726; RESULT-NEXT: ret i32 %load0727; RESULT-NEXT: }728define void @replace_switch_with_ret(i32 %arg0, ptr %arg1, ptr %arg2) {729entry:730 %load0 = load i32, ptr %arg1731 switch i32 %arg0, label %bb2 [732 i32 1, label %bb0733 i32 2, label %bb1734 ]735 736bb0:737 store i32 9, ptr %arg2738 ret void739 740bb1:741 store i32 10, ptr %arg2742 unreachable743 744bb2:745 ret void746}747 748; INTERESTING-LABEL: @replace_uncond_br_with_ret(749; INTERESTING: %load0 = load i32, ptr %arg1750 751; RESULT-LABEL: define i32 @replace_uncond_br_with_ret(752; RESULT-NEXT: entry:753; RESULT: %load0 = load i32, ptr %arg1, align 4754; RESULT-NEXT: ret i32 %load0755; RESULT-NEXT: }756define void @replace_uncond_br_with_ret(i1 %arg0, ptr %arg1, ptr %arg2) {757entry:758 %load0 = load i32, ptr %arg1759 br label %bb0760 761bb0:762 store i32 %load0, ptr %arg2763 ret void764}765 766; INTERESTING-LABEL: @replace_uncond_br_with_ret_with_phi(767; INTERESTING: %load0 = load i32, ptr %arg1768 769; RESULT-LABEL: define i32 @replace_uncond_br_with_ret_with_phi(770; RESULT-NEXT: entry:771; RESULT-NEXT: %load0 = load i32, ptr %arg1772; RESULT-NEXT: ret i32 %load0773; RESULT-NEXT: }774define void @replace_uncond_br_with_ret_with_phi(i1 %arg0, ptr %arg1, ptr %arg2, ptr %arg3) {775entry:776 %load0 = load i32, ptr %arg1777 br label %bb0778 779bb0:780 %phi = phi i32 [ %load0, %entry ]781 store i32 %phi, ptr %arg2782 store i32 %load0, ptr %arg3783 ret void784}785 786; INTERESTING-LABEL: @use_tail_instr_in_successor_phi(787; INTERESTING: %load0 = load i32, ptr %arg1788 789; RESULT-LABEL: define i32 @use_tail_instr_in_successor_phi(790; RESULT-NEXT: entry:791; RESULT-NEXT: %load0 = load i32, ptr %arg1792; RESULT-NEXT: ret i32 %load0793; RESULT-NEXT: }794define void @use_tail_instr_in_successor_phi(i1 %arg0, ptr %arg1, ptr %arg2) {795entry:796 %load0 = load i32, ptr %arg1797 %load1 = load i32, ptr %arg2798 br i1 %arg0, label %bb0, label %bb1799 800bb0:801 %phi = phi i32 [ %load0, %entry ], [ %load1, %bb1 ]802 store i32 %phi, ptr @gv803 br label %bb2804 805bb1:806 br label %bb0807 808bb2:809 ret void810}811 812; INTERESTING-LABEL: @use_before_instr_in_successor_phi(813; INTERESTING: %load1 = load i32, ptr %arg2814 815; RESULT-LABEL: define i32 @use_before_instr_in_successor_phi(816; RESULT-NEXT: entry:817; RESULT-NEXT: %load0 = load i32, ptr %arg1818; RESULT-NEXT: %load1 = load i32, ptr %arg2819; RESULT-NEXT: ret i32 %load1820; RESULT-NEXT: }821define void @use_before_instr_in_successor_phi(i1 %arg0, ptr %arg1, ptr %arg2) {822entry:823 %load0 = load i32, ptr %arg1824 %load1 = load i32, ptr %arg2825 br i1 %arg0, label %bb0, label %bb1826 827bb0:828 %phi = phi i32 [ %load0, %entry ], [ %load1, %bb1 ]829 store i32 %phi, ptr @gv830 br label %bb2831 832bb1:833 br label %bb0834 835bb2:836 ret void837}838 839declare i32 @maybe_throwing_callee(i32)840declare void @thrown()841declare void @did_not_throw(i32)842 843; TODO: Handle invokes properly844; INTERESTING-LABEL @reduce_invoke_use(845; INTERESTING: call void @did_not_throw(i32 %invoke)846 847; RESULT-LABEL: define { ptr, i32 } @reduce_invoke_use(848 849; RESULT: %invoke = invoke i32 @maybe_throwing_callee850 851; RESULT: bb1: ; preds = %bb852; RESULT-NEXT: %landing = landingpad { ptr, i32 }853; RESULT-NEXT: catch ptr null854; RESULT-NEXT: ret { ptr, i32 } %landing855 856; RESULT: bb4: ; preds = %bb3857; RESULT-NEXT: ret { ptr, i32 } zeroinitializer858define void @reduce_invoke_use(i32 %arg) personality ptr @__gxx_personality_v0 {859bb:860 %invoke = invoke i32 @maybe_throwing_callee(i32 %arg)861 to label %bb3 unwind label %bb1862 863bb1: ; preds = %bb864 %landing = landingpad { ptr, i32 }865 catch ptr null866 call void @thrown()867 br label %bb4868 869bb3: ; preds = %bb870 call void @did_not_throw(i32 %invoke)871 br label %bb4872 873bb4: ; preds = %bb3, %bb1874 ret void875}876 877; We can replace the branch in %bb0 with a return, but bb2 will still878; be reachable after879 880; INTERESTING-LABEL: @successor_block_not_dead_after_ret(881; INTERESTING: %load0 = load i32, ptr %arg2882 883; RESULT-LABEL: define i32 @successor_block_not_dead_after_ret(884; RESULT: entry:885; RESULT-NEXT: br i1 %arg0, label %bb0, label %bb2886 887; RESULT: bb0: ; preds = %entry888; RESULT-NEXT: %load0 = load i32, ptr %arg2, align 4889; RESULT-NEXT: ret i32 %load0890 891; RESULT: bb2: ; preds = %entry892; RESULT-NEXT: %phi = phi i32 [ %arg4, %entry ]893; RESULT-NEXT: ret i32 %phi894; RESULT-NEXT: }895define void @successor_block_not_dead_after_ret(i1 %arg0, i1 %arg1, ptr %arg2, ptr %arg3, i32 %arg4, i32 %arg5) {896entry:897 br i1 %arg0, label %bb0, label %bb2898 899bb0:900 %load0 = load i32, ptr %arg2901 store i32 %load0, ptr @gv902 br i1 %arg1, label %bb1, label %bb2903 904bb1:905 %load1 = load i32, ptr %arg3906 store i32 %load1, ptr @gv907 br label %bb0908 909bb2:910 %phi = phi i32 [ %arg4, %entry ], [ %arg5, %bb0 ]911 store i32 %phi, ptr @gv912 ret void913}914 915; INTERESTING-LABEL: @successor_block_self_loop_phi(916; INTERESTING: %load0 = load i32, ptr %arg2917 918; RESULT-LABEL: define i32 @successor_block_self_loop_phi(919; RESULT: entry:920; RESULT-NEXT: br i1 %arg0, label %bb0, label %bb1921 922; RESULT: bb0: ; preds = %entry923; RESULT-NEXT: %phi = phi i32 [ 12, %entry ]924; RESULT-NEXT: %load0 = load i32, ptr %arg2, align 4925; RESULT-NEXT: ret i32 %load0926 927; RESULT: bb1: ; preds = %entry928; RESULT-NEXT: ret i32 0929; RESULT-NEXT: }930define void @successor_block_self_loop_phi(i1 %arg0, i1 %arg1, ptr %arg2) {931entry:932 br i1 %arg0, label %bb0, label %bb1933 934bb0:935 %phi = phi i32 [ 12, %entry ], [ %load0, %bb0 ]936 %load0 = load i32, ptr %arg2937 store i32 %phi, ptr @gv938 br i1 %arg1, label %bb0, label %bb1939 940bb1:941 ret void942}943 944; INTERESTING-LABEL: @successor_block_self_loop_phi_2(945; INTERESTING: %phi1 = phi i32946 947; RESULT-LABEL: define i32 @successor_block_self_loop_phi_2(948; RESULT: entry:949; RESULT-NEXT: %load0 = load i32, ptr %arg2950; RESULT-NEXT: br i1 %arg0, label %bb0, label %bb1951 952; RESULT: bb0: ; preds = %entry953; RESULT-NEXT: %phi0 = phi i32 [ 12, %entry ]954; RESULT-NEXT: %phi1 = phi i32 [ %arg4, %entry ]955; RESULT-NEXT: ret i32 %phi1956 957; RESULT-NOT: bb958 959; RESULT: bb1: ; preds = %entry960; RESULT-NEXT: ret i32 0961; RESULT-NEXT: }962define void @successor_block_self_loop_phi_2(i1 %arg0, i1 %arg1, ptr %arg2, ptr %arg3, i32 %arg4) {963entry:964 %load0 = load i32, ptr %arg2965 br i1 %arg0, label %bb0, label %bb1966 967bb0:968 %phi0 = phi i32 [ 12, %entry ], [ %load0, %bb0 ]969 %phi1 = phi i32 [ %arg4, %entry ], [ %load1, %bb0 ]970 %load1 = load i32, ptr %arg3971 store i32 %phi0, ptr @gv972 store i32 %phi1, ptr @gv973 br i1 %arg1, label %bb0, label %bb1974 975bb1:976 ret void977}978