1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -passes=div-rem-pairs -S -mtriple=x86_64-unknown-unknown | FileCheck %s 3 4declare void @foo(i32, i32) 5 6define void @decompose_illegal_srem_same_block(i32 %a, i32 %b) { 7; CHECK-LABEL: @decompose_illegal_srem_same_block( 8; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]] 9; CHECK-NEXT: [[T0:%.*]] = mul i32 [[DIV]], [[B]] 10; CHECK-NEXT: [[REM_RECOMPOSED:%.*]] = srem i32 [[A]], [[B]] 11; CHECK-NEXT: call void @foo(i32 [[REM_RECOMPOSED]], i32 [[DIV]]) 12; CHECK-NEXT: ret void 13; 14 %div = sdiv i32 %a, %b 15 %t0 = mul i32 %div, %b 16 %rem = sub i32 %a, %t0 17 call void @foo(i32 %rem, i32 %div) 18 ret void 19} 20 21define void @decompose_illegal_urem_same_block(i32 %a, i32 %b) { 22; CHECK-LABEL: @decompose_illegal_urem_same_block( 23; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[A:%.*]], [[B:%.*]] 24; CHECK-NEXT: [[T0:%.*]] = mul i32 [[DIV]], [[B]] 25; CHECK-NEXT: [[REM_RECOMPOSED:%.*]] = urem i32 [[A]], [[B]] 26; CHECK-NEXT: call void @foo(i32 [[REM_RECOMPOSED]], i32 [[DIV]]) 27; CHECK-NEXT: ret void 28; 29 %div = udiv i32 %a, %b 30 %t0 = mul i32 %div, %b 31 %rem = sub i32 %a, %t0 32 call void @foo(i32 %rem, i32 %div) 33 ret void 34} 35 36; Recompose and hoist the srem if it's safe and free, otherwise keep as-is.. 37 38define i16 @hoist_srem(i16 %a, i16 %b) { 39; CHECK-LABEL: @hoist_srem( 40; CHECK-NEXT: entry: 41; CHECK-NEXT: [[DIV:%.*]] = sdiv i16 [[A:%.*]], [[B:%.*]] 42; CHECK-NEXT: [[REM_RECOMPOSED:%.*]] = srem i16 [[A]], [[B]] 43; CHECK-NEXT: [[CMP:%.*]] = icmp eq i16 [[DIV]], 42 44; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] 45; CHECK: if: 46; CHECK-NEXT: [[T0:%.*]] = mul i16 [[DIV]], [[B]] 47; CHECK-NEXT: br label [[END]] 48; CHECK: end: 49; CHECK-NEXT: [[RET:%.*]] = phi i16 [ [[REM_RECOMPOSED]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] 50; CHECK-NEXT: ret i16 [[RET]] 51; 52entry: 53 %div = sdiv i16 %a, %b 54 %cmp = icmp eq i16 %div, 42 55 br i1 %cmp, label %if, label %end 56 57if: 58 %t0 = mul i16 %div, %b 59 %rem = sub i16 %a, %t0 60 br label %end 61 62end: 63 %ret = phi i16 [ %rem, %if ], [ 3, %entry ] 64 ret i16 %ret 65} 66 67; Recompose and hoist the urem if it's safe and free, otherwise keep as-is.. 68 69define i8 @hoist_urem(i8 %a, i8 %b) { 70; CHECK-LABEL: @hoist_urem( 71; CHECK-NEXT: entry: 72; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[A:%.*]], [[B:%.*]] 73; CHECK-NEXT: [[REM_RECOMPOSED:%.*]] = urem i8 [[A]], [[B]] 74; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[DIV]], 42 75; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] 76; CHECK: if: 77; CHECK-NEXT: [[T0:%.*]] = mul i8 [[DIV]], [[B]] 78; CHECK-NEXT: br label [[END]] 79; CHECK: end: 80; CHECK-NEXT: [[RET:%.*]] = phi i8 [ [[REM_RECOMPOSED]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] 81; CHECK-NEXT: ret i8 [[RET]] 82; 83entry: 84 %div = udiv i8 %a, %b 85 %cmp = icmp eq i8 %div, 42 86 br i1 %cmp, label %if, label %end 87 88if: 89 %t0 = mul i8 %div, %b 90 %rem = sub i8 %a, %t0 91 br label %end 92 93end: 94 %ret = phi i8 [ %rem, %if ], [ 3, %entry ] 95 ret i8 %ret 96} 97 98; Be careful with RAUW/invalidation if this is a srem-of-srem. 99 100define i32 @srem_of_srem_unexpanded(i32 %X, i32 %Y, i32 %Z) { 101; CHECK-LABEL: @srem_of_srem_unexpanded( 102; CHECK-NEXT: [[T0:%.*]] = mul nsw i32 [[Z:%.*]], [[Y:%.*]] 103; CHECK-NEXT: [[T1:%.*]] = sdiv i32 [[X:%.*]], [[T0]] 104; CHECK-NEXT: [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]] 105; CHECK-NEXT: [[T3:%.*]] = srem i32 [[X]], [[T0]] 106; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3]], [[Y]] 107; CHECK-NEXT: [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]] 108; CHECK-NEXT: [[T6:%.*]] = srem i32 [[T3]], [[Y]] 109; CHECK-NEXT: ret i32 [[T6]] 110; 111 %t0 = mul nsw i32 %Z, %Y 112 %t1 = sdiv i32 %X, %t0 113 %t2 = mul nsw i32 %t0, %t1 114 %t3 = srem i32 %X, %t0 115 %t4 = sdiv i32 %t3, %Y 116 %t5 = mul nsw i32 %t4, %Y 117 %t6 = srem i32 %t3, %Y 118 ret i32 %t6 119} 120define i32 @srem_of_srem_expanded(i32 %X, i32 %Y, i32 %Z) { 121; CHECK-LABEL: @srem_of_srem_expanded( 122; CHECK-NEXT: [[T0:%.*]] = mul nsw i32 [[Z:%.*]], [[Y:%.*]] 123; CHECK-NEXT: [[T1:%.*]] = sdiv i32 [[X:%.*]], [[T0]] 124; CHECK-NEXT: [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]] 125; CHECK-NEXT: [[T3_RECOMPOSED:%.*]] = srem i32 [[X]], [[T0]] 126; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3_RECOMPOSED]], [[Y]] 127; CHECK-NEXT: [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]] 128; CHECK-NEXT: [[T6_RECOMPOSED:%.*]] = srem i32 [[T3_RECOMPOSED]], [[Y]] 129; CHECK-NEXT: ret i32 [[T6_RECOMPOSED]] 130; 131 %t0 = mul nsw i32 %Z, %Y 132 %t1 = sdiv i32 %X, %t0 133 %t2 = mul nsw i32 %t0, %t1 134 %t3 = sub nsw i32 %X, %t2 135 %t4 = sdiv i32 %t3, %Y 136 %t5 = mul nsw i32 %t4, %Y 137 %t6 = sub nsw i32 %t3, %t5 138 ret i32 %t6 139} 140 141; If the target doesn't have a unified div/rem op for the type, keep decomposed rem 142 143define i128 @dont_hoist_urem(i128 %a, i128 %b) { 144; CHECK-LABEL: @dont_hoist_urem( 145; CHECK-NEXT: entry: 146; CHECK-NEXT: [[DIV:%.*]] = udiv i128 [[A:%.*]], [[B:%.*]] 147; CHECK-NEXT: [[CMP:%.*]] = icmp eq i128 [[DIV]], 42 148; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] 149; CHECK: if: 150; CHECK-NEXT: [[T0:%.*]] = mul i128 [[DIV]], [[B]] 151; CHECK-NEXT: [[REM:%.*]] = sub i128 [[A]], [[T0]] 152; CHECK-NEXT: br label [[END]] 153; CHECK: end: 154; CHECK-NEXT: [[RET:%.*]] = phi i128 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] 155; CHECK-NEXT: ret i128 [[RET]] 156; 157entry: 158 %div = udiv i128 %a, %b 159 %cmp = icmp eq i128 %div, 42 160 br i1 %cmp, label %if, label %end 161 162if: 163 %t0 = mul i128 %div, %b 164 %rem = sub i128 %a, %t0 165 br label %end 166 167end: 168 %ret = phi i128 [ %rem, %if ], [ 3, %entry ] 169 ret i128 %ret 170} 171 172; Even in expanded form, we can end up with div and rem in different basic 173; blocks neither of which dominates each another. 174define i32 @can_have_divrem_in_mutually_nondominating_bbs(i1 %cmp, i32 %a, i32 %b) { 175; CHECK-LABEL: @can_have_divrem_in_mutually_nondominating_bbs( 176; CHECK-NEXT: entry: 177; CHECK-NEXT: [[T3:%.*]] = udiv i32 [[A:%.*]], [[B:%.*]] 178; CHECK-NEXT: [[T2_RECOMPOSED:%.*]] = urem i32 [[A]], [[B]] 179; CHECK-NEXT: br i1 [[CMP:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] 180; CHECK: if.then: 181; CHECK-NEXT: [[T0:%.*]] = udiv i32 [[A]], [[B]] 182; CHECK-NEXT: [[T1:%.*]] = mul nuw i32 [[T0]], [[B]] 183; CHECK-NEXT: br label [[END:%.*]] 184; CHECK: if.else: 185; CHECK-NEXT: br label [[END]] 186; CHECK: end: 187; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[T2_RECOMPOSED]], [[IF_THEN]] ], [ [[T3]], [[IF_ELSE]] ] 188; CHECK-NEXT: ret i32 [[RET]] 189; 190entry: 191 br i1 %cmp, label %if.then, label %if.else 192 193if.then: 194 %t0 = udiv i32 %a, %b 195 %t1 = mul nuw i32 %t0, %b 196 %t2 = sub i32 %a, %t1 197 br label %end 198 199if.else: 200 %t3 = udiv i32 %a, %b 201 br label %end 202 203end: 204 %ret = phi i32 [ %t2, %if.then ], [ %t3, %if.else ] 205 ret i32 %ret 206} 207 208; Test for hoisting a udiv to dominate a urem to allow udivrem. 209define i64 @remainder_triangle_i64(i64 %a, i64 %b, ptr %rp) { 210; CHECK-LABEL: @remainder_triangle_i64( 211; CHECK-NEXT: entry: 212; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[RP:%.*]], null 213; CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[A:%.*]], [[B:%.*]] 214; CHECK-NEXT: [[REM:%.*]] = urem i64 [[A]], [[B]] 215; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[END:%.*]] 216; CHECK: if.then: 217; CHECK-NEXT: store i64 [[REM]], ptr [[RP]], align 8 218; CHECK-NEXT: br label [[END]] 219; CHECK: end: 220; CHECK-NEXT: ret i64 [[DIV]] 221; 222entry: 223 %cmp = icmp ne ptr %rp, null 224 br i1 %cmp, label %if.then, label %end 225 226if.then: 227 %rem = urem i64 %a, %b 228 store i64 %rem, ptr %rp 229 br label %end 230 231end: 232 %div = udiv i64 %a, %b 233 ret i64 %div 234} 235 236; Test for hoisting a udiv to dominate a urem to allow the urem to be expanded 237; into mul+sub. 238define i128 @remainder_triangle_i128(i128 %a, i128 %b, ptr %rp) { 239; CHECK-LABEL: @remainder_triangle_i128( 240; CHECK-NEXT: entry: 241; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[RP:%.*]], null 242; CHECK-NEXT: [[A_FROZEN:%.*]] = freeze i128 [[A:%.*]] 243; CHECK-NEXT: [[B_FROZEN:%.*]] = freeze i128 [[B:%.*]] 244; CHECK-NEXT: [[DIV:%.*]] = udiv i128 [[A_FROZEN]], [[B_FROZEN]] 245; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[END:%.*]] 246; CHECK: if.then: 247; CHECK-NEXT: [[TMP0:%.*]] = mul i128 [[DIV]], [[B_FROZEN]] 248; CHECK-NEXT: [[REM_DECOMPOSED:%.*]] = sub i128 [[A_FROZEN]], [[TMP0]] 249; CHECK-NEXT: store i128 [[REM_DECOMPOSED]], ptr [[RP]], align 16 250; CHECK-NEXT: br label [[END]] 251; CHECK: end: 252; CHECK-NEXT: ret i128 [[DIV]] 253; 254entry: 255 %cmp = icmp ne ptr %rp, null 256 br i1 %cmp, label %if.then, label %end 257 258if.then: 259 %rem = urem i128 %a, %b 260 store i128 %rem, ptr %rp 261 br label %end 262 263end: 264 %div = udiv i128 %a, %b 265 ret i128 %div 266} 267 268define i64 @remainder_triangle_i64_multiple_rem_edges(i64 %a, i64 %b, i64 %c, ptr %rp) { 269; CHECK-LABEL: @remainder_triangle_i64_multiple_rem_edges( 270; CHECK-NEXT: entry: 271; CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[A:%.*]], [[B:%.*]] 272; CHECK-NEXT: [[REM:%.*]] = urem i64 [[A]], [[B]] 273; CHECK-NEXT: switch i64 [[C:%.*]], label [[SW_DEFAULT:%.*]] [ 274; CHECK-NEXT: i64 0, label [[SW_BB:%.*]] 275; CHECK-NEXT: i64 2, label [[SW_BB]] 276; CHECK-NEXT: ] 277; CHECK: sw.bb: 278; CHECK-NEXT: store i64 [[REM]], ptr [[RP:%.*]], align 8 279; CHECK-NEXT: br label [[SW_DEFAULT]] 280; CHECK: sw.default: 281; CHECK-NEXT: ret i64 [[DIV]] 282; 283entry: 284 switch i64 %c, label %sw.default [ 285 i64 0, label %sw.bb 286 i64 2, label %sw.bb 287 ] 288 289sw.bb: ; preds = %entry, %entry 290 %rem = urem i64 %a, %b 291 store i64 %rem, ptr %rp 292 br label %sw.default 293 294sw.default: ; preds = %entry, %sw.bb 295 %div = udiv i64 %a, %b 296 ret i64 %div 297} 298 299define i64 @remainder_triangle_i64_multiple_div_edges(i64 %a, i64 %b, i64 %c, ptr %rp) { 300; CHECK-LABEL: @remainder_triangle_i64_multiple_div_edges( 301; CHECK-NEXT: entry: 302; CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[A:%.*]], [[B:%.*]] 303; CHECK-NEXT: [[REM:%.*]] = urem i64 [[A]], [[B]] 304; CHECK-NEXT: switch i64 [[C:%.*]], label [[SW_DEFAULT:%.*]] [ 305; CHECK-NEXT: i64 0, label [[SW_BB:%.*]] 306; CHECK-NEXT: i64 2, label [[SW_BB]] 307; CHECK-NEXT: ] 308; CHECK: sw.default: 309; CHECK-NEXT: store i64 [[REM]], ptr [[RP:%.*]], align 8 310; CHECK-NEXT: br label [[SW_BB]] 311; CHECK: sw.bb: 312; CHECK-NEXT: ret i64 [[DIV]] 313; 314entry: 315 switch i64 %c, label %sw.default [ 316 i64 0, label %sw.bb 317 i64 2, label %sw.bb 318 ] 319 320sw.default: ; preds = %entry, %entry 321 %rem = urem i64 %a, %b 322 store i64 %rem, ptr %rp 323 br label %sw.bb 324 325sw.bb: ; preds = %entry, %sw.default 326 %div = udiv i64 %a, %b 327 ret i64 %div 328} 329 330declare void @maythrow() 331 332; Negative test. make sure we don't transform if there are instructions before 333; the rem that might throw. 334define i64 @remainder_triangle_i64_maythrow_rem(i64 %a, i64 %b, ptr %rp) { 335; CHECK-LABEL: @remainder_triangle_i64_maythrow_rem( 336; CHECK-NEXT: entry: 337; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[RP:%.*]], null 338; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[END:%.*]] 339; CHECK: if.then: 340; CHECK-NEXT: call void @maythrow() 341; CHECK-NEXT: [[REM:%.*]] = urem i64 [[A:%.*]], [[B:%.*]] 342; CHECK-NEXT: store i64 [[REM]], ptr [[RP]], align 8 343; CHECK-NEXT: br label [[END]] 344; CHECK: end: 345; CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[A]], [[B]] 346; CHECK-NEXT: ret i64 [[DIV]] 347; 348entry: 349 %cmp = icmp ne ptr %rp, null 350 br i1 %cmp, label %if.then, label %end 351 352if.then: 353 call void @maythrow() 354 %rem = urem i64 %a, %b 355 store i64 %rem, ptr %rp 356 br label %end 357 358end: 359 %div = udiv i64 %a, %b 360 ret i64 %div 361} 362 363; Negative test. make sure we don't transform if there are instructions before 364; the div that might throw. 365define i64 @remainder_triangle_i64_maythrow_div(i64 %a, i64 %b, ptr %rp) { 366; CHECK-LABEL: @remainder_triangle_i64_maythrow_div( 367; CHECK-NEXT: entry: 368; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[RP:%.*]], null 369; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[END:%.*]] 370; CHECK: if.then: 371; CHECK-NEXT: [[REM:%.*]] = urem i64 [[A:%.*]], [[B:%.*]] 372; CHECK-NEXT: store i64 [[REM]], ptr [[RP]], align 8 373; CHECK-NEXT: br label [[END]] 374; CHECK: end: 375; CHECK-NEXT: call void @maythrow() 376; CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[A]], [[B]] 377; CHECK-NEXT: ret i64 [[DIV]] 378; 379entry: 380 %cmp = icmp ne ptr %rp, null 381 br i1 %cmp, label %if.then, label %end 382 383if.then: 384 %rem = urem i64 %a, %b 385 store i64 %rem, ptr %rp 386 br label %end 387 388end: 389 call void @maythrow() 390 %div = udiv i64 %a, %b 391 ret i64 %div 392} 393 394; Negative test, Make sure we don't transform if there are instructions before 395; the rem that might throw. 396define i128 @remainder_triangle_i128_maythrow_rem(i128 %a, i128 %b, ptr %rp) { 397; CHECK-LABEL: @remainder_triangle_i128_maythrow_rem( 398; CHECK-NEXT: entry: 399; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[RP:%.*]], null 400; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[END:%.*]] 401; CHECK: if.then: 402; CHECK-NEXT: call void @maythrow() 403; CHECK-NEXT: [[REM:%.*]] = urem i128 [[A:%.*]], [[B:%.*]] 404; CHECK-NEXT: store i128 [[REM]], ptr [[RP]], align 16 405; CHECK-NEXT: br label [[END]] 406; CHECK: end: 407; CHECK-NEXT: [[DIV:%.*]] = udiv i128 [[A]], [[B]] 408; CHECK-NEXT: ret i128 [[DIV]] 409; 410entry: 411 %cmp = icmp ne ptr %rp, null 412 br i1 %cmp, label %if.then, label %end 413 414if.then: 415 call void @maythrow() 416 %rem = urem i128 %a, %b 417 store i128 %rem, ptr %rp 418 br label %end 419 420end: 421 %div = udiv i128 %a, %b 422 ret i128 %div 423} 424 425; Negative test. Make sure we don't transform if there are instructions before 426; the div that might throw. 427define i128 @remainder_triangle_i128_maythrow_div(i128 %a, i128 %b, ptr %rp) { 428; CHECK-LABEL: @remainder_triangle_i128_maythrow_div( 429; CHECK-NEXT: entry: 430; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[RP:%.*]], null 431; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[END:%.*]] 432; CHECK: if.then: 433; CHECK-NEXT: [[REM:%.*]] = urem i128 [[A:%.*]], [[B:%.*]] 434; CHECK-NEXT: store i128 [[REM]], ptr [[RP]], align 16 435; CHECK-NEXT: br label [[END]] 436; CHECK: end: 437; CHECK-NEXT: call void @maythrow() 438; CHECK-NEXT: [[DIV:%.*]] = udiv i128 [[A]], [[B]] 439; CHECK-NEXT: ret i128 [[DIV]] 440; 441entry: 442 %cmp = icmp ne ptr %rp, null 443 br i1 %cmp, label %if.then, label %end 444 445if.then: 446 %rem = urem i128 %a, %b 447 store i128 %rem, ptr %rp 448 br label %end 449 450end: 451 call void @maythrow() 452 %div = udiv i128 %a, %b 453 ret i128 %div 454} 455 456; Negative test. The common predecessor has another successor so we can't hoist 457; the udiv to the common predecessor. 458define i64 @remainder_not_triangle_i32(i64 %a, i64 %b, i64 %c, ptr %rp) { 459; CHECK-LABEL: @remainder_not_triangle_i32( 460; CHECK-NEXT: entry: 461; CHECK-NEXT: switch i64 [[C:%.*]], label [[RETURN:%.*]] [ 462; CHECK-NEXT: i64 0, label [[SW_BB:%.*]] 463; CHECK-NEXT: i64 1, label [[SW_BB1:%.*]] 464; CHECK-NEXT: ] 465; CHECK: sw.bb: 466; CHECK-NEXT: [[REM:%.*]] = urem i64 [[A:%.*]], [[B:%.*]] 467; CHECK-NEXT: store i64 [[REM]], ptr [[RP:%.*]], align 8 468; CHECK-NEXT: br label [[SW_BB1]] 469; CHECK: sw.bb1: 470; CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[A]], [[B]] 471; CHECK-NEXT: br label [[RETURN]] 472; CHECK: return: 473; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i64 [ [[DIV]], [[SW_BB1]] ], [ 0, [[ENTRY:%.*]] ] 474; CHECK-NEXT: ret i64 [[RETVAL_0]] 475; 476entry: 477 switch i64 %c, label %return [ 478 i64 0, label %sw.bb 479 i64 1, label %sw.bb1 480 ] 481 482sw.bb: ; preds = %entry 483 %rem = urem i64 %a, %b 484 store i64 %rem, ptr %rp 485 br label %sw.bb1 486 487sw.bb1: ; preds = %entry, %sw.bb 488 %div = udiv i64 %a, %b 489 br label %return 490 491return: ; preds = %entry, %sw.bb1 492 %retval.0 = phi i64 [ %div, %sw.bb1 ], [ 0, %entry ] 493 ret i64 %retval.0 494} 495 496; Negative test. The urem block has a successor that isn't udiv. 497define i64 @remainder_not_triangle_i32_2(i64 %a, i64 %b, i64 %c, ptr %rp) { 498; CHECK-LABEL: @remainder_not_triangle_i32_2( 499; CHECK-NEXT: entry: 500; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[RP:%.*]], null 501; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[IF_END3:%.*]], label [[IF_THEN:%.*]] 502; CHECK: if.then: 503; CHECK-NEXT: [[REM:%.*]] = urem i64 [[A:%.*]], [[B:%.*]] 504; CHECK-NEXT: store i64 [[REM]], ptr [[RP]], align 8 505; CHECK-NEXT: [[TOBOOL1_NOT:%.*]] = icmp eq i64 [[C:%.*]], 0 506; CHECK-NEXT: br i1 [[TOBOOL1_NOT]], label [[IF_END3]], label [[RETURN:%.*]] 507; CHECK: if.end3: 508; CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[A]], [[B]] 509; CHECK-NEXT: br label [[RETURN]] 510; CHECK: return: 511; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i64 [ [[DIV]], [[IF_END3]] ], [ 0, [[IF_THEN]] ] 512; CHECK-NEXT: ret i64 [[RETVAL_0]] 513; 514entry: 515 %tobool.not = icmp eq ptr %rp, null 516 br i1 %tobool.not, label %if.end3, label %if.then 517 518if.then: ; preds = %entry 519 %rem = urem i64 %a, %b 520 store i64 %rem, ptr %rp 521 %tobool1.not = icmp eq i64 %c, 0 522 br i1 %tobool1.not, label %if.end3, label %return 523 524if.end3: ; preds = %if.then, %entry 525 %div = udiv i64 %a, %b 526 br label %return 527 528return: ; preds = %if.then, %if.end3 529 %retval.0 = phi i64 [ %div, %if.end3 ], [ 0, %if.then ] 530 ret i64 %retval.0 531} 532 533; Negative test (this would create invalid IR and crash). 534; The div block can't have predecessors other than the rem block 535; and the common single pred block (it is reachable from entry here). 536 537define i32 @PR51241(i1 %b1, i1 %b2, i32 %t0) { 538; CHECK-LABEL: @PR51241( 539; CHECK-NEXT: entry: 540; CHECK-NEXT: br i1 [[B1:%.*]], label [[DIVBB:%.*]], label [[PREDBB:%.*]] 541; CHECK: predbb: 542; CHECK-NEXT: br i1 [[B2:%.*]], label [[DIVBB]], label [[REMBB:%.*]] 543; CHECK: rembb: 544; CHECK-NEXT: [[REM2:%.*]] = srem i32 7, [[T0:%.*]] 545; CHECK-NEXT: br label [[DIVBB]] 546; CHECK: divbb: 547; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 7, [[T0]] 548; CHECK-NEXT: ret i32 [[DIV]] 549; 550entry: 551 br i1 %b1, label %divbb, label %predbb 552 553predbb: 554 br i1 %b2, label %divbb, label %rembb 555 556rembb: 557 %rem2 = srem i32 7, %t0 558 br label %divbb 559 560divbb: 561 %div = sdiv i32 7, %t0 562 ret i32 %div 563} 564