1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -S -passes=simplifycfg < %s | FileCheck %s 3 4declare void @foo() 5declare void @bar() 6declare void @use.i1(i1) 7declare void @use.i32(i32) 8 9define void @test_phi_simple(i1 %c) { 10; CHECK-LABEL: @test_phi_simple( 11; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] 12; CHECK: if: 13; CHECK-NEXT: call void @foo() 14; CHECK-NEXT: call void @foo() 15; CHECK-NEXT: br label [[JOIN2:%.*]] 16; CHECK: else: 17; CHECK-NEXT: call void @bar() 18; CHECK-NEXT: call void @bar() 19; CHECK-NEXT: br label [[JOIN2]] 20; CHECK: join2: 21; CHECK-NEXT: ret void 22; 23 br i1 %c, label %if, label %else 24 25if: 26 call void @foo() 27 br label %join 28 29else: 30 call void @bar() 31 br label %join 32 33join: 34 %c2 = phi i1 [ true, %if ], [ false, %else ] 35 br i1 %c2, label %if2, label %else2 36 37if2: 38 call void @foo() 39 br label %join2 40 41else2: 42 call void @bar() 43 br label %join2 44 45join2: 46 ret void 47} 48 49define void @test_phi_extra_use(i1 %c) { 50; CHECK-LABEL: @test_phi_extra_use( 51; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] 52; CHECK: if: 53; CHECK-NEXT: call void @foo() 54; CHECK-NEXT: call void @use.i1(i1 true) 55; CHECK-NEXT: call void @foo() 56; CHECK-NEXT: br label [[JOIN2:%.*]] 57; CHECK: else: 58; CHECK-NEXT: call void @bar() 59; CHECK-NEXT: call void @use.i1(i1 false) 60; CHECK-NEXT: call void @bar() 61; CHECK-NEXT: br label [[JOIN2]] 62; CHECK: join2: 63; CHECK-NEXT: ret void 64; 65 br i1 %c, label %if, label %else 66 67if: 68 call void @foo() 69 br label %join 70 71else: 72 call void @bar() 73 br label %join 74 75join: 76 %c2 = phi i1 [ true, %if ], [ false, %else ] 77 call void @use.i1(i1 %c2) 78 br i1 %c2, label %if2, label %else2 79 80if2: 81 call void @foo() 82 br label %join2 83 84else2: 85 call void @bar() 86 br label %join2 87 88join2: 89 ret void 90} 91 92define void @test_phi_extra_use_different_block(i1 %c) { 93; CHECK-LABEL: @test_phi_extra_use_different_block( 94; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] 95; CHECK: if: 96; CHECK-NEXT: call void @foo() 97; CHECK-NEXT: br label [[JOIN:%.*]] 98; CHECK: else: 99; CHECK-NEXT: call void @bar() 100; CHECK-NEXT: br label [[JOIN]] 101; CHECK: join: 102; CHECK-NEXT: [[C2:%.*]] = phi i1 [ true, [[IF]] ], [ false, [[ELSE]] ] 103; CHECK-NEXT: br i1 [[C2]], label [[IF2:%.*]], label [[ELSE2:%.*]] 104; CHECK: if2: 105; CHECK-NEXT: call void @use.i1(i1 [[C2]]) 106; CHECK-NEXT: call void @foo() 107; CHECK-NEXT: br label [[JOIN2:%.*]] 108; CHECK: else2: 109; CHECK-NEXT: call void @use.i1(i1 [[C2]]) 110; CHECK-NEXT: call void @bar() 111; CHECK-NEXT: br label [[JOIN2]] 112; CHECK: join2: 113; CHECK-NEXT: ret void 114; 115 br i1 %c, label %if, label %else 116 117if: 118 call void @foo() 119 br label %join 120 121else: 122 call void @bar() 123 br label %join 124 125join: 126 %c2 = phi i1 [ true, %if ], [ false, %else ] 127 br i1 %c2, label %if2, label %else2 128 129if2: 130 call void @use.i1(i1 %c2) 131 call void @foo() 132 br label %join2 133 134else2: 135 call void @use.i1(i1 %c2) 136 call void @bar() 137 br label %join2 138 139join2: 140 ret void 141} 142 143define void @test_same_cond_simple(i1 %c) { 144; CHECK-LABEL: @test_same_cond_simple( 145; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] 146; CHECK: if: 147; CHECK-NEXT: call void @foo() 148; CHECK-NEXT: br label [[JOIN:%.*]] 149; CHECK: else: 150; CHECK-NEXT: call void @bar() 151; CHECK-NEXT: br label [[JOIN]] 152; CHECK: join: 153; CHECK-NEXT: br i1 [[C]], label [[IF2:%.*]], label [[ELSE2:%.*]] 154; CHECK: if2: 155; CHECK-NEXT: call void @foo() 156; CHECK-NEXT: br label [[JOIN2:%.*]] 157; CHECK: else2: 158; CHECK-NEXT: call void @bar() 159; CHECK-NEXT: br label [[JOIN2]] 160; CHECK: join2: 161; CHECK-NEXT: ret void 162; 163 br i1 %c, label %if, label %else 164 165if: 166 call void @foo() 167 br label %join 168 169else: 170 call void @bar() 171 br label %join 172 173join: 174 br i1 %c, label %if2, label %else2 175 176if2: 177 call void @foo() 178 br label %join2 179 180else2: 181 call void @bar() 182 br label %join2 183 184join2: 185 ret void 186} 187 188define void @test_same_cond_extra_use(i1 %c) { 189; CHECK-LABEL: @test_same_cond_extra_use( 190; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] 191; CHECK: if: 192; CHECK-NEXT: call void @foo() 193; CHECK-NEXT: br label [[JOIN:%.*]] 194; CHECK: else: 195; CHECK-NEXT: call void @bar() 196; CHECK-NEXT: br label [[JOIN]] 197; CHECK: join: 198; CHECK-NEXT: call void @use.i1(i1 [[C]]) 199; CHECK-NEXT: br i1 [[C]], label [[IF2:%.*]], label [[ELSE2:%.*]] 200; CHECK: if2: 201; CHECK-NEXT: call void @foo() 202; CHECK-NEXT: br label [[JOIN2:%.*]] 203; CHECK: else2: 204; CHECK-NEXT: call void @bar() 205; CHECK-NEXT: br label [[JOIN2]] 206; CHECK: join2: 207; CHECK-NEXT: ret void 208; 209 br i1 %c, label %if, label %else 210 211if: 212 call void @foo() 213 br label %join 214 215else: 216 call void @bar() 217 br label %join 218 219join: 220 call void @use.i1(i1 %c) 221 br i1 %c, label %if2, label %else2 222 223if2: 224 call void @foo() 225 br label %join2 226 227else2: 228 call void @bar() 229 br label %join2 230 231join2: 232 ret void 233} 234 235define void @test_same_cond_extra_use_different_block(i1 %c) { 236; CHECK-LABEL: @test_same_cond_extra_use_different_block( 237; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] 238; CHECK: if: 239; CHECK-NEXT: call void @foo() 240; CHECK-NEXT: br label [[JOIN:%.*]] 241; CHECK: else: 242; CHECK-NEXT: call void @bar() 243; CHECK-NEXT: br label [[JOIN]] 244; CHECK: join: 245; CHECK-NEXT: br i1 [[C]], label [[IF2:%.*]], label [[ELSE2:%.*]] 246; CHECK: if2: 247; CHECK-NEXT: call void @use.i1(i1 [[C]]) 248; CHECK-NEXT: call void @foo() 249; CHECK-NEXT: br label [[JOIN2:%.*]] 250; CHECK: else2: 251; CHECK-NEXT: call void @use.i1(i1 [[C]]) 252; CHECK-NEXT: call void @bar() 253; CHECK-NEXT: br label [[JOIN2]] 254; CHECK: join2: 255; CHECK-NEXT: ret void 256; 257 br i1 %c, label %if, label %else 258 259if: 260 call void @foo() 261 br label %join 262 263else: 264 call void @bar() 265 br label %join 266 267join: 268 br i1 %c, label %if2, label %else2 269 270if2: 271 call void @use.i1(i1 %c) 272 call void @foo() 273 br label %join2 274 275else2: 276 call void @use.i1(i1 %c) 277 call void @bar() 278 br label %join2 279 280join2: 281 ret void 282} 283 284define void @test_multiple_threadable_preds_with_phi(i1 %cond1, i1 %cond2) { 285; CHECK-LABEL: @test_multiple_threadable_preds_with_phi( 286; CHECK-NEXT: br i1 [[COND1:%.*]], label [[IF1:%.*]], label [[IF2:%.*]] 287; CHECK: if1: 288; CHECK-NEXT: call void @foo() 289; CHECK-NEXT: br i1 [[COND2:%.*]], label [[IF3_CRITEDGE:%.*]], label [[EXIT:%.*]] 290; CHECK: if2: 291; CHECK-NEXT: call void @bar() 292; CHECK-NEXT: br i1 [[COND2]], label [[IF3_CRITEDGE]], label [[EXIT]] 293; CHECK: if3.critedge: 294; CHECK-NEXT: [[PHI_PH:%.*]] = phi i32 [ 2, [[IF2]] ], [ 1, [[IF1]] ] 295; CHECK-NEXT: call void @use.i32(i32 [[PHI_PH]]) 296; CHECK-NEXT: call void @foo() 297; CHECK-NEXT: br label [[EXIT]] 298; CHECK: exit: 299; CHECK-NEXT: ret void 300; 301 br i1 %cond1, label %if1, label %if2 302 303if1: 304 call void @foo() 305 br i1 %cond2, label %join, label %exit 306 307if2: 308 call void @bar() 309 br i1 %cond2, label %join, label %exit 310 311join: 312 %phi = phi i32 [ 1, %if1 ], [ 2, %if2 ] 313 call void @use.i32(i32 %phi) 314 br i1 %cond2, label %if3, label %exit 315 316if3: 317 call void @foo() 318 br label %exit 319 320exit: 321 ret void 322} 323 324; This test case used to infinite loop. 325 326define void @infloop(i1 %cmp.a, i1 %cmp.b, i1 %cmp.c) { 327; CHECK-LABEL: @infloop( 328; CHECK-NEXT: entry: 329; CHECK-NEXT: br label [[WHILE_COND:%.*]] 330; CHECK: while.cond: 331; CHECK-NEXT: br i1 [[CMP_A:%.*]], label [[FOR:%.*]], label [[WHILE_BODY_THREAD:%.*]] 332; CHECK: for.body: 333; CHECK-NEXT: br i1 [[CMP_B:%.*]], label [[WHILE_BODY:%.*]], label [[FOR_BODY:%.*]] 334; CHECK: for: 335; CHECK-NEXT: tail call void @foo() 336; CHECK-NEXT: br label [[FOR_BODY]] 337; CHECK: while.body: 338; CHECK-NEXT: br i1 [[CMP_C:%.*]], label [[C_EXIT:%.*]], label [[LAND:%.*]] 339; CHECK: while.body.thread: 340; CHECK-NEXT: br i1 [[CMP_C]], label [[WHILE_COND]], label [[LAND]] 341; CHECK: land: 342; CHECK-NEXT: tail call void @bar() 343; CHECK-NEXT: br label [[WHILE_COND]] 344; CHECK: c.exit: 345; CHECK-NEXT: br i1 [[CMP_A]], label [[FOR_D:%.*]], label [[WHILE_BODY_THREAD]] 346; CHECK: for.d: 347; CHECK-NEXT: ret void 348; 349entry: 350 br label %while.cond 351 352while.cond: ; preds = %land, %while.body.thread, %entry 353 br i1 %cmp.a, label %for, label %while.body.thread 354 355for.body: ; preds = %for, %for.body 356 br i1 %cmp.b, label %while.body, label %for.body 357 358for: ; preds = %while.cond 359 tail call void @foo() 360 br label %for.body 361 362while.body: ; preds = %for.body 363 br i1 %cmp.c, label %c.exit, label %land 364 365while.body.thread: ; preds = %c.exit, %while.cond 366 br i1 %cmp.c, label %while.cond, label %land 367 368land: ; preds = %while.body.thread, %while.body 369 tail call void @bar() 370 br label %while.cond 371 372c.exit: ; preds = %while.body 373 br i1 %cmp.a, label %for.d, label %while.cond 374 375for.d: ; preds = %c.exit 376 ret void 377} 378 379; A combination of "branch to common dest" and jump threading kept peeling 380; off loop iterations here. 381 382define void @infloop_pr56203(i1 %c1, i1 %c2) { 383; CHECK-LABEL: @infloop_pr56203( 384; CHECK-NEXT: entry: 385; CHECK-NEXT: br i1 [[C1:%.*]], label [[EXIT:%.*]], label [[IF:%.*]] 386; CHECK: if: 387; CHECK-NEXT: call void @foo() 388; CHECK-NEXT: [[C3:%.*]] = icmp eq i64 0, 0 389; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[C2:%.*]], [[C3]] 390; CHECK-NEXT: br i1 [[OR_COND]], label [[EXIT]], label [[LOOP_SPLIT:%.*]] 391; CHECK: loop: 392; CHECK-NEXT: [[C3_OLD:%.*]] = icmp eq i64 0, 0 393; CHECK-NEXT: br i1 [[C3_OLD]], label [[EXIT]], label [[LOOP_SPLIT]] 394; CHECK: loop.split: 395; CHECK-NEXT: br i1 [[C1]], label [[LOOP_LATCH:%.*]], label [[LOOP:%.*]] 396; CHECK: loop.latch: 397; CHECK-NEXT: call void @foo() 398; CHECK-NEXT: br label [[LOOP]] 399; CHECK: exit: 400; CHECK-NEXT: ret void 401; 402entry: 403 br i1 %c1, label %exit, label %if 404 405if: 406 call void @foo() 407 br i1 %c2, label %exit, label %loop 408 409loop: 410 %c3 = icmp eq i64 0, 0 411 br i1 %c3, label %exit, label %loop.split 412 413loop.split: 414 br i1 %c1, label %loop.latch, label %loop 415 416loop.latch: 417 call void @foo() 418 br label %loop 419 420exit: 421 ret void 422} 423 424define void @callbr() { 425; CHECK-LABEL: @callbr( 426; CHECK-NEXT: entry: 427; CHECK-NEXT: callbr void asm sideeffect "", "!i,~{dirflag},~{fpsr},~{flags}"() 428; CHECK-NEXT: to label [[IF_END:%.*]] [label %if.end] 429; CHECK: if.end: 430; CHECK-NEXT: ret void 431; 432entry: 433 callbr void asm sideeffect "", "!i,~{dirflag},~{fpsr},~{flags}"() 434 to label %join [label %target] 435 436target: 437 br label %join 438 439join: 440 %phi = phi i1 [ false, %target ], [ false, %entry ] 441 br i1 %phi, label %if.then, label %if.end 442 443if.then: 444 call void @foo() 445 br label %if.end 446 447if.end: 448 ret void 449} 450