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: [[REM:%.*]] = srem i32 [[A:%.*]], [[B:%.*]] 9; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A]], [[B]] 10; CHECK-NEXT: call void @foo(i32 [[REM]], i32 [[DIV]]) 11; CHECK-NEXT: ret void 12; 13 %rem = srem i32 %a, %b 14 %div = sdiv i32 %a, %b 15 call void @foo(i32 %rem, i32 %div) 16 ret void 17} 18 19define void @decompose_illegal_urem_same_block(i32 %a, i32 %b) { 20; CHECK-LABEL: @decompose_illegal_urem_same_block( 21; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[A:%.*]], [[B:%.*]] 22; CHECK-NEXT: [[REM:%.*]] = urem i32 [[A]], [[B]] 23; CHECK-NEXT: call void @foo(i32 [[REM]], i32 [[DIV]]) 24; CHECK-NEXT: ret void 25; 26 %div = udiv i32 %a, %b 27 %rem = urem i32 %a, %b 28 call void @foo(i32 %rem, i32 %div) 29 ret void 30} 31 32; Hoist and optionally decompose the sdiv because it's safe and free. 33; PR31028 - https://bugs.llvm.org/show_bug.cgi?id=31028 34 35define i32 @hoist_sdiv(i32 %a, i32 %b) { 36; CHECK-LABEL: @hoist_sdiv( 37; CHECK-NEXT: entry: 38; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A:%.*]], [[B:%.*]] 39; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A]], [[B]] 40; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[REM]], 42 41; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] 42; CHECK: if: 43; CHECK-NEXT: br label [[END]] 44; CHECK: end: 45; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] 46; CHECK-NEXT: ret i32 [[RET]] 47; 48entry: 49 %rem = srem i32 %a, %b 50 %cmp = icmp eq i32 %rem, 42 51 br i1 %cmp, label %if, label %end 52 53if: 54 %div = sdiv i32 %a, %b 55 br label %end 56 57end: 58 %ret = phi i32 [ %div, %if ], [ 3, %entry ] 59 ret i32 %ret 60} 61 62; Hoist and optionally decompose the udiv because it's safe and free. 63 64define i64 @hoist_udiv(i64 %a, i64 %b) { 65; CHECK-LABEL: @hoist_udiv( 66; CHECK-NEXT: entry: 67; CHECK-NEXT: [[REM:%.*]] = urem i64 [[A:%.*]], [[B:%.*]] 68; CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[A]], [[B]] 69; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[REM]], 42 70; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] 71; CHECK: if: 72; CHECK-NEXT: br label [[END]] 73; CHECK: end: 74; CHECK-NEXT: [[RET:%.*]] = phi i64 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] 75; CHECK-NEXT: ret i64 [[RET]] 76; 77entry: 78 %rem = urem i64 %a, %b 79 %cmp = icmp eq i64 %rem, 42 80 br i1 %cmp, label %if, label %end 81 82if: 83 %div = udiv i64 %a, %b 84 br label %end 85 86end: 87 %ret = phi i64 [ %div, %if ], [ 3, %entry ] 88 ret i64 %ret 89} 90 91; Hoist the srem if it's safe and free, otherwise decompose it. 92 93define i16 @hoist_srem(i16 %a, i16 %b) { 94; CHECK-LABEL: @hoist_srem( 95; CHECK-NEXT: entry: 96; CHECK-NEXT: [[DIV:%.*]] = sdiv i16 [[A:%.*]], [[B:%.*]] 97; CHECK-NEXT: [[REM:%.*]] = srem i16 [[A]], [[B]] 98; CHECK-NEXT: [[CMP:%.*]] = icmp eq i16 [[DIV]], 42 99; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] 100; CHECK: if: 101; CHECK-NEXT: br label [[END]] 102; CHECK: end: 103; CHECK-NEXT: [[RET:%.*]] = phi i16 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] 104; CHECK-NEXT: ret i16 [[RET]] 105; 106entry: 107 %div = sdiv i16 %a, %b 108 %cmp = icmp eq i16 %div, 42 109 br i1 %cmp, label %if, label %end 110 111if: 112 %rem = srem i16 %a, %b 113 br label %end 114 115end: 116 %ret = phi i16 [ %rem, %if ], [ 3, %entry ] 117 ret i16 %ret 118} 119 120; Hoist the urem if it's safe and free, otherwise decompose it. 121 122define i8 @hoist_urem(i8 %a, i8 %b) { 123; CHECK-LABEL: @hoist_urem( 124; CHECK-NEXT: entry: 125; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[A:%.*]], [[B:%.*]] 126; CHECK-NEXT: [[REM:%.*]] = urem i8 [[A]], [[B]] 127; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[DIV]], 42 128; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] 129; CHECK: if: 130; CHECK-NEXT: br label [[END]] 131; CHECK: end: 132; CHECK-NEXT: [[RET:%.*]] = phi i8 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] 133; CHECK-NEXT: ret i8 [[RET]] 134; 135entry: 136 %div = udiv i8 %a, %b 137 %cmp = icmp eq i8 %div, 42 138 br i1 %cmp, label %if, label %end 139 140if: 141 %rem = urem i8 %a, %b 142 br label %end 143 144end: 145 %ret = phi i8 [ %rem, %if ], [ 3, %entry ] 146 ret i8 %ret 147} 148 149; Be careful with RAUW/invalidation if this is a srem-of-srem. 150 151define i32 @srem_of_srem_unexpanded(i32 %X, i32 %Y, i32 %Z) { 152; CHECK-LABEL: @srem_of_srem_unexpanded( 153; CHECK-NEXT: [[T0:%.*]] = mul nsw i32 [[Z:%.*]], [[Y:%.*]] 154; CHECK-NEXT: [[T1:%.*]] = sdiv i32 [[X:%.*]], [[T0]] 155; CHECK-NEXT: [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]] 156; CHECK-NEXT: [[T3:%.*]] = srem i32 [[X]], [[T0]] 157; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3]], [[Y]] 158; CHECK-NEXT: [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]] 159; CHECK-NEXT: [[T6:%.*]] = srem i32 [[T3]], [[Y]] 160; CHECK-NEXT: ret i32 [[T6]] 161; 162 %t0 = mul nsw i32 %Z, %Y 163 %t1 = sdiv i32 %X, %t0 164 %t2 = mul nsw i32 %t0, %t1 165 %t3 = srem i32 %X, %t0 166 %t4 = sdiv i32 %t3, %Y 167 %t5 = mul nsw i32 %t4, %Y 168 %t6 = srem i32 %t3, %Y 169 ret i32 %t6 170} 171define i32 @srem_of_srem_expanded(i32 %X, i32 %Y, i32 %Z) { 172; CHECK-LABEL: @srem_of_srem_expanded( 173; CHECK-NEXT: [[T0:%.*]] = mul nsw i32 [[Z:%.*]], [[Y:%.*]] 174; CHECK-NEXT: [[T1:%.*]] = sdiv i32 [[X:%.*]], [[T0]] 175; CHECK-NEXT: [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]] 176; CHECK-NEXT: [[T3_RECOMPOSED:%.*]] = srem i32 [[X]], [[T0]] 177; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3_RECOMPOSED]], [[Y]] 178; CHECK-NEXT: [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]] 179; CHECK-NEXT: [[T6_RECOMPOSED:%.*]] = srem i32 [[T3_RECOMPOSED]], [[Y]] 180; CHECK-NEXT: ret i32 [[T6_RECOMPOSED]] 181; 182 %t0 = mul nsw i32 %Z, %Y 183 %t1 = sdiv i32 %X, %t0 184 %t2 = mul nsw i32 %t0, %t1 185 %t3 = sub nsw i32 %X, %t2 186 %t4 = sdiv i32 %t3, %Y 187 %t5 = mul nsw i32 %t4, %Y 188 %t6 = sub nsw i32 %t3, %t5 189 ret i32 %t6 190} 191 192; If the ops don't match, don't do anything: signedness. 193 194define i32 @dont_hoist_udiv(i32 %a, i32 %b) { 195; CHECK-LABEL: @dont_hoist_udiv( 196; CHECK-NEXT: entry: 197; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A:%.*]], [[B:%.*]] 198; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[REM]], 42 199; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] 200; CHECK: if: 201; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[A]], [[B]] 202; CHECK-NEXT: br label [[END]] 203; CHECK: end: 204; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] 205; CHECK-NEXT: ret i32 [[RET]] 206; 207entry: 208 %rem = srem i32 %a, %b 209 %cmp = icmp eq i32 %rem, 42 210 br i1 %cmp, label %if, label %end 211 212if: 213 %div = udiv i32 %a, %b 214 br label %end 215 216end: 217 %ret = phi i32 [ %div, %if ], [ 3, %entry ] 218 ret i32 %ret 219} 220 221; If the ops don't match, don't do anything: operation. 222 223define i32 @dont_hoist_srem(i32 %a, i32 %b) { 224; CHECK-LABEL: @dont_hoist_srem( 225; CHECK-NEXT: entry: 226; CHECK-NEXT: [[REM:%.*]] = urem i32 [[A:%.*]], [[B:%.*]] 227; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[REM]], 42 228; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] 229; CHECK: if: 230; CHECK-NEXT: [[REM2:%.*]] = srem i32 [[A]], [[B]] 231; CHECK-NEXT: br label [[END]] 232; CHECK: end: 233; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[REM2]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] 234; CHECK-NEXT: ret i32 [[RET]] 235; 236entry: 237 %rem = urem i32 %a, %b 238 %cmp = icmp eq i32 %rem, 42 239 br i1 %cmp, label %if, label %end 240 241if: 242 %rem2 = srem i32 %a, %b 243 br label %end 244 245end: 246 %ret = phi i32 [ %rem2, %if ], [ 3, %entry ] 247 ret i32 %ret 248} 249 250; If the ops don't match, don't do anything: operands. 251 252define i32 @dont_hoist_sdiv(i32 %a, i32 %b, i32 %c) { 253; CHECK-LABEL: @dont_hoist_sdiv( 254; CHECK-NEXT: entry: 255; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A:%.*]], [[B:%.*]] 256; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[REM]], 42 257; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] 258; CHECK: if: 259; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A]], [[C:%.*]] 260; CHECK-NEXT: br label [[END]] 261; CHECK: end: 262; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] 263; CHECK-NEXT: ret i32 [[RET]] 264; 265entry: 266 %rem = srem i32 %a, %b 267 %cmp = icmp eq i32 %rem, 42 268 br i1 %cmp, label %if, label %end 269 270if: 271 %div = sdiv i32 %a, %c 272 br label %end 273 274end: 275 %ret = phi i32 [ %div, %if ], [ 3, %entry ] 276 ret i32 %ret 277} 278 279; If the target doesn't have a unified div/rem op for the type, decompose rem in-place to mul+sub. 280 281define i128 @dont_hoist_urem(i128 %a, i128 %b) { 282; CHECK-LABEL: @dont_hoist_urem( 283; CHECK-NEXT: entry: 284; CHECK-NEXT: [[A_FROZEN:%.*]] = freeze i128 [[A:%.*]] 285; CHECK-NEXT: [[B_FROZEN:%.*]] = freeze i128 [[B:%.*]] 286; CHECK-NEXT: [[DIV:%.*]] = udiv i128 [[A_FROZEN]], [[B_FROZEN]] 287; CHECK-NEXT: [[CMP:%.*]] = icmp eq i128 [[DIV]], 42 288; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] 289; CHECK: if: 290; CHECK-NEXT: [[TMP0:%.*]] = mul i128 [[DIV]], [[B_FROZEN]] 291; CHECK-NEXT: [[REM_DECOMPOSED:%.*]] = sub i128 [[A_FROZEN]], [[TMP0]] 292; CHECK-NEXT: br label [[END]] 293; CHECK: end: 294; CHECK-NEXT: [[RET:%.*]] = phi i128 [ [[REM_DECOMPOSED]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] 295; CHECK-NEXT: ret i128 [[RET]] 296; 297entry: 298 %div = udiv i128 %a, %b 299 %cmp = icmp eq i128 %div, 42 300 br i1 %cmp, label %if, label %end 301 302if: 303 %rem = urem i128 %a, %b 304 br label %end 305 306end: 307 %ret = phi i128 [ %rem, %if ], [ 3, %entry ] 308 ret i128 %ret 309} 310 311; Hoist both ops to the common predecessor block. 312 313define i32 @no_domination(i1 %cmp, i32 %a, i32 %b) { 314; CHECK-LABEL: @no_domination( 315; CHECK-NEXT: entry: 316; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]] 317; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A]], [[B]] 318; CHECK-NEXT: br i1 [[CMP:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] 319; CHECK: if: 320; CHECK-NEXT: br label [[END:%.*]] 321; CHECK: else: 322; CHECK-NEXT: br label [[END]] 323; CHECK: end: 324; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ [[REM]], [[ELSE]] ] 325; CHECK-NEXT: ret i32 [[RET]] 326; 327entry: 328 br i1 %cmp, label %if, label %else 329 330if: 331 %div = sdiv i32 %a, %b 332 br label %end 333 334else: 335 %rem = srem i32 %a, %b 336 br label %end 337 338end: 339 %ret = phi i32 [ %div, %if ], [ %rem, %else ] 340 ret i32 %ret 341} 342 343define i64 @diamond_pred_has_other_sucessors(i64 %a, i64 %b, i64 %c) { 344; CHECK-LABEL: @diamond_pred_has_other_sucessors( 345; CHECK-NEXT: entry: 346; CHECK-NEXT: switch i64 [[A:%.*]], label [[RETURN:%.*]] [ 347; CHECK-NEXT: i64 0, label [[SW_BB:%.*]] 348; CHECK-NEXT: i64 1, label [[SW_BB1:%.*]] 349; CHECK-NEXT: ] 350; CHECK: sw.bb: 351; CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[B:%.*]], [[C:%.*]] 352; CHECK-NEXT: br label [[RETURN]] 353; CHECK: sw.bb1: 354; CHECK-NEXT: [[REM:%.*]] = urem i64 [[B]], [[C]] 355; CHECK-NEXT: br label [[RETURN]] 356; CHECK: return: 357; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i64 [ [[REM]], [[SW_BB1]] ], [ [[DIV]], [[SW_BB]] ], [ 0, [[ENTRY:%.*]] ] 358; CHECK-NEXT: ret i64 [[RETVAL_0]] 359; 360entry: 361 switch i64 %a, label %return [ 362 i64 0, label %sw.bb 363 i64 1, label %sw.bb1 364 ] 365 366sw.bb: ; preds = %entry 367 %div = udiv i64 %b, %c 368 br label %return 369 370sw.bb1: ; preds = %entry 371 %rem = urem i64 %b, %c 372 br label %return 373 374return: ; preds = %entry, %sw.bb1, %sw.bb 375 %retval.0 = phi i64 [ %rem, %sw.bb1 ], [ %div, %sw.bb ], [ 0, %entry ] 376 ret i64 %retval.0 377} 378 379define i64 @diamond_div_no_unique_predecessor(i64 %a, i64 %b, i64 %c) { 380; CHECK-LABEL: @diamond_div_no_unique_predecessor( 381; CHECK-NEXT: entry: 382; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[A:%.*]], -1 383; CHECK-NEXT: br i1 [[CMP]], label [[FOO:%.*]], label [[IF_END:%.*]] 384; CHECK: if.end: 385; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i64 [[A]], 1 386; CHECK-NEXT: br i1 [[CMP1]], label [[BAR:%.*]], label [[BAZ:%.*]] 387; CHECK: baz: 388; CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[B:%.*]], [[C:%.*]] 389; CHECK-NEXT: br label [[RETURN:%.*]] 390; CHECK: foo: 391; CHECK-NEXT: br label [[BAZ]] 392; CHECK: bar: 393; CHECK-NEXT: [[REM:%.*]] = urem i64 [[B]], [[C]] 394; CHECK-NEXT: br label [[RETURN]] 395; CHECK: return: 396; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i64 [ [[DIV]], [[BAZ]] ], [ [[REM]], [[BAR]] ] 397; CHECK-NEXT: ret i64 [[RETVAL_0]] 398; 399entry: 400 %cmp = icmp slt i64 %a, -1 401 br i1 %cmp, label %foo, label %if.end 402 403if.end: 404 %cmp1 = icmp sgt i64 %a, 1 405 br i1 %cmp1, label %bar, label %baz 406 407baz: 408 %div = udiv i64 %b, %c 409 br label %return 410 411foo: 412 br label %baz 413 414bar: 415 %rem = urem i64 %b, %c 416 br label %return 417 418return: 419 %retval.0 = phi i64 [ %div, %baz ], [ %rem, %bar ] 420 ret i64 %retval.0 421} 422 423define i64 @diamond_rem_no_unique_predecessor(i64 %a, i64 %b, i64 %c) { 424; CHECK-LABEL: @diamond_rem_no_unique_predecessor( 425; CHECK-NEXT: entry: 426; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[A:%.*]], -1 427; CHECK-NEXT: br i1 [[CMP]], label [[FOO:%.*]], label [[IF_END:%.*]] 428; CHECK: if.end: 429; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i64 [[A]], 1 430; CHECK-NEXT: br i1 [[CMP1]], label [[BAR:%.*]], label [[BAZ:%.*]] 431; CHECK: baz: 432; CHECK-NEXT: [[REM:%.*]] = urem i64 [[B:%.*]], [[C:%.*]] 433; CHECK-NEXT: br label [[RETURN:%.*]] 434; CHECK: foo: 435; CHECK-NEXT: br label [[BAZ]] 436; CHECK: bar: 437; CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[B]], [[C]] 438; CHECK-NEXT: br label [[RETURN]] 439; CHECK: return: 440; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i64 [ [[REM]], [[BAZ]] ], [ [[DIV]], [[BAR]] ] 441; CHECK-NEXT: ret i64 [[RETVAL_0]] 442; 443entry: 444 %cmp = icmp slt i64 %a, -1 445 br i1 %cmp, label %foo, label %if.end 446 447if.end: 448 %cmp1 = icmp sgt i64 %a, 1 449 br i1 %cmp1, label %bar, label %baz 450 451baz: 452 %rem = urem i64 %b, %c 453 br label %return 454 455foo: 456 br label %baz 457 458bar: 459 %div = udiv i64 %b, %c 460 br label %return 461 462return: 463 %retval.0 = phi i64 [ %rem, %baz ], [ %div, %bar ] 464 ret i64 %retval.0 465} 466 467declare void @dummy() 468 469define i32 @invoke_not_willreturn(i32 %a, i32 %b) personality ptr null { 470; CHECK-LABEL: @invoke_not_willreturn( 471; CHECK-NEXT: entry: 472; CHECK-NEXT: invoke void @dummy() 473; CHECK-NEXT: to label [[CONT:%.*]] unwind label [[LPAD:%.*]] 474; CHECK: cont: 475; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]] 476; CHECK-NEXT: ret i32 [[DIV]] 477; CHECK: lpad: 478; CHECK-NEXT: [[TMP0:%.*]] = landingpad { ptr, i32 } 479; CHECK-NEXT: cleanup 480; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A]], [[B]] 481; CHECK-NEXT: ret i32 [[REM]] 482; 483entry: 484 invoke void @dummy() 485 to label %cont unwind label %lpad 486 487cont: 488 %div = sdiv i32 %a, %b 489 ret i32 %div 490 491lpad: 492 landingpad { ptr, i32 } 493 cleanup 494 %rem = srem i32 %a, %b 495 ret i32 %rem 496} 497 498define i32 @invoke_willreturn(i32 %a, i32 %b) personality ptr null { 499; CHECK-LABEL: @invoke_willreturn( 500; CHECK-NEXT: entry: 501; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]] 502; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A]], [[B]] 503; CHECK-NEXT: invoke void @dummy() #[[ATTR0:[0-9]+]] 504; CHECK-NEXT: to label [[CONT:%.*]] unwind label [[LPAD:%.*]] 505; CHECK: cont: 506; CHECK-NEXT: ret i32 [[DIV]] 507; CHECK: lpad: 508; CHECK-NEXT: [[TMP0:%.*]] = landingpad { ptr, i32 } 509; CHECK-NEXT: cleanup 510; CHECK-NEXT: ret i32 [[REM]] 511; 512entry: 513 invoke void @dummy() willreturn 514 to label %cont unwind label %lpad 515 516cont: 517 %div = sdiv i32 %a, %b 518 ret i32 %div 519 520lpad: 521 landingpad { ptr, i32 } 522 cleanup 523 %rem = srem i32 %a, %b 524 ret i32 %rem 525} 526 527; Use this personality function so that catchpad is guaranteed to transfer. 528declare void @ProcessCLRException() 529 530define i32 @catchswitch(i32 %a, i32 %b) personality ptr @ProcessCLRException { 531; CHECK-LABEL: @catchswitch( 532; CHECK-NEXT: entry: 533; CHECK-NEXT: invoke void @dummy() #[[ATTR0]] 534; CHECK-NEXT: to label [[CONT:%.*]] unwind label [[LPAD:%.*]] 535; CHECK: cont: 536; CHECK-NEXT: ret i32 0 537; CHECK: lpad: 538; CHECK-NEXT: [[CS:%.*]] = catchswitch within none [label %cp] unwind label [[LPAD_END:%.*]] 539; CHECK: cp: 540; CHECK-NEXT: [[TMP0:%.*]] = catchpad within [[CS]] [] 541; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]] 542; CHECK-NEXT: ret i32 [[DIV]] 543; CHECK: lpad.end: 544; CHECK-NEXT: [[TMP1:%.*]] = cleanuppad within none [] 545; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A]], [[B]] 546; CHECK-NEXT: ret i32 [[REM]] 547; 548entry: 549 invoke void @dummy() willreturn 550 to label %cont unwind label %lpad 551 552cont: 553 ret i32 0 554 555lpad: 556 %cs = catchswitch within none [label %cp] unwind label %lpad.end 557 558cp: 559 catchpad within %cs [] 560 %div = sdiv i32 %a, %b 561 ret i32 %div 562 563lpad.end: 564 cleanuppad within none [] 565 %rem = srem i32 %a, %b 566 ret i32 %rem 567} 568