434 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt %s -callbrprepare -S -o - | FileCheck %s3; RUN: opt %s -passes=callbr-prepare -S -o - | FileCheck %s4 5define i32 @test0() {6; CHECK-LABEL: @test0(7; CHECK-NEXT: entry:8; CHECK-NEXT: [[OUT:%.*]] = callbr i32 asm "# $0", "=r,!i"()9; CHECK-NEXT: to label [[DIRECT:%.*]] [label %entry.indirect_crit_edge]10; CHECK: entry.indirect_crit_edge:11; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.callbr.landingpad.i32(i32 [[OUT]])12; CHECK-NEXT: br label [[INDIRECT:%.*]]13; CHECK: direct:14; CHECK-NEXT: [[OUT2:%.*]] = callbr i32 asm "# $0", "=r,!i"()15; CHECK-NEXT: to label [[DIRECT2:%.*]] [label %direct.indirect_crit_edge]16; CHECK: direct.indirect_crit_edge:17; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.callbr.landingpad.i32(i32 [[OUT2]])18; CHECK-NEXT: br label [[INDIRECT]]19; CHECK: direct2:20; CHECK-NEXT: ret i32 021; CHECK: indirect:22; CHECK-NEXT: [[OUT3:%.*]] = phi i32 [ [[TMP0]], [[ENTRY_INDIRECT_CRIT_EDGE:%.*]] ], [ [[TMP1]], [[DIRECT_INDIRECT_CRIT_EDGE:%.*]] ]23; CHECK-NEXT: ret i32 [[OUT3]]24;25entry:26 %out = callbr i32 asm "# $0", "=r,!i"()27 to label %direct [label %indirect]28direct:29 %out2 = callbr i32 asm "# $0", "=r,!i"()30 to label %direct2 [label %indirect]31direct2:32 ret i32 033indirect:34 %out3 = phi i32 [%out, %entry], [%out2, %direct]35 ret i32 %out336}37 38; Don't split edges unless they are critical, and callbr produces output, and39; that output is used.40; Here we have none of the above.41define i32 @dont_split0() {42; CHECK-LABEL: @dont_split0(43; CHECK-NEXT: entry:44; CHECK-NEXT: callbr void asm "", "!i"()45; CHECK-NEXT: to label [[X:%.*]] [label %y]46; CHECK: x:47; CHECK-NEXT: ret i32 4248; CHECK: y:49; CHECK-NEXT: ret i32 050;51entry:52 callbr void asm "", "!i"()53 to label %x [label %y]54 55x:56 ret i32 4257 58y:59 ret i32 060}61 62; Don't split edges unless they are critical, and callbr produces output, and63; that output is used.64; Here we have output, but no critical edge.65; That said, we ought to insert a callbr landing pad intrinsic call and update66; to use the correct SSA value.67define i32 @dont_split1() {68; CHECK-LABEL: @dont_split1(69; CHECK-NEXT: entry:70; CHECK-NEXT: [[TMP0:%.*]] = callbr i32 asm "", "=r,!i"()71; CHECK-NEXT: to label [[X:%.*]] [label %y]72; CHECK: x:73; CHECK-NEXT: ret i32 4274; CHECK: y:75; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.callbr.landingpad.i32(i32 [[TMP0]])76; CHECK-NEXT: ret i32 [[TMP1]]77;78entry:79 %0 = callbr i32 asm "", "=r,!i"()80 to label %x [label %y]81 82x:83 ret i32 4284 85y:86 ret i32 %087}88 89; Don't split edges unless they are critical, and callbr produces output, and90; that output is used.91; Here we have a critical edge along an indirect branch, but no output.92define i32 @dont_split2() {93; CHECK-LABEL: @dont_split2(94; CHECK-NEXT: entry:95; CHECK-NEXT: callbr void asm "", "!i"()96; CHECK-NEXT: to label [[X:%.*]] [label %y]97; CHECK: x:98; CHECK-NEXT: br label [[Y:%.*]]99; CHECK: y:100; CHECK-NEXT: [[TMP0:%.*]] = phi i32 [ 0, [[X]] ], [ 42, [[ENTRY:%.*]] ]101; CHECK-NEXT: ret i32 [[TMP0]]102;103entry:104 callbr void asm "", "!i"()105 to label %x [label %y]106 107x:108 br label %y109 110y:111 %0 = phi i32 [ 0, %x ], [ 42, %entry ]112 ret i32 %0113}114 115; Don't split edges unless they are critical, and callbr produces output, and116; that output is used.117; Here we're missing a use.118define i32 @dont_split3() {119; CHECK-LABEL: @dont_split3(120; CHECK-NEXT: entry:121; CHECK-NEXT: [[TMP0:%.*]] = callbr i32 asm "", "=r,!i"()122; CHECK-NEXT: to label [[X:%.*]] [label %v]123; CHECK: x:124; CHECK-NEXT: br label [[V:%.*]]125; CHECK: v:126; CHECK-NEXT: ret i32 42127;128entry:129 %0 = callbr i32 asm "", "=r,!i"() to label %x [label %v]130 131x:132 br label %v133 134v:135 ret i32 42136}137 138; Don't split edges unless they are critical, and callbr produces output, and139; that output is used.140; Here we have output and a critical edge along an indirect branch.141define i32 @split_me0() {142; CHECK-LABEL: @split_me0(143; CHECK-NEXT: entry:144; CHECK-NEXT: [[TMP0:%.*]] = callbr i32 asm "", "=r,!i"()145; CHECK-NEXT: to label [[X:%.*]] [label %entry.y_crit_edge]146; CHECK: entry.y_crit_edge:147; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.callbr.landingpad.i32(i32 [[TMP0]])148; CHECK-NEXT: br label [[Y:%.*]]149; CHECK: x:150; CHECK-NEXT: br label [[Y]]151; CHECK: y:152; CHECK-NEXT: [[TMP2:%.*]] = phi i32 [ [[TMP1]], [[ENTRY_Y_CRIT_EDGE:%.*]] ], [ 42, [[X]] ]153; CHECK-NEXT: ret i32 [[TMP2]]154;155entry:156 %0 = callbr i32 asm "", "=r,!i"()157 to label %x [label %y]158 159x:160 br label %y161 162y:163 %1 = phi i32 [ %0, %entry ], [ 42, %x ]164 ret i32 %1165}166 167; Here we have output and a critical edge along an indirect branch.168; Ensure that if we repeat the indirect destination, that we only split it169; once.170define i32 @split_me1(i1 %z) {171; CHECK-LABEL: @split_me1(172; CHECK-NEXT: entry:173; CHECK-NEXT: br i1 [[Z:%.*]], label [[W:%.*]], label [[V:%.*]]174; CHECK: w:175; CHECK-NEXT: [[TMP0:%.*]] = callbr i32 asm "", "=r,!i,!i"()176; CHECK-NEXT: to label [[X:%.*]] [label [[W_V_CRIT_EDGE:%.*]], label %w.v_crit_edge]177; CHECK: w.v_crit_edge:178; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.callbr.landingpad.i32(i32 [[TMP0]])179; CHECK-NEXT: br label [[V]]180; CHECK: x:181; CHECK-NEXT: ret i32 42182; CHECK: v:183; CHECK-NEXT: [[TMP2:%.*]] = phi i32 [ [[TMP1]], [[W_V_CRIT_EDGE]] ], [ undef, [[ENTRY:%.*]] ]184; CHECK-NEXT: ret i32 [[TMP2]]185;186entry:187 br i1 %z, label %w, label %v188 189w:190 %0 = callbr i32 asm "", "=r,!i,!i"()191 to label %x [label %v, label %v]192 193x:194 ret i32 42195 196v:197 %1 = phi i32 [%0, %w], [%0, %w], [undef, %entry]198 ret i32 %1199}200 201; A more interessting case of @split_me1. Check that we still only split the202; critical edge from w to v once.203define i32 @split_me2(i1 %z) {204; CHECK-LABEL: @split_me2(205; CHECK-NEXT: entry:206; CHECK-NEXT: br i1 [[Z:%.*]], label [[W:%.*]], label [[V:%.*]]207; CHECK: w:208; CHECK-NEXT: [[TMP0:%.*]] = callbr i32 asm "", "=r,!i,!i"()209; CHECK-NEXT: to label [[X:%.*]] [label [[W_V_CRIT_EDGE:%.*]], label %w.v_crit_edge]210; CHECK: w.v_crit_edge:211; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.callbr.landingpad.i32(i32 [[TMP0]])212; CHECK-NEXT: br label [[V]]213; CHECK: x:214; CHECK-NEXT: ret i32 42215; CHECK: v:216; CHECK-NEXT: [[TMP2:%.*]] = phi i32 [ [[TMP1]], [[W_V_CRIT_EDGE]] ], [ 42, [[ENTRY:%.*]] ]217; CHECK-NEXT: ret i32 [[TMP2]]218;219entry:220 br i1 %z, label %w, label %v221 222w:223 %0 = callbr i32 asm "", "=r,!i,!i"()224 to label %x [label %v, label %v]225 226x:227 ret i32 42228 229v:230 %1 = phi i32 [ %0, %w ], [ 42, %entry ], [ %0, %w ]231 ret i32 %1232}233 234; Here we have a diamond with no phi.235define i32 @dont_split4() {236; CHECK-LABEL: @dont_split4(237; CHECK-NEXT: entry:238; CHECK-NEXT: [[TMP0:%.*]] = callbr i32 asm "", "=r,!i"()239; CHECK-NEXT: to label [[X:%.*]] [label %y]240; CHECK: x:241; CHECK-NEXT: br label [[OUT:%.*]]242; CHECK: y:243; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.callbr.landingpad.i32(i32 [[TMP0]])244; CHECK-NEXT: br label [[OUT]]245; CHECK: out:246; CHECK-NEXT: [[TMP2:%.*]] = phi i32 [ [[TMP1]], [[Y:%.*]] ], [ [[TMP0]], [[X]] ]247; CHECK-NEXT: ret i32 [[TMP2]]248;249entry:250 %0 = callbr i32 asm "", "=r,!i"()251 to label %x [label %y]252 253x:254 br label %out255 256y:257 br label %out258 259out:260 ret i32 %0261}262 263; Triangle with no phi.264define i32 @dont_split5() {265; CHECK-LABEL: @dont_split5(266; CHECK-NEXT: entry:267; CHECK-NEXT: [[TMP0:%.*]] = callbr i32 asm "", "=r,!i"()268; CHECK-NEXT: to label [[OUT:%.*]] [label %y]269; CHECK: y:270; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.callbr.landingpad.i32(i32 [[TMP0]])271; CHECK-NEXT: br label [[OUT]]272; CHECK: out:273; CHECK-NEXT: [[TMP2:%.*]] = phi i32 [ [[TMP1]], [[Y:%.*]] ], [ [[TMP0]], [[ENTRY:%.*]] ]274; CHECK-NEXT: ret i32 [[TMP2]]275;276entry:277 %0 = callbr i32 asm "", "=r,!i"()278 to label %out [label %y]279 280y:281 br label %out282 283out:284 ret i32 %0285}286 287; Triangle the other way with no phi.288define i32 @split_me3() {289; CHECK-LABEL: @split_me3(290; CHECK-NEXT: entry:291; CHECK-NEXT: [[TMP0:%.*]] = callbr i32 asm "", "=r,!i"()292; CHECK-NEXT: to label [[Y:%.*]] [label %entry.out_crit_edge]293; CHECK: entry.out_crit_edge:294; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.callbr.landingpad.i32(i32 [[TMP0]])295; CHECK-NEXT: br label [[OUT:%.*]]296; CHECK: y:297; CHECK-NEXT: br label [[OUT]]298; CHECK: out:299; CHECK-NEXT: [[TMP2:%.*]] = phi i32 [ [[TMP1]], [[ENTRY_OUT_CRIT_EDGE:%.*]] ], [ [[TMP0]], [[Y]] ]300; CHECK-NEXT: ret i32 [[TMP2]]301;302entry:303 %0 = callbr i32 asm "", "=r,!i"()304 to label %y [label %out]305 306y:307 br label %out308 309out:310 ret i32 %0311}312 313; Test callbr looping back on itself.314define i32 @dont_split6(i32 %0) {315; CHECK-LABEL: @dont_split6(316; CHECK-NEXT: entry:317; CHECK-NEXT: br label [[LOOP:%.*]]318; CHECK: loop:319; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ [[TMP0:%.*]], [[ENTRY:%.*]] ], [ [[TMP3:%.*]], [[LOOP_LOOP_CRIT_EDGE:%.*]] ]320; CHECK-NEXT: [[TMP2:%.*]] = callbr i32 asm "", "=r,0,!i"(i32 [[TMP1]])321; CHECK-NEXT: to label [[EXIT:%.*]] [label %loop.loop_crit_edge]322; CHECK: loop.loop_crit_edge:323; CHECK-NEXT: [[TMP3]] = call i32 @llvm.callbr.landingpad.i32(i32 [[TMP2]])324; CHECK-NEXT: br label [[LOOP]]325; CHECK: exit:326; CHECK-NEXT: ret i32 0327;328entry:329 br label %loop330loop:331 %1 = phi i32 [%0, %entry], [%2, %loop]332 %2 = callbr i32 asm "", "=r,0,!i"(i32 %1) to label %exit [label %loop]333exit:334 ret i32 0335}336 337; Test same direct+indirect dest no phi.338define i32 @split_me4() {339; CHECK-LABEL: @split_me4(340; CHECK-NEXT: entry:341; CHECK-NEXT: [[TMP0:%.*]] = callbr i32 asm "", "=r,!i"()342; CHECK-NEXT: to label [[SAME:%.*]] [label %entry.same_crit_edge]343; CHECK: entry.same_crit_edge:344; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.callbr.landingpad.i32(i32 [[TMP0]])345; CHECK-NEXT: br label [[SAME]]346; CHECK: same:347; CHECK-NEXT: [[TMP2:%.*]] = phi i32 [ [[TMP1]], [[ENTRY_SAME_CRIT_EDGE:%.*]] ], [ [[TMP0]], [[ENTRY:%.*]] ]348; CHECK-NEXT: ret i32 [[TMP2]]349;350entry:351 %0 = callbr i32 asm "", "=r,!i"() to label %same [label %same]352same:353 ret i32 %0354}355 356; Test same direct+indirect dest w/ phi.357define i32 @split_me5() {358; CHECK-LABEL: @split_me5(359; CHECK-NEXT: entry:360; CHECK-NEXT: [[TMP0:%.*]] = callbr i32 asm "", "=r,!i"()361; CHECK-NEXT: to label [[SAME:%.*]] [label %entry.same_crit_edge]362; CHECK: entry.same_crit_edge:363; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.callbr.landingpad.i32(i32 [[TMP0]])364; CHECK-NEXT: br label [[SAME]]365; CHECK: same:366; CHECK-NEXT: [[TMP2:%.*]] = phi i32 [ [[TMP1]], [[ENTRY_SAME_CRIT_EDGE:%.*]] ], [ [[TMP0]], [[ENTRY:%.*]] ]367; CHECK-NEXT: ret i32 [[TMP2]]368;369entry:370 %0 = callbr i32 asm "", "=r,!i"() to label %same [label %same]371same:372 %1 = phi i32 [%0, %entry], [%0, %entry]373 ret i32 %1374}375 376; "The Devil's cross" (i.e. two asm goto with conflicting physreg constraints377; going to the same destination).378define i64 @split_me6() {379; CHECK-LABEL: @split_me6(380; CHECK-NEXT: entry:381; CHECK-NEXT: [[TMP0:%.*]] = callbr i64 asm "# $0 $1", "={dx},!i"()382; CHECK-NEXT: to label [[ASM_FALLTHROUGH:%.*]] [label %entry.foo_crit_edge]383; CHECK: entry.foo_crit_edge:384; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.callbr.landingpad.i64(i64 [[TMP0]])385; CHECK-NEXT: br label [[FOO:%.*]]386; CHECK: asm.fallthrough:387; CHECK-NEXT: [[TMP2:%.*]] = callbr i64 asm "# $0 $1", "={bx},!i"()388; CHECK-NEXT: to label [[FOO]] [label %asm.fallthrough.foo_crit_edge]389; CHECK: asm.fallthrough.foo_crit_edge:390; CHECK-NEXT: [[TMP3:%.*]] = call i64 @llvm.callbr.landingpad.i64(i64 [[TMP2]])391; CHECK-NEXT: br label [[FOO]]392; CHECK: foo:393; CHECK-NEXT: [[X_0:%.*]] = phi i64 [ [[TMP1]], [[ENTRY_FOO_CRIT_EDGE:%.*]] ], [ [[TMP3]], [[ASM_FALLTHROUGH_FOO_CRIT_EDGE:%.*]] ], [ [[TMP2]], [[ASM_FALLTHROUGH]] ]394; CHECK-NEXT: ret i64 [[X_0]]395;396entry:397 %0 = callbr i64 asm "# $0 $1", "={dx},!i"()398 to label %asm.fallthrough [label %foo]399 400asm.fallthrough:401 %1 = callbr i64 asm "# $0 $1", "={bx},!i"()402 to label %foo [label %foo]403 404foo:405 %x.0 = phi i64 [ %0, %entry ], [ %1, %asm.fallthrough ], [ %1, %asm.fallthrough ]406 ret i64 %x.0407}408 409; Test the result of the callbr having multiple uses to avoid iterator410; invalidation bugs in CallBrPrepare::UpdateSSA.411define i32 @multiple_split() {412; CHECK-LABEL: @multiple_split(413; CHECK-NEXT: entry:414; CHECK-NEXT: [[TMP0:%.*]] = callbr i32 asm "", "=r,!i"()415; CHECK-NEXT: to label [[X:%.*]] [label %y]416; CHECK: x:417; CHECK-NEXT: ret i32 42418; CHECK: y:419; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.callbr.landingpad.i32(i32 [[TMP0]])420; CHECK-NEXT: [[TMP2:%.*]] = add nsw i32 [[TMP1]], [[TMP1]]421; CHECK-NEXT: ret i32 [[TMP2]]422;423entry:424 %0 = callbr i32 asm "", "=r,!i"()425 to label %x [label %y]426 427x:428 ret i32 42429 430y:431 %1 = add nsw i32 %0, %0432 ret i32 %1433}434