1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -S -simplifycfg -bonus-inst-threshold=10 | FileCheck %s 3 4declare void @sideeffect0() 5declare void @sideeffect1() 6declare void @sideeffect2() 7declare void @use8(i8) 8 9; Basic cases, blocks have nothing other than the comparison itself. 10 11define void @one_pred(i8 %v0, i8 %v1) { 12; CHECK-LABEL: @one_pred( 13; CHECK-NEXT: pred: 14; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0 15; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0 16; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C0]], [[C1]] 17; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]] 18; CHECK: final_left: 19; CHECK-NEXT: call void @sideeffect0() 20; CHECK-NEXT: ret void 21; CHECK: final_right: 22; CHECK-NEXT: call void @sideeffect1() 23; CHECK-NEXT: ret void 24; 25pred: 26 %c0 = icmp eq i8 %v0, 0 27 br i1 %c0, label %dispatch, label %final_right 28dispatch: 29 %c1 = icmp eq i8 %v1, 0 30 br i1 %c1, label %final_left, label %final_right 31final_left: 32 call void @sideeffect0() 33 ret void 34final_right: 35 call void @sideeffect1() 36 ret void 37} 38 39define void @two_preds(i8 %v0, i8 %v1, i8 %v2, i8 %v3) { 40; CHECK-LABEL: @two_preds( 41; CHECK-NEXT: entry: 42; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0 43; CHECK-NEXT: br i1 [[C0]], label [[PRED0:%.*]], label [[PRED1:%.*]] 44; CHECK: pred0: 45; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0 46; CHECK-NEXT: [[DOTOLD:%.*]] = icmp eq i8 [[V3:%.*]], 0 47; CHECK-NEXT: [[OR_COND2:%.*]] = or i1 [[C1]], [[DOTOLD]] 48; CHECK-NEXT: br i1 [[OR_COND2]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]] 49; CHECK: pred1: 50; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V2:%.*]], 0 51; CHECK-NEXT: [[C3:%.*]] = icmp eq i8 [[V3]], 0 52; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C2]], [[C3]] 53; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]] 54; CHECK: final_left: 55; CHECK-NEXT: call void @sideeffect0() 56; CHECK-NEXT: ret void 57; CHECK: final_right: 58; CHECK-NEXT: call void @sideeffect1() 59; CHECK-NEXT: ret void 60; 61entry: 62 %c0 = icmp eq i8 %v0, 0 63 br i1 %c0, label %pred0, label %pred1 64pred0: 65 %c1 = icmp eq i8 %v1, 0 66 br i1 %c1, label %final_left, label %dispatch 67pred1: 68 %c2 = icmp eq i8 %v2, 0 69 br i1 %c2, label %dispatch, label %final_right 70dispatch: 71 %c3 = icmp eq i8 %v3, 0 72 br i1 %c3, label %final_left, label %final_right 73final_left: 74 call void @sideeffect0() 75 ret void 76final_right: 77 call void @sideeffect1() 78 ret void 79} 80 81; More complex case, there's an extra op that is safe to execute unconditionally. 82 83define void @one_pred_with_extra_op(i8 %v0, i8 %v1) { 84; CHECK-LABEL: @one_pred_with_extra_op( 85; CHECK-NEXT: pred: 86; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0 87; CHECK-NEXT: [[V1_ADJ:%.*]] = add i8 [[V0]], [[V1:%.*]] 88; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1_ADJ]], 0 89; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C0]], [[C1]] 90; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]] 91; CHECK: final_left: 92; CHECK-NEXT: call void @sideeffect0() 93; CHECK-NEXT: ret void 94; CHECK: final_right: 95; CHECK-NEXT: call void @sideeffect1() 96; CHECK-NEXT: ret void 97; 98pred: 99 %c0 = icmp eq i8 %v0, 0 100 br i1 %c0, label %dispatch, label %final_right 101dispatch: 102 %v1_adj = add i8 %v0, %v1 103 %c1 = icmp eq i8 %v1_adj, 0 104 br i1 %c1, label %final_left, label %final_right 105final_left: 106 call void @sideeffect0() 107 ret void 108final_right: 109 call void @sideeffect1() 110 ret void 111} 112 113define void @two_preds_with_extra_op(i8 %v0, i8 %v1, i8 %v2, i8 %v3) { 114; CHECK-LABEL: @two_preds_with_extra_op( 115; CHECK-NEXT: entry: 116; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0 117; CHECK-NEXT: br i1 [[C0]], label [[PRED0:%.*]], label [[PRED1:%.*]] 118; CHECK: pred0: 119; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0 120; CHECK-NEXT: [[DOTOLD:%.*]] = add i8 [[V1]], [[V2:%.*]] 121; CHECK-NEXT: [[DOTOLD1:%.*]] = icmp eq i8 [[DOTOLD]], 0 122; CHECK-NEXT: [[OR_COND4:%.*]] = or i1 [[C1]], [[DOTOLD1]] 123; CHECK-NEXT: br i1 [[OR_COND4]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]] 124; CHECK: pred1: 125; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V2]], 0 126; CHECK-NEXT: [[V3_ADJ:%.*]] = add i8 [[V1]], [[V2]] 127; CHECK-NEXT: [[C3:%.*]] = icmp eq i8 [[V3_ADJ]], 0 128; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C2]], [[C3]] 129; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]] 130; CHECK: final_left: 131; CHECK-NEXT: call void @sideeffect0() 132; CHECK-NEXT: ret void 133; CHECK: final_right: 134; CHECK-NEXT: call void @sideeffect1() 135; CHECK-NEXT: ret void 136; 137entry: 138 %c0 = icmp eq i8 %v0, 0 139 br i1 %c0, label %pred0, label %pred1 140pred0: 141 %c1 = icmp eq i8 %v1, 0 142 br i1 %c1, label %final_left, label %dispatch 143pred1: 144 %c2 = icmp eq i8 %v2, 0 145 br i1 %c2, label %dispatch, label %final_right 146dispatch: 147 %v3_adj = add i8 %v1, %v2 148 %c3 = icmp eq i8 %v3_adj, 0 149 br i1 %c3, label %final_left, label %final_right 150final_left: 151 call void @sideeffect0() 152 ret void 153final_right: 154 call void @sideeffect1() 155 ret void 156} 157 158; More complex case, there's an extra op that is safe to execute unconditionally, and it has multiple uses. 159 160define void @one_pred_with_extra_op_multiuse(i8 %v0, i8 %v1) { 161; CHECK-LABEL: @one_pred_with_extra_op_multiuse( 162; CHECK-NEXT: pred: 163; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0 164; CHECK-NEXT: [[V1_ADJ:%.*]] = add i8 [[V0]], [[V1:%.*]] 165; CHECK-NEXT: [[V1_ADJ_ADJ:%.*]] = add i8 [[V1_ADJ]], [[V1_ADJ]] 166; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1_ADJ_ADJ]], 0 167; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C0]], [[C1]] 168; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]] 169; CHECK: final_left: 170; CHECK-NEXT: call void @sideeffect0() 171; CHECK-NEXT: ret void 172; CHECK: final_right: 173; CHECK-NEXT: call void @sideeffect1() 174; CHECK-NEXT: ret void 175; 176pred: 177 %c0 = icmp eq i8 %v0, 0 178 br i1 %c0, label %dispatch, label %final_right 179dispatch: 180 %v1_adj = add i8 %v0, %v1 181 %v1_adj_adj = add i8 %v1_adj, %v1_adj 182 %c1 = icmp eq i8 %v1_adj_adj, 0 183 br i1 %c1, label %final_left, label %final_right 184final_left: 185 call void @sideeffect0() 186 ret void 187final_right: 188 call void @sideeffect1() 189 ret void 190} 191 192define void @two_preds_with_extra_op_multiuse(i8 %v0, i8 %v1, i8 %v2, i8 %v3) { 193; CHECK-LABEL: @two_preds_with_extra_op_multiuse( 194; CHECK-NEXT: entry: 195; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0 196; CHECK-NEXT: br i1 [[C0]], label [[PRED0:%.*]], label [[PRED1:%.*]] 197; CHECK: pred0: 198; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0 199; CHECK-NEXT: [[DOTOLD:%.*]] = add i8 [[V1]], [[V2:%.*]] 200; CHECK-NEXT: [[DOTOLD1:%.*]] = add i8 [[DOTOLD]], [[DOTOLD]] 201; CHECK-NEXT: [[DOTOLD2:%.*]] = icmp eq i8 [[DOTOLD1]], 0 202; CHECK-NEXT: [[OR_COND6:%.*]] = or i1 [[C1]], [[DOTOLD2]] 203; CHECK-NEXT: br i1 [[OR_COND6]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]] 204; CHECK: pred1: 205; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V2]], 0 206; CHECK-NEXT: [[V3_ADJ:%.*]] = add i8 [[V1]], [[V2]] 207; CHECK-NEXT: [[V3_ADJ_ADJ:%.*]] = add i8 [[V3_ADJ]], [[V3_ADJ]] 208; CHECK-NEXT: [[C3:%.*]] = icmp eq i8 [[V3_ADJ_ADJ]], 0 209; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C2]], [[C3]] 210; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]] 211; CHECK: final_left: 212; CHECK-NEXT: call void @sideeffect0() 213; CHECK-NEXT: ret void 214; CHECK: final_right: 215; CHECK-NEXT: call void @sideeffect1() 216; CHECK-NEXT: ret void 217; 218entry: 219 %c0 = icmp eq i8 %v0, 0 220 br i1 %c0, label %pred0, label %pred1 221pred0: 222 %c1 = icmp eq i8 %v1, 0 223 br i1 %c1, label %final_left, label %dispatch 224pred1: 225 %c2 = icmp eq i8 %v2, 0 226 br i1 %c2, label %dispatch, label %final_right 227dispatch: 228 %v3_adj = add i8 %v1, %v2 229 %v3_adj_adj = add i8 %v3_adj, %v3_adj 230 %c3 = icmp eq i8 %v3_adj_adj, 0 231 br i1 %c3, label %final_left, label %final_right 232final_left: 233 call void @sideeffect0() 234 ret void 235final_right: 236 call void @sideeffect1() 237 ret void 238} 239 240; More complex case, there's an op that is safe to execute unconditionally, 241; and said op is live-out. 242 243define void @one_pred_with_extra_op_liveout(i8 %v0, i8 %v1) { 244; CHECK-LABEL: @one_pred_with_extra_op_liveout( 245; CHECK-NEXT: pred: 246; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0 247; CHECK-NEXT: [[V1_ADJ:%.*]] = add i8 [[V0]], [[V1:%.*]] 248; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1_ADJ]], 0 249; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C0]], [[C1]] 250; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]] 251; CHECK: final_left: 252; CHECK-NEXT: call void @sideeffect0() 253; CHECK-NEXT: call void @use8(i8 [[V1_ADJ]]) 254; CHECK-NEXT: ret void 255; CHECK: final_right: 256; CHECK-NEXT: call void @sideeffect1() 257; CHECK-NEXT: ret void 258; 259pred: 260 %c0 = icmp eq i8 %v0, 0 261 br i1 %c0, label %dispatch, label %final_right 262dispatch: 263 %v1_adj = add i8 %v0, %v1 264 %c1 = icmp eq i8 %v1_adj, 0 265 br i1 %c1, label %final_left, label %final_right 266final_left: 267 call void @sideeffect0() 268 call void @use8(i8 %v1_adj) 269 ret void 270final_right: 271 call void @sideeffect1() 272 ret void 273} 274define void @one_pred_with_extra_op_liveout_multiuse(i8 %v0, i8 %v1) { 275; CHECK-LABEL: @one_pred_with_extra_op_liveout_multiuse( 276; CHECK-NEXT: pred: 277; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0 278; CHECK-NEXT: [[V1_ADJ:%.*]] = add i8 [[V0]], [[V1:%.*]] 279; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1_ADJ]], 0 280; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C0]], [[C1]] 281; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]] 282; CHECK: final_left: 283; CHECK-NEXT: call void @sideeffect0() 284; CHECK-NEXT: call void @use8(i8 [[V1_ADJ]]) 285; CHECK-NEXT: call void @use8(i8 [[V1_ADJ]]) 286; CHECK-NEXT: ret void 287; CHECK: final_right: 288; CHECK-NEXT: call void @sideeffect1() 289; CHECK-NEXT: ret void 290; 291pred: 292 %c0 = icmp eq i8 %v0, 0 293 br i1 %c0, label %dispatch, label %final_right 294dispatch: 295 %v1_adj = add i8 %v0, %v1 296 %c1 = icmp eq i8 %v1_adj, 0 297 br i1 %c1, label %final_left, label %final_right 298final_left: 299 call void @sideeffect0() 300 call void @use8(i8 %v1_adj) 301 call void @use8(i8 %v1_adj) 302 ret void 303final_right: 304 call void @sideeffect1() 305 ret void 306} 307 308define void @one_pred_with_extra_op_liveout_distant_phi(i8 %v0, i8 %v1) { 309; CHECK-LABEL: @one_pred_with_extra_op_liveout_distant_phi( 310; CHECK-NEXT: entry: 311; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0 312; CHECK-NEXT: br i1 [[C0]], label [[PRED:%.*]], label [[LEFT_END:%.*]] 313; CHECK: pred: 314; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0 315; CHECK-NEXT: [[V2_ADJ:%.*]] = add i8 [[V0]], [[V1]] 316; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V2_ADJ]], 0 317; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C1]], [[C2]] 318; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]] 319; CHECK: final_left: 320; CHECK-NEXT: call void @sideeffect0() 321; CHECK-NEXT: call void @use8(i8 [[V2_ADJ]]) 322; CHECK-NEXT: br label [[LEFT_END]] 323; CHECK: left_end: 324; CHECK-NEXT: [[MERGE_LEFT:%.*]] = phi i8 [ [[V2_ADJ]], [[FINAL_LEFT]] ], [ 0, [[ENTRY:%.*]] ] 325; CHECK-NEXT: call void @sideeffect1() 326; CHECK-NEXT: call void @use8(i8 [[MERGE_LEFT]]) 327; CHECK-NEXT: ret void 328; CHECK: final_right: 329; CHECK-NEXT: call void @sideeffect2() 330; CHECK-NEXT: ret void 331; 332entry: 333 %c0 = icmp eq i8 %v0, 0 334 br i1 %c0, label %pred, label %left_end 335pred: 336 %c1 = icmp eq i8 %v1, 0 337 br i1 %c1, label %dispatch, label %final_right 338dispatch: 339 %v2_adj = add i8 %v0, %v1 340 %c2 = icmp eq i8 %v2_adj, 0 341 br i1 %c2, label %final_left, label %final_right 342final_left: 343 call void @sideeffect0() 344 call void @use8(i8 %v2_adj) 345 br label %left_end 346left_end: 347 %merge_left = phi i8 [ %v2_adj, %final_left ], [ 0, %entry ] 348 call void @sideeffect1() 349 call void @use8(i8 %merge_left) 350 ret void 351final_right: 352 call void @sideeffect2() 353 ret void 354} 355 356define void @two_preds_with_extra_op_liveout(i8 %v0, i8 %v1, i8 %v2, i8 %v3) { 357; CHECK-LABEL: @two_preds_with_extra_op_liveout( 358; CHECK-NEXT: entry: 359; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0 360; CHECK-NEXT: br i1 [[C0]], label [[PRED0:%.*]], label [[PRED1:%.*]] 361; CHECK: pred0: 362; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0 363; CHECK-NEXT: br i1 [[C1]], label [[FINAL_LEFT:%.*]], label [[DISPATCH:%.*]] 364; CHECK: pred1: 365; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V2:%.*]], 0 366; CHECK-NEXT: [[V3_ADJ:%.*]] = add i8 [[V1]], [[V2]] 367; CHECK-NEXT: [[C3:%.*]] = icmp eq i8 [[V3_ADJ]], 0 368; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C2]], [[C3]] 369; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT:%.*]] 370; CHECK: dispatch: 371; CHECK-NEXT: [[DOTOLD:%.*]] = add i8 [[V1]], [[V2]] 372; CHECK-NEXT: [[DOTOLD1:%.*]] = icmp eq i8 [[DOTOLD]], 0 373; CHECK-NEXT: br i1 [[DOTOLD1]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]] 374; CHECK: final_left: 375; CHECK-NEXT: [[MERGE_LEFT:%.*]] = phi i8 [ [[DOTOLD]], [[DISPATCH]] ], [ 0, [[PRED0]] ], [ [[V3_ADJ]], [[PRED1]] ] 376; CHECK-NEXT: call void @use8(i8 [[MERGE_LEFT]]) 377; CHECK-NEXT: call void @sideeffect0() 378; CHECK-NEXT: ret void 379; CHECK: final_right: 380; CHECK-NEXT: call void @sideeffect1() 381; CHECK-NEXT: ret void 382; 383entry: 384 %c0 = icmp eq i8 %v0, 0 385 br i1 %c0, label %pred0, label %pred1 386pred0: 387 %c1 = icmp eq i8 %v1, 0 388 br i1 %c1, label %final_left, label %dispatch 389pred1: 390 %c2 = icmp eq i8 %v2, 0 391 br i1 %c2, label %dispatch, label %final_right 392dispatch: 393 %v3_adj = add i8 %v1, %v2 394 %c3 = icmp eq i8 %v3_adj, 0 395 br i1 %c3, label %final_left, label %final_right 396final_left: 397 %merge_left = phi i8 [ %v3_adj, %dispatch ], [ 0, %pred0 ] 398 call void @use8(i8 %merge_left) 399 call void @sideeffect0() 400 ret void 401final_right: 402 call void @sideeffect1() 403 ret void 404} 405 406define void @two_preds_with_extra_op_liveout_multiuse(i8 %v0, i8 %v1, i8 %v2, i8 %v3) { 407; CHECK-LABEL: @two_preds_with_extra_op_liveout_multiuse( 408; CHECK-NEXT: entry: 409; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0 410; CHECK-NEXT: br i1 [[C0]], label [[PRED0:%.*]], label [[PRED1:%.*]] 411; CHECK: pred0: 412; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0 413; CHECK-NEXT: br i1 [[C1]], label [[FINAL_LEFT:%.*]], label [[DISPATCH:%.*]] 414; CHECK: pred1: 415; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V2:%.*]], 0 416; CHECK-NEXT: [[V3_ADJ:%.*]] = add i8 [[V1]], [[V2]] 417; CHECK-NEXT: [[C3:%.*]] = icmp eq i8 [[V3_ADJ]], 0 418; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C2]], [[C3]] 419; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT:%.*]] 420; CHECK: dispatch: 421; CHECK-NEXT: [[DOTOLD:%.*]] = add i8 [[V1]], [[V2]] 422; CHECK-NEXT: [[DOTOLD1:%.*]] = icmp eq i8 [[DOTOLD]], 0 423; CHECK-NEXT: br i1 [[DOTOLD1]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]] 424; CHECK: final_left: 425; CHECK-NEXT: [[MERGE_LEFT:%.*]] = phi i8 [ [[DOTOLD]], [[DISPATCH]] ], [ 0, [[PRED0]] ], [ [[V3_ADJ]], [[PRED1]] ] 426; CHECK-NEXT: [[MERGE_LEFT_2:%.*]] = phi i8 [ [[DOTOLD]], [[DISPATCH]] ], [ 42, [[PRED0]] ], [ [[V3_ADJ]], [[PRED1]] ] 427; CHECK-NEXT: call void @use8(i8 [[MERGE_LEFT]]) 428; CHECK-NEXT: call void @use8(i8 [[MERGE_LEFT_2]]) 429; CHECK-NEXT: call void @sideeffect0() 430; CHECK-NEXT: ret void 431; CHECK: final_right: 432; CHECK-NEXT: call void @sideeffect1() 433; CHECK-NEXT: ret void 434; 435entry: 436 %c0 = icmp eq i8 %v0, 0 437 br i1 %c0, label %pred0, label %pred1 438pred0: 439 %c1 = icmp eq i8 %v1, 0 440 br i1 %c1, label %final_left, label %dispatch 441pred1: 442 %c2 = icmp eq i8 %v2, 0 443 br i1 %c2, label %dispatch, label %final_right 444dispatch: 445 %v3_adj = add i8 %v1, %v2 446 %c3 = icmp eq i8 %v3_adj, 0 447 br i1 %c3, label %final_left, label %final_right 448final_left: 449 %merge_left = phi i8 [ %v3_adj, %dispatch ], [ 0, %pred0 ] 450 %merge_left_2 = phi i8 [ %v3_adj, %dispatch ], [ 42, %pred0 ] 451 call void @use8(i8 %merge_left) 452 call void @use8(i8 %merge_left_2) 453 call void @sideeffect0() 454 ret void 455final_right: 456 call void @sideeffect1() 457 ret void 458} 459 460; More complex case, there's an op that is safe to execute unconditionally, 461; and said op is live-out, and it is only used externally. 462 463define void @one_pred_with_extra_op_eexternally_used_only(i8 %v0, i8 %v1) { 464; CHECK-LABEL: @one_pred_with_extra_op_eexternally_used_only( 465; CHECK-NEXT: pred: 466; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0 467; CHECK-NEXT: [[V1_ADJ:%.*]] = add i8 [[V0]], [[V1:%.*]] 468; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1]], 0 469; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C0]], [[C1]] 470; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]] 471; CHECK: final_left: 472; CHECK-NEXT: call void @sideeffect0() 473; CHECK-NEXT: call void @use8(i8 [[V1_ADJ]]) 474; CHECK-NEXT: ret void 475; CHECK: final_right: 476; CHECK-NEXT: call void @sideeffect1() 477; CHECK-NEXT: ret void 478; 479pred: 480 %c0 = icmp eq i8 %v0, 0 481 br i1 %c0, label %dispatch, label %final_right 482dispatch: 483 %v1_adj = add i8 %v0, %v1 484 %c1 = icmp eq i8 %v1, 0 485 br i1 %c1, label %final_left, label %final_right 486final_left: 487 call void @sideeffect0() 488 call void @use8(i8 %v1_adj) 489 ret void 490final_right: 491 call void @sideeffect1() 492 ret void 493} 494define void @one_pred_with_extra_op_externally_used_only_multiuse(i8 %v0, i8 %v1) { 495; CHECK-LABEL: @one_pred_with_extra_op_externally_used_only_multiuse( 496; CHECK-NEXT: pred: 497; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0 498; CHECK-NEXT: [[V1_ADJ:%.*]] = add i8 [[V0]], [[V1:%.*]] 499; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1]], 0 500; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C0]], [[C1]] 501; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]] 502; CHECK: final_left: 503; CHECK-NEXT: call void @sideeffect0() 504; CHECK-NEXT: call void @use8(i8 [[V1_ADJ]]) 505; CHECK-NEXT: call void @use8(i8 [[V1_ADJ]]) 506; CHECK-NEXT: ret void 507; CHECK: final_right: 508; CHECK-NEXT: call void @sideeffect1() 509; CHECK-NEXT: ret void 510; 511pred: 512 %c0 = icmp eq i8 %v0, 0 513 br i1 %c0, label %dispatch, label %final_right 514dispatch: 515 %v1_adj = add i8 %v0, %v1 516 %c1 = icmp eq i8 %v1, 0 517 br i1 %c1, label %final_left, label %final_right 518final_left: 519 call void @sideeffect0() 520 call void @use8(i8 %v1_adj) 521 call void @use8(i8 %v1_adj) 522 ret void 523final_right: 524 call void @sideeffect1() 525 ret void 526} 527 528define void @two_preds_with_extra_op_externally_used_only(i8 %v0, i8 %v1, i8 %v2, i8 %v3) { 529; CHECK-LABEL: @two_preds_with_extra_op_externally_used_only( 530; CHECK-NEXT: entry: 531; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0 532; CHECK-NEXT: br i1 [[C0]], label [[PRED0:%.*]], label [[PRED1:%.*]] 533; CHECK: pred0: 534; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0 535; CHECK-NEXT: br i1 [[C1]], label [[FINAL_LEFT:%.*]], label [[DISPATCH:%.*]] 536; CHECK: pred1: 537; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V2:%.*]], 0 538; CHECK-NEXT: [[V3_ADJ:%.*]] = add i8 [[V1]], [[V2]] 539; CHECK-NEXT: [[C3:%.*]] = icmp eq i8 [[V3:%.*]], 0 540; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C2]], [[C3]] 541; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT:%.*]] 542; CHECK: dispatch: 543; CHECK-NEXT: [[DOTOLD:%.*]] = add i8 [[V1]], [[V2]] 544; CHECK-NEXT: [[DOTOLD1:%.*]] = icmp eq i8 [[V3]], 0 545; CHECK-NEXT: br i1 [[DOTOLD1]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]] 546; CHECK: final_left: 547; CHECK-NEXT: [[MERGE_LEFT:%.*]] = phi i8 [ [[DOTOLD]], [[DISPATCH]] ], [ 0, [[PRED0]] ], [ [[V3_ADJ]], [[PRED1]] ] 548; CHECK-NEXT: call void @use8(i8 [[MERGE_LEFT]]) 549; CHECK-NEXT: call void @sideeffect0() 550; CHECK-NEXT: ret void 551; CHECK: final_right: 552; CHECK-NEXT: call void @sideeffect1() 553; CHECK-NEXT: ret void 554; 555entry: 556 %c0 = icmp eq i8 %v0, 0 557 br i1 %c0, label %pred0, label %pred1 558pred0: 559 %c1 = icmp eq i8 %v1, 0 560 br i1 %c1, label %final_left, label %dispatch 561pred1: 562 %c2 = icmp eq i8 %v2, 0 563 br i1 %c2, label %dispatch, label %final_right 564dispatch: 565 %v3_adj = add i8 %v1, %v2 566 %c3 = icmp eq i8 %v3, 0 567 br i1 %c3, label %final_left, label %final_right 568final_left: 569 %merge_left = phi i8 [ %v3_adj, %dispatch ], [ 0, %pred0 ] 570 call void @use8(i8 %merge_left) 571 call void @sideeffect0() 572 ret void 573final_right: 574 call void @sideeffect1() 575 ret void 576} 577 578define void @two_preds_with_extra_op_externally_used_only_multiuse(i8 %v0, i8 %v1, i8 %v2, i8 %v3) { 579; CHECK-LABEL: @two_preds_with_extra_op_externally_used_only_multiuse( 580; CHECK-NEXT: entry: 581; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0 582; CHECK-NEXT: br i1 [[C0]], label [[PRED0:%.*]], label [[PRED1:%.*]] 583; CHECK: pred0: 584; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0 585; CHECK-NEXT: br i1 [[C1]], label [[FINAL_LEFT:%.*]], label [[DISPATCH:%.*]] 586; CHECK: pred1: 587; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V2:%.*]], 0 588; CHECK-NEXT: [[V3_ADJ:%.*]] = add i8 [[V1]], [[V2]] 589; CHECK-NEXT: [[C3:%.*]] = icmp eq i8 [[V3:%.*]], 0 590; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C2]], [[C3]] 591; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT:%.*]] 592; CHECK: dispatch: 593; CHECK-NEXT: [[DOTOLD:%.*]] = add i8 [[V1]], [[V2]] 594; CHECK-NEXT: [[DOTOLD1:%.*]] = icmp eq i8 [[V3]], 0 595; CHECK-NEXT: br i1 [[DOTOLD1]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]] 596; CHECK: final_left: 597; CHECK-NEXT: [[MERGE_LEFT:%.*]] = phi i8 [ [[DOTOLD]], [[DISPATCH]] ], [ 0, [[PRED0]] ], [ [[V3_ADJ]], [[PRED1]] ] 598; CHECK-NEXT: [[MERGE_LEFT_2:%.*]] = phi i8 [ [[DOTOLD]], [[DISPATCH]] ], [ 42, [[PRED0]] ], [ [[V3_ADJ]], [[PRED1]] ] 599; CHECK-NEXT: call void @use8(i8 [[MERGE_LEFT]]) 600; CHECK-NEXT: call void @use8(i8 [[MERGE_LEFT_2]]) 601; CHECK-NEXT: call void @sideeffect0() 602; CHECK-NEXT: ret void 603; CHECK: final_right: 604; CHECK-NEXT: call void @sideeffect1() 605; CHECK-NEXT: ret void 606; 607entry: 608 %c0 = icmp eq i8 %v0, 0 609 br i1 %c0, label %pred0, label %pred1 610pred0: 611 %c1 = icmp eq i8 %v1, 0 612 br i1 %c1, label %final_left, label %dispatch 613pred1: 614 %c2 = icmp eq i8 %v2, 0 615 br i1 %c2, label %dispatch, label %final_right 616dispatch: 617 %v3_adj = add i8 %v1, %v2 618 %c3 = icmp eq i8 %v3, 0 619 br i1 %c3, label %final_left, label %final_right 620final_left: 621 %merge_left = phi i8 [ %v3_adj, %dispatch ], [ 0, %pred0 ] 622 %merge_left_2 = phi i8 [ %v3_adj, %dispatch ], [ 42, %pred0 ] 623 call void @use8(i8 %merge_left) 624 call void @use8(i8 %merge_left_2) 625 call void @sideeffect0() 626 ret void 627final_right: 628 call void @sideeffect1() 629 ret void 630} 631 632; The liveout instruction can be located after the branch condition. 633define void @one_pred_with_extra_op_externally_used_only_after_cond_distant_phi(i8 %v0, i8 %v1, i8 %v3, i8 %v4, i8 %v5) { 634; CHECK-LABEL: @one_pred_with_extra_op_externally_used_only_after_cond_distant_phi( 635; CHECK-NEXT: entry: 636; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0 637; CHECK-NEXT: br i1 [[C0]], label [[PRED:%.*]], label [[LEFT_END:%.*]] 638; CHECK: pred: 639; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0 640; CHECK-NEXT: [[C3:%.*]] = icmp eq i8 [[V3:%.*]], 0 641; CHECK-NEXT: [[V2_ADJ:%.*]] = add i8 [[V4:%.*]], [[V5:%.*]] 642; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C1]], [[C3]] 643; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]] 644; CHECK: final_left: 645; CHECK-NEXT: call void @sideeffect0() 646; CHECK-NEXT: call void @use8(i8 [[V2_ADJ]]) 647; CHECK-NEXT: br label [[LEFT_END]] 648; CHECK: left_end: 649; CHECK-NEXT: [[MERGE_LEFT:%.*]] = phi i8 [ [[V2_ADJ]], [[FINAL_LEFT]] ], [ 0, [[ENTRY:%.*]] ] 650; CHECK-NEXT: call void @sideeffect1() 651; CHECK-NEXT: call void @use8(i8 [[MERGE_LEFT]]) 652; CHECK-NEXT: ret void 653; CHECK: final_right: 654; CHECK-NEXT: call void @sideeffect2() 655; CHECK-NEXT: ret void 656; 657entry: 658 %c0 = icmp eq i8 %v0, 0 659 br i1 %c0, label %pred, label %left_end 660pred: 661 %c1 = icmp eq i8 %v1, 0 662 br i1 %c1, label %dispatch, label %final_right 663dispatch: 664 %c3 = icmp eq i8 %v3, 0 665 %v2_adj = add i8 %v4, %v5 666 br i1 %c3, label %final_left, label %final_right 667final_left: 668 call void @sideeffect0() 669 call void @use8(i8 %v2_adj) 670 br label %left_end 671left_end: 672 %merge_left = phi i8 [ %v2_adj, %final_left ], [ 0, %entry ] 673 call void @sideeffect1() 674 call void @use8(i8 %merge_left) 675 ret void 676final_right: 677 call void @sideeffect2() 678 ret void 679} 680define void @two_preds_with_extra_op_externally_used_only_after_cond(i8 %v0, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %v5) { 681; CHECK-LABEL: @two_preds_with_extra_op_externally_used_only_after_cond( 682; CHECK-NEXT: entry: 683; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0 684; CHECK-NEXT: br i1 [[C0]], label [[PRED0:%.*]], label [[PRED1:%.*]] 685; CHECK: pred0: 686; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0 687; CHECK-NEXT: br i1 [[C1]], label [[FINAL_LEFT:%.*]], label [[DISPATCH:%.*]] 688; CHECK: pred1: 689; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V2:%.*]], 0 690; CHECK-NEXT: [[C3:%.*]] = icmp eq i8 [[V3:%.*]], 0 691; CHECK-NEXT: [[V3_ADJ:%.*]] = add i8 [[V4:%.*]], [[V5:%.*]] 692; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C2]], [[C3]] 693; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT:%.*]] 694; CHECK: dispatch: 695; CHECK-NEXT: [[DOTOLD:%.*]] = icmp eq i8 [[V3]], 0 696; CHECK-NEXT: [[DOTOLD1:%.*]] = add i8 [[V4]], [[V5]] 697; CHECK-NEXT: br i1 [[DOTOLD]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]] 698; CHECK: final_left: 699; CHECK-NEXT: [[MERGE_LEFT:%.*]] = phi i8 [ [[DOTOLD1]], [[DISPATCH]] ], [ 0, [[PRED0]] ], [ [[V3_ADJ]], [[PRED1]] ] 700; CHECK-NEXT: call void @use8(i8 [[MERGE_LEFT]]) 701; CHECK-NEXT: call void @sideeffect0() 702; CHECK-NEXT: ret void 703; CHECK: final_right: 704; CHECK-NEXT: call void @sideeffect1() 705; CHECK-NEXT: ret void 706; 707entry: 708 %c0 = icmp eq i8 %v0, 0 709 br i1 %c0, label %pred0, label %pred1 710pred0: 711 %c1 = icmp eq i8 %v1, 0 712 br i1 %c1, label %final_left, label %dispatch 713pred1: 714 %c2 = icmp eq i8 %v2, 0 715 br i1 %c2, label %dispatch, label %final_right 716dispatch: 717 %c3 = icmp eq i8 %v3, 0 718 %v3_adj = add i8 %v4, %v5 719 br i1 %c3, label %final_left, label %final_right 720final_left: 721 %merge_left = phi i8 [ %v3_adj, %dispatch ], [ 0, %pred0 ] 722 call void @use8(i8 %merge_left) 723 call void @sideeffect0() 724 ret void 725final_right: 726 call void @sideeffect1() 727 ret void 728} 729