brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.4 KiB · 2b9e3bd Raw
397 lines · plain
1; RUN: opt -mtriple=x86_64-pc-windows-msvc -S -win-eh-prepare  < %s | FileCheck %s2; RUN: opt -mtriple=x86_64-pc-windows-msvc -S -passes=win-eh-prepare  < %s | FileCheck %s3; RUN: %if aarch64-registered-target %{ opt -mtriple=aarch64-pc-windows-msvc -S -win-eh-prepare  < %s | FileCheck %s %}4; RUN: %if aarch64-registered-target %{ opt -mtriple=aarch64-pc-windows-msvc -S -passes=win-eh-prepare  < %s | FileCheck %s %}5 6declare i32 @__CxxFrameHandler3(...)7declare i32 @__C_specific_handler(...)8declare void @ProcessCLRException(...)9 10declare void @f()11 12declare void @llvm.foo(i32) nounwind13declare void @llvm.bar() nounwind14declare i32 @llvm.qux() nounwind15declare i1 @llvm.baz() nounwind16 17define void @test1() personality ptr @__CxxFrameHandler3 {18entry:19  ; %x def colors: {entry} subset of use colors; must spill20  %x = call i32 @llvm.qux()21  invoke void @f()22    to label %noreturn unwind label %catch.switch23catch.switch:24  %cs = catchswitch within none [label %catch] unwind to caller25catch:26  %cp = catchpad within %cs []27  br label %noreturn28noreturn:29  ; %x use colors: {entry, cleanup}30  call void @llvm.foo(i32 %x)31  unreachable32}33; Need two copies of the call to @h, one under entry and one under catch.34; Currently we generate a load for each, though we shouldn't need one35; for the use in entry's copy.36; CHECK-LABEL: define void @test1(37; CHECK: entry:38; CHECK:   %x = call i32 @llvm.qux()39; CHECK:   invoke void @f()40; CHECK:     to label %[[EntryCopy:[^ ]+]] unwind label %catch41; CHECK: catch.switch:42; CHECK:   %cs = catchswitch within none [label %catch] unwind to caller43; CHECK: catch:44; CHECK:   catchpad within %cs []45; CHECK-NEXT: call void @llvm.foo(i32 %x)46; CHECK: [[EntryCopy]]:47; CHECK:   call void @llvm.foo(i32 %x)48 49 50define void @test2() personality ptr @__CxxFrameHandler3 {51entry:52  invoke void @f()53    to label %exit unwind label %cleanup54cleanup:55  cleanuppad within none []56  br label %exit57exit:58  call void @llvm.bar()59  ret void60}61; Need two copies of %exit's call to @f -- the subsequent ret is only62; valid when coming from %entry, but on the path from %cleanup, this63; might be a valid call to @f which might dynamically not return.64; CHECK-LABEL: define void @test2(65; CHECK: entry:66; CHECK:   invoke void @f()67; CHECK:     to label %[[exit:[^ ]+]] unwind label %cleanup68; CHECK: cleanup:69; CHECK:   cleanuppad within none []70; CHECK:   call void @llvm.bar()71; CHECK-NEXT: unreachable72; CHECK: [[exit]]:73; CHECK:   call void @llvm.bar()74; CHECK-NEXT: ret void75 76 77define void @test3() personality ptr @__CxxFrameHandler3 {78entry:79  invoke void @f()80    to label %invoke.cont unwind label %catch.switch81invoke.cont:82  invoke void @f()83    to label %exit unwind label %cleanup84catch.switch:85  %cs = catchswitch within none [label %catch] unwind to caller86catch:87  catchpad within %cs []88  br label %shared89cleanup:90  cleanuppad within none []91  br label %shared92shared:93  call void @llvm.bar()94  br label %exit95exit:96  ret void97}98; Need two copies of %shared's call to @f (similar to @test2 but99; the two regions here are siblings, not parent-child).100; CHECK-LABEL: define void @test3(101; CHECK:   invoke void @f()102; CHECK:   invoke void @f()103; CHECK:     to label %[[exit:[^ ]+]] unwind104; CHECK: catch:105; CHECK:   catchpad within %cs []106; CHECK-NEXT: call void @llvm.bar()107; CHECK-NEXT: unreachable108; CHECK: cleanup:109; CHECK:   cleanuppad within none []110; CHECK:   call void @llvm.bar()111; CHECK-NEXT: unreachable112; CHECK: [[exit]]:113; CHECK:   ret void114 115 116define void @test4() personality ptr @__CxxFrameHandler3 {117entry:118  invoke void @f()119    to label %shared unwind label %catch.switch120catch.switch:121  %cs = catchswitch within none [label %catch] unwind to caller122catch:123  catchpad within %cs []124  br label %shared125shared:126  %x = call i32 @llvm.qux()127  %i = call i32 @llvm.qux()128  %zero.trip = icmp eq i32 %i, 0129  br i1 %zero.trip, label %exit, label %loop130loop:131  %i.loop = phi i32 [ %i, %shared ], [ %i.dec, %loop.tail ]132  %b = call i1 @llvm.baz()133  br i1 %b, label %left, label %right134left:135  %y = call i32 @llvm.qux()136  br label %loop.tail137right:138  call void @llvm.foo(i32 %x)139  br label %loop.tail140loop.tail:141  %i.dec = sub i32 %i.loop, 1142  %done = icmp eq i32 %i.dec, 0143  br i1 %done, label %exit, label %loop144exit:145  call void @llvm.foo(i32 %x)146  unreachable147}148; Make sure we can clone regions that have internal control149; flow and SSA values.  Here we need two copies of everything150; from %shared to %exit.151; CHECK-LABEL: define void @test4(152; CHECK:  entry:153; CHECK:    to label %[[shared_E:[^ ]+]] unwind label %catch.switch154; CHECK:  catch:155; CHECK:    catchpad within %cs []156; CHECK:    [[x_C:%[^ ]+]] = call i32 @llvm.qux()157; CHECK:    [[i_C:%[^ ]+]] = call i32 @llvm.qux()158; CHECK:    [[zt_C:%[^ ]+]] = icmp eq i32 [[i_C]], 0159; CHECK:    br i1 [[zt_C]], label %[[exit_C:[^ ]+]], label %[[loop_C:[^ ]+]]160; CHECK:  [[shared_E]]:161; CHECK:    [[x_E:%[^ ]+]] = call i32 @llvm.qux()162; CHECK:    [[i_E:%[^ ]+]] = call i32 @llvm.qux()163; CHECK:    [[zt_E:%[^ ]+]] = icmp eq i32 [[i_E]], 0164; CHECK:    br i1 [[zt_E]], label %[[exit_E:[^ ]+]], label %[[loop_E:[^ ]+]]165; CHECK:  [[loop_C]]:166; CHECK:    [[iloop_C:%[^ ]+]] = phi i32 [ [[i_C]], %catch ], [ [[idec_C:%[^ ]+]], %[[looptail_C:[^ ]+]] ]167; CHECK:    [[b_C:%[^ ]+]] = call i1 @llvm.baz()168; CHECK:    br i1 [[b_C]], label %[[left_C:[^ ]+]], label %[[right_C:[^ ]+]]169; CHECK:  [[loop_E]]:170; CHECK:    [[iloop_E:%[^ ]+]] = phi i32 [ [[i_E]], %[[shared_E]] ], [ [[idec_E:%[^ ]+]], %[[looptail_E:[^ ]+]] ]171; CHECK:    [[b_E:%[^ ]+]] = call i1 @llvm.baz()172; CHECK:    br i1 [[b_E]], label %[[left_E:[^ ]+]], label %[[right_E:[^ ]+]]173; CHECK:  [[left_C]]:174; CHECK:    [[y_C:%[^ ]+]] = call i32 @llvm.qux()175; CHECK:    br label %[[looptail_C]]176; CHECK:  [[left_E]]:177; CHECK:    [[y_E:%[^ ]+]] = call i32 @llvm.qux()178; CHECK:    br label %[[looptail_E]]179; CHECK:  [[right_C]]:180; CHECK:    call void @llvm.foo(i32 [[x_C]])181; CHECK:    br label %[[looptail_C]]182; CHECK:  [[right_E]]:183; CHECK:    call void @llvm.foo(i32 [[x_E]])184; CHECK:    br label %[[looptail_E]]185; CHECK:  [[looptail_C]]:186; CHECK:    [[idec_C]] = sub i32 [[iloop_C]], 1187; CHECK:    [[done_C:%[^ ]+]] = icmp eq i32 [[idec_C]], 0188; CHECK:    br i1 [[done_C]], label %[[exit_C]], label %[[loop_C]]189; CHECK:  [[looptail_E]]:190; CHECK:    [[idec_E]] = sub i32 [[iloop_E]], 1191; CHECK:    [[done_E:%[^ ]+]] = icmp eq i32 [[idec_E]], 0192; CHECK:    br i1 [[done_E]], label %[[exit_E]], label %[[loop_E]]193; CHECK:  [[exit_C]]:194; CHECK:    call void @llvm.foo(i32 [[x_C]])195; CHECK:    unreachable196; CHECK:  [[exit_E]]:197; CHECK:    call void @llvm.foo(i32 [[x_E]])198; CHECK:    unreachable199 200 201define void @test5() personality ptr @__C_specific_handler {202entry:203  invoke void @f()204    to label %exit unwind label %outer205outer:206  %o = cleanuppad within none []207  %x = call i32 @llvm.qux()208  invoke void @f() [ "funclet"(token %o) ]209    to label %outer.ret unwind label %catch.switch210catch.switch:211  %cs = catchswitch within %o [label %inner] unwind to caller212inner:213  %i = catchpad within %cs []214  catchret from %i to label %outer.post-inner215outer.post-inner:216  call void @llvm.foo(i32 %x)217  br label %outer.ret218outer.ret:219  cleanupret from %o unwind to caller220exit:221  ret void222}223; Simple nested case (catch-inside-cleanup).  Nothing needs224; to be cloned.  The def and use of %x are both in %outer225; and so don't need to be spilled.226; CHECK-LABEL: define void @test5(227; CHECK:      outer:228; CHECK:        %x = call i32 @llvm.qux()229; CHECK-NEXT:   invoke void @f()230; CHECK-NEXT:     to label %outer.ret unwind label %catch.switch231; CHECK:      inner:232; CHECK-NEXT:   %i = catchpad within %cs []233; CHECK-NEXT:   catchret from %i to label %outer.post-inner234; CHECK:      outer.post-inner:235; CHECK-NEXT:   call void @llvm.foo(i32 %x)236; CHECK-NEXT:   br label %outer.ret237 238 239define void @test10() personality ptr @__CxxFrameHandler3 {240entry:241  invoke void @f()242    to label %unreachable unwind label %inner243inner:244  %cleanup = cleanuppad within none []245  ; make sure we don't overlook this cleanupret and try to process246  ; successor %outer as a child of inner.247  cleanupret from %cleanup unwind label %outer248outer:249  %cs = catchswitch within none [label %catch.body] unwind to caller250 251catch.body:252  %catch = catchpad within %cs []253  catchret from %catch to label %exit254exit:255  ret void256unreachable:257  unreachable258}259; CHECK-LABEL: define void @test10(260; CHECK-NEXT: entry:261; CHECK-NEXT:   invoke262; CHECK-NEXT:     to label %unreachable unwind label %inner263; CHECK:      inner:264; CHECK-NEXT:   %cleanup = cleanuppad within none []265; CHECK-NEXT:   cleanupret from %cleanup unwind label %outer266; CHECK:      outer:267; CHECK-NEXT:   %cs = catchswitch within none [label %catch.body] unwind to caller268; CHECK:      catch.body:269; CHECK-NEXT:   %catch = catchpad within %cs []270; CHECK-NEXT:   catchret from %catch to label %exit271; CHECK:      exit:272; CHECK-NEXT:   ret void273 274define void @test11() personality ptr @__C_specific_handler {275entry:276  invoke void @f()277    to label %exit unwind label %cleanup.outer278cleanup.outer:279  %outer = cleanuppad within none []280  invoke void @f() [ "funclet"(token %outer) ]281    to label %outer.cont unwind label %cleanup.inner282outer.cont:283  br label %merge284cleanup.inner:285  %inner = cleanuppad within %outer []286  br label %merge287merge:288  call void @llvm.bar()289  unreachable290exit:291  ret void292}293; merge.end will get cloned for outer and inner, but is implausible294; from inner, so the call @f() in inner's copy of merge should be295; rewritten to call @f()296; CHECK-LABEL: define void @test11()297; CHECK:      %inner = cleanuppad within %outer []298; CHECK-NEXT: call void @llvm.bar()299; CHECK-NEXT: unreachable300 301define void @test12() personality ptr @__CxxFrameHandler3 !dbg !5 {302entry:303  invoke void @f()304    to label %cont unwind label %left, !dbg !8305cont:306  invoke void @f()307    to label %exit unwind label %right308left:309  cleanuppad within none []310  br label %join311right:312  cleanuppad within none []313  br label %join314join:315  ; This call will get cloned; make sure we can handle cloning316  ; instructions with debug metadata attached.317  call void @llvm.bar(), !dbg !9318  unreachable319exit:320  ret void321}322 323; CHECK-LABEL: define void @test13()324; CHECK: ret void325define void @test13() personality ptr @__CxxFrameHandler3 {326entry:327  ret void328 329unreachable:330  cleanuppad within none []331  unreachable332}333 334define void @test14() personality ptr @ProcessCLRException {335entry:336  invoke void @f()337    to label %cont unwind label %cleanup338cont:339  invoke void @f()340    to label %exit unwind label %switch.outer341cleanup:342  %cleanpad = cleanuppad within none []343  invoke void @f() [ "funclet" (token %cleanpad) ]344    to label %cleanret unwind label %switch.inner345switch.inner:346  %cs.inner = catchswitch within %cleanpad [label %pad.inner] unwind to caller347pad.inner:348  %cp.inner = catchpad within %cs.inner [i32 1]349  catchret from %cp.inner to label %join350cleanret:351  cleanupret from %cleanpad unwind to caller352switch.outer:353  %cs.outer = catchswitch within none [label %pad.outer] unwind to caller354pad.outer:355  %cp.outer = catchpad within %cs.outer [i32 2]356  catchret from %cp.outer to label %join357join:358  %phi = phi i32 [ 1, %pad.inner ], [ 2, %pad.outer ]359  call void @llvm.foo(i32 %phi)360  unreachable361exit:362  ret void363}364; Both catchrets target %join, but the catchret from %cp.inner365; returns to %cleanpad and the catchret from %cp.outer returns to the366; main function, so %join needs to get cloned and one of the cleanuprets367; needs to be updated to target the clone368; CHECK-LABEL: define void @test14()369; CHECK: catchret from %cp.inner to label %[[Clone1:.+]]370; CHECK: catchret from %cp.outer to label %[[Clone2:.+]]371; CHECK: [[Clone1]]:372; CHECK-NEXT: call void @llvm.foo(i32 1)373; CHECK-NEXT: unreachable374; CHECK: [[Clone2]]:375; CHECK-NEXT: call void @llvm.foo(i32 2)376; CHECK-NEXT: unreachable377 378;; Debug info (from test12)379 380; Make sure the DISubprogram doesn't get cloned381; CHECK-LABEL: !llvm.module.flags382; CHECK-NOT: !DISubprogram383; CHECK: !{{[0-9]+}} = distinct !DISubprogram(name: "test12"384; CHECK-NOT: !DISubprogram385!llvm.module.flags = !{!0}386!llvm.dbg.cu = !{!1}387 388!0 = !{i32 2, !"Debug Info Version", i32 3}389!1 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !2, producer: "compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !3)390!2 = !DIFile(filename: "test.cpp", directory: ".")391!3 = !{}392!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)393!6 = !DISubroutineType(types: !7)394!7 = !{null}395!8 = !DILocation(line: 1, scope: !5)396!9 = !DILocation(line: 2, scope: !5)397