1; RUN: opt -mtriple=x86_64-pc-windows-msvc -S -winehprepare < %s | FileCheck %s 2 3declare i32 @__CxxFrameHandler3(...) 4declare i32 @__C_specific_handler(...) 5declare void @ProcessCLRException(...) 6 7declare void @f() 8 9declare void @llvm.foo(i32) nounwind 10declare void @llvm.bar() nounwind 11declare i32 @llvm.qux() nounwind 12declare i1 @llvm.baz() nounwind 13 14define void @test1() personality i32 (...)* @__CxxFrameHandler3 { 15entry: 16 ; %x def colors: {entry} subset of use colors; must spill 17 %x = call i32 @llvm.qux() 18 invoke void @f() 19 to label %noreturn unwind label %catch.switch 20catch.switch: 21 %cs = catchswitch within none [label %catch] unwind to caller 22catch: 23 %cp = catchpad within %cs [] 24 br label %noreturn 25noreturn: 26 ; %x use colors: {entry, cleanup} 27 call void @llvm.foo(i32 %x) 28 unreachable 29} 30; Need two copies of the call to @h, one under entry and one under catch. 31; Currently we generate a load for each, though we shouldn't need one 32; for the use in entry's copy. 33; CHECK-LABEL: define void @test1( 34; CHECK: entry: 35; CHECK: %x = call i32 @llvm.qux() 36; CHECK: invoke void @f() 37; CHECK: to label %[[EntryCopy:[^ ]+]] unwind label %catch 38; CHECK: catch.switch: 39; CHECK: %cs = catchswitch within none [label %catch] unwind to caller 40; CHECK: catch: 41; CHECK: catchpad within %cs [] 42; CHECK-NEXT: call void @llvm.foo(i32 %x) 43; CHECK: [[EntryCopy]]: 44; CHECK: call void @llvm.foo(i32 %x) 45 46 47define void @test2() personality i32 (...)* @__CxxFrameHandler3 { 48entry: 49 invoke void @f() 50 to label %exit unwind label %cleanup 51cleanup: 52 cleanuppad within none [] 53 br label %exit 54exit: 55 call void @llvm.bar() 56 ret void 57} 58; Need two copies of %exit's call to @f -- the subsequent ret is only 59; valid when coming from %entry, but on the path from %cleanup, this 60; might be a valid call to @f which might dynamically not return. 61; CHECK-LABEL: define void @test2( 62; CHECK: entry: 63; CHECK: invoke void @f() 64; CHECK: to label %[[exit:[^ ]+]] unwind label %cleanup 65; CHECK: cleanup: 66; CHECK: cleanuppad within none [] 67; CHECK: call void @llvm.bar() 68; CHECK-NEXT: unreachable 69; CHECK: [[exit]]: 70; CHECK: call void @llvm.bar() 71; CHECK-NEXT: ret void 72 73 74define void @test3() personality i32 (...)* @__CxxFrameHandler3 { 75entry: 76 invoke void @f() 77 to label %invoke.cont unwind label %catch.switch 78invoke.cont: 79 invoke void @f() 80 to label %exit unwind label %cleanup 81catch.switch: 82 %cs = catchswitch within none [label %catch] unwind to caller 83catch: 84 catchpad within %cs [] 85 br label %shared 86cleanup: 87 cleanuppad within none [] 88 br label %shared 89shared: 90 call void @llvm.bar() 91 br label %exit 92exit: 93 ret void 94} 95; Need two copies of %shared's call to @f (similar to @test2 but 96; the two regions here are siblings, not parent-child). 97; CHECK-LABEL: define void @test3( 98; CHECK: invoke void @f() 99; CHECK: invoke void @f() 100; CHECK: to label %[[exit:[^ ]+]] unwind 101; CHECK: catch: 102; CHECK: catchpad within %cs [] 103; CHECK-NEXT: call void @llvm.bar() 104; CHECK-NEXT: unreachable 105; CHECK: cleanup: 106; CHECK: cleanuppad within none [] 107; CHECK: call void @llvm.bar() 108; CHECK-NEXT: unreachable 109; CHECK: [[exit]]: 110; CHECK: ret void 111 112 113define void @test4() personality i32 (...)* @__CxxFrameHandler3 { 114entry: 115 invoke void @f() 116 to label %shared unwind label %catch.switch 117catch.switch: 118 %cs = catchswitch within none [label %catch] unwind to caller 119catch: 120 catchpad within %cs [] 121 br label %shared 122shared: 123 %x = call i32 @llvm.qux() 124 %i = call i32 @llvm.qux() 125 %zero.trip = icmp eq i32 %i, 0 126 br i1 %zero.trip, label %exit, label %loop 127loop: 128 %i.loop = phi i32 [ %i, %shared ], [ %i.dec, %loop.tail ] 129 %b = call i1 @llvm.baz() 130 br i1 %b, label %left, label %right 131left: 132 %y = call i32 @llvm.qux() 133 br label %loop.tail 134right: 135 call void @llvm.foo(i32 %x) 136 br label %loop.tail 137loop.tail: 138 %i.dec = sub i32 %i.loop, 1 139 %done = icmp eq i32 %i.dec, 0 140 br i1 %done, label %exit, label %loop 141exit: 142 call void @llvm.foo(i32 %x) 143 unreachable 144} 145; Make sure we can clone regions that have internal control 146; flow and SSA values. Here we need two copies of everything 147; from %shared to %exit. 148; CHECK-LABEL: define void @test4( 149; CHECK: entry: 150; CHECK: to label %[[shared_E:[^ ]+]] unwind label %catch.switch 151; CHECK: catch: 152; CHECK: catchpad within %cs [] 153; CHECK: [[x_C:%[^ ]+]] = call i32 @llvm.qux() 154; CHECK: [[i_C:%[^ ]+]] = call i32 @llvm.qux() 155; CHECK: [[zt_C:%[^ ]+]] = icmp eq i32 [[i_C]], 0 156; CHECK: br i1 [[zt_C]], label %[[exit_C:[^ ]+]], label %[[loop_C:[^ ]+]] 157; CHECK: [[shared_E]]: 158; CHECK: [[x_E:%[^ ]+]] = call i32 @llvm.qux() 159; CHECK: [[i_E:%[^ ]+]] = call i32 @llvm.qux() 160; CHECK: [[zt_E:%[^ ]+]] = icmp eq i32 [[i_E]], 0 161; CHECK: br i1 [[zt_E]], label %[[exit_E:[^ ]+]], label %[[loop_E:[^ ]+]] 162; CHECK: [[loop_C]]: 163; CHECK: [[iloop_C:%[^ ]+]] = phi i32 [ [[i_C]], %catch ], [ [[idec_C:%[^ ]+]], %[[looptail_C:[^ ]+]] ] 164; CHECK: [[b_C:%[^ ]+]] = call i1 @llvm.baz() 165; CHECK: br i1 [[b_C]], label %[[left_C:[^ ]+]], label %[[right_C:[^ ]+]] 166; CHECK: [[loop_E]]: 167; CHECK: [[iloop_E:%[^ ]+]] = phi i32 [ [[i_E]], %[[shared_E]] ], [ [[idec_E:%[^ ]+]], %[[looptail_E:[^ ]+]] ] 168; CHECK: [[b_E:%[^ ]+]] = call i1 @llvm.baz() 169; CHECK: br i1 [[b_E]], label %[[left_E:[^ ]+]], label %[[right_E:[^ ]+]] 170; CHECK: [[left_C]]: 171; CHECK: [[y_C:%[^ ]+]] = call i32 @llvm.qux() 172; CHECK: br label %[[looptail_C]] 173; CHECK: [[left_E]]: 174; CHECK: [[y_E:%[^ ]+]] = call i32 @llvm.qux() 175; CHECK: br label %[[looptail_E]] 176; CHECK: [[right_C]]: 177; CHECK: call void @llvm.foo(i32 [[x_C]]) 178; CHECK: br label %[[looptail_C]] 179; CHECK: [[right_E]]: 180; CHECK: call void @llvm.foo(i32 [[x_E]]) 181; CHECK: br label %[[looptail_E]] 182; CHECK: [[looptail_C]]: 183; CHECK: [[idec_C]] = sub i32 [[iloop_C]], 1 184; CHECK: [[done_C:%[^ ]+]] = icmp eq i32 [[idec_C]], 0 185; CHECK: br i1 [[done_C]], label %[[exit_C]], label %[[loop_C]] 186; CHECK: [[looptail_E]]: 187; CHECK: [[idec_E]] = sub i32 [[iloop_E]], 1 188; CHECK: [[done_E:%[^ ]+]] = icmp eq i32 [[idec_E]], 0 189; CHECK: br i1 [[done_E]], label %[[exit_E]], label %[[loop_E]] 190; CHECK: [[exit_C]]: 191; CHECK: call void @llvm.foo(i32 [[x_C]]) 192; CHECK: unreachable 193; CHECK: [[exit_E]]: 194; CHECK: call void @llvm.foo(i32 [[x_E]]) 195; CHECK: unreachable 196 197 198define void @test5() personality i32 (...)* @__C_specific_handler { 199entry: 200 invoke void @f() 201 to label %exit unwind label %outer 202outer: 203 %o = cleanuppad within none [] 204 %x = call i32 @llvm.qux() 205 invoke void @f() [ "funclet"(token %o) ] 206 to label %outer.ret unwind label %catch.switch 207catch.switch: 208 %cs = catchswitch within %o [label %inner] unwind to caller 209inner: 210 %i = catchpad within %cs [] 211 catchret from %i to label %outer.post-inner 212outer.post-inner: 213 call void @llvm.foo(i32 %x) 214 br label %outer.ret 215outer.ret: 216 cleanupret from %o unwind to caller 217exit: 218 ret void 219} 220; Simple nested case (catch-inside-cleanup). Nothing needs 221; to be cloned. The def and use of %x are both in %outer 222; and so don't need to be spilled. 223; CHECK-LABEL: define void @test5( 224; CHECK: outer: 225; CHECK: %x = call i32 @llvm.qux() 226; CHECK-NEXT: invoke void @f() 227; CHECK-NEXT: to label %outer.ret unwind label %catch.switch 228; CHECK: inner: 229; CHECK-NEXT: %i = catchpad within %cs [] 230; CHECK-NEXT: catchret from %i to label %outer.post-inner 231; CHECK: outer.post-inner: 232; CHECK-NEXT: call void @llvm.foo(i32 %x) 233; CHECK-NEXT: br label %outer.ret 234 235 236define void @test10() personality i32 (...)* @__CxxFrameHandler3 { 237entry: 238 invoke void @f() 239 to label %unreachable unwind label %inner 240inner: 241 %cleanup = cleanuppad within none [] 242 ; make sure we don't overlook this cleanupret and try to process 243 ; successor %outer as a child of inner. 244 cleanupret from %cleanup unwind label %outer 245outer: 246 %cs = catchswitch within none [label %catch.body] unwind to caller 247 248catch.body: 249 %catch = catchpad within %cs [] 250 catchret from %catch to label %exit 251exit: 252 ret void 253unreachable: 254 unreachable 255} 256; CHECK-LABEL: define void @test10( 257; CHECK-NEXT: entry: 258; CHECK-NEXT: invoke 259; CHECK-NEXT: to label %unreachable unwind label %inner 260; CHECK: inner: 261; CHECK-NEXT: %cleanup = cleanuppad within none [] 262; CHECK-NEXT: cleanupret from %cleanup unwind label %outer 263; CHECK: outer: 264; CHECK-NEXT: %cs = catchswitch within none [label %catch.body] unwind to caller 265; CHECK: catch.body: 266; CHECK-NEXT: %catch = catchpad within %cs [] 267; CHECK-NEXT: catchret from %catch to label %exit 268; CHECK: exit: 269; CHECK-NEXT: ret void 270 271define void @test11() personality i32 (...)* @__C_specific_handler { 272entry: 273 invoke void @f() 274 to label %exit unwind label %cleanup.outer 275cleanup.outer: 276 %outer = cleanuppad within none [] 277 invoke void @f() [ "funclet"(token %outer) ] 278 to label %outer.cont unwind label %cleanup.inner 279outer.cont: 280 br label %merge 281cleanup.inner: 282 %inner = cleanuppad within %outer [] 283 br label %merge 284merge: 285 call void @llvm.bar() 286 unreachable 287exit: 288 ret void 289} 290; merge.end will get cloned for outer and inner, but is implausible 291; from inner, so the call @f() in inner's copy of merge should be 292; rewritten to call @f() 293; CHECK-LABEL: define void @test11() 294; CHECK: %inner = cleanuppad within %outer [] 295; CHECK-NEXT: call void @llvm.bar() 296; CHECK-NEXT: unreachable 297 298define void @test12() personality i32 (...)* @__CxxFrameHandler3 !dbg !5 { 299entry: 300 invoke void @f() 301 to label %cont unwind label %left, !dbg !8 302cont: 303 invoke void @f() 304 to label %exit unwind label %right 305left: 306 cleanuppad within none [] 307 br label %join 308right: 309 cleanuppad within none [] 310 br label %join 311join: 312 ; This call will get cloned; make sure we can handle cloning 313 ; instructions with debug metadata attached. 314 call void @llvm.bar(), !dbg !9 315 unreachable 316exit: 317 ret void 318} 319 320; CHECK-LABEL: define void @test13() 321; CHECK: ret void 322define void @test13() personality i32 (...)* @__CxxFrameHandler3 { 323entry: 324 ret void 325 326unreachable: 327 cleanuppad within none [] 328 unreachable 329} 330 331define void @test14() personality void (...)* @ProcessCLRException { 332entry: 333 invoke void @f() 334 to label %cont unwind label %cleanup 335cont: 336 invoke void @f() 337 to label %exit unwind label %switch.outer 338cleanup: 339 %cleanpad = cleanuppad within none [] 340 invoke void @f() [ "funclet" (token %cleanpad) ] 341 to label %cleanret unwind label %switch.inner 342switch.inner: 343 %cs.inner = catchswitch within %cleanpad [label %pad.inner] unwind to caller 344pad.inner: 345 %cp.inner = catchpad within %cs.inner [i32 1] 346 catchret from %cp.inner to label %join 347cleanret: 348 cleanupret from %cleanpad unwind to caller 349switch.outer: 350 %cs.outer = catchswitch within none [label %pad.outer] unwind to caller 351pad.outer: 352 %cp.outer = catchpad within %cs.outer [i32 2] 353 catchret from %cp.outer to label %join 354join: 355 %phi = phi i32 [ 1, %pad.inner ], [ 2, %pad.outer ] 356 call void @llvm.foo(i32 %phi) 357 unreachable 358exit: 359 ret void 360} 361; Both catchrets target %join, but the catchret from %cp.inner 362; returns to %cleanpad and the catchret from %cp.outer returns to the 363; main function, so %join needs to get cloned and one of the cleanuprets 364; needs to be updated to target the clone 365; CHECK-LABEL: define void @test14() 366; CHECK: catchret from %cp.inner to label %[[Clone1:.+]] 367; CHECK: catchret from %cp.outer to label %[[Clone2:.+]] 368; CHECK: [[Clone1]]: 369; CHECK-NEXT: call void @llvm.foo(i32 1) 370; CHECK-NEXT: unreachable 371; CHECK: [[Clone2]]: 372; CHECK-NEXT: call void @llvm.foo(i32 2) 373; CHECK-NEXT: unreachable 374 375;; Debug info (from test12) 376 377; Make sure the DISubprogram doesn't get cloned 378; CHECK-LABEL: !llvm.module.flags 379; CHECK-NOT: !DISubprogram 380; CHECK: !{{[0-9]+}} = distinct !DISubprogram(name: "test12" 381; CHECK-NOT: !DISubprogram 382!llvm.module.flags = !{!0} 383!llvm.dbg.cu = !{!1} 384 385!0 = !{i32 2, !"Debug Info Version", i32 3} 386!1 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !2, producer: "compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !3) 387!2 = !DIFile(filename: "test.cpp", directory: ".") 388!3 = !{} 389!5 = distinct !DISubprogram(name: "test12", scope: !2, file: !2, type: !6, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !1, retainedNodes: !3) 390!6 = !DISubroutineType(types: !7) 391!7 = !{null} 392!8 = !DILocation(line: 1, scope: !5) 393!9 = !DILocation(line: 2, scope: !5) 394