1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt %s -callbrprepare -S -o - | FileCheck %s 3; RUN: opt %s -passes=callbr-prepare -S -o - | FileCheck %s 4 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 0 21; 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 0 33indirect: 34 %out3 = phi i32 [%out, %entry], [%out2, %direct] 35 ret i32 %out3 36} 37 38; Don't split edges unless they are critical, and callbr produces output, and 39; 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 42 48; CHECK: y: 49; CHECK-NEXT: ret i32 0 50; 51entry: 52 callbr void asm "", "!i"() 53 to label %x [label %y] 54 55x: 56 ret i32 42 57 58y: 59 ret i32 0 60} 61 62; Don't split edges unless they are critical, and callbr produces output, and 63; 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 update 66; 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 42 74; 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 42 84 85y: 86 ret i32 %0 87} 88 89; Don't split edges unless they are critical, and callbr produces output, and 90; 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 %y 109 110y: 111 %0 = phi i32 [ 0, %x ], [ 42, %entry ] 112 ret i32 %0 113} 114 115; Don't split edges unless they are critical, and callbr produces output, and 116; 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 42 127; 128entry: 129 %0 = callbr i32 asm "", "=r,!i"() to label %x [label %v] 130 131x: 132 br label %v 133 134v: 135 ret i32 42 136} 137 138; Don't split edges unless they are critical, and callbr produces output, and 139; 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 %y 161 162y: 163 %1 = phi i32 [ %0, %entry ], [ 42, %x ] 164 ret i32 %1 165} 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 it 169; 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 42 182; 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 %v 188 189w: 190 %0 = callbr i32 asm "", "=r,!i,!i"() 191 to label %x [label %v, label %v] 192 193x: 194 ret i32 42 195 196v: 197 %1 = phi i32 [%0, %w], [%0, %w], [undef, %entry] 198 ret i32 %1 199} 200 201; A more interessting case of @split_me1. Check that we still only split the 202; 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 42 215; 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 %v 221 222w: 223 %0 = callbr i32 asm "", "=r,!i,!i"() 224 to label %x [label %v, label %v] 225 226x: 227 ret i32 42 228 229v: 230 %1 = phi i32 [ %0, %w ], [ 42, %entry ], [ %0, %w ] 231 ret i32 %1 232} 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 %out 255 256y: 257 br label %out 258 259out: 260 ret i32 %0 261} 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 %out 282 283out: 284 ret i32 %0 285} 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 %out 308 309out: 310 ret i32 %0 311} 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 0 327; 328entry: 329 br label %loop 330loop: 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 0 335} 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 %0 354} 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 %1 374} 375 376; "The Devil's cross" (i.e. two asm goto with conflicting physreg constraints 377; 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.0 407} 408 409; Test the result of the callbr having multiple uses to avoid iterator 410; 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 42 418; 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 42 429 430y: 431 %1 = add nsw i32 %0, %0 432 ret i32 %1 433} 434