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