Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@ -0,0 +1,12 @@
# FIXME: For now, override suffixes to exclude any .s tests, because some of the
# buildbots have a stray misched-copy.s output file lying around that causes
# failures. See misched-copy.s where we try and clean up that file.
#
# It should be possible to remove this override once all the bots have cycled
# cleanly.
config.suffixes = ['.ll', '.test', '.txt']
# FIXME: Add Windows on ARM support to these tests.
if not 'X86' in config.root.targets:
config.unsupported = True

View File

@ -0,0 +1,26 @@
; RUN: opt -winehprepare < %s
target triple = "x86_64-pc-windows-msvc"
define void @test1() personality i32 (...)* @__CxxFrameHandler3 {
entry:
invoke void @f(i32 1)
to label %exit unwind label %cleanup
cleanup:
%cp = cleanuppad within none []
call void asm sideeffect "", ""()
cleanupret from %cp unwind to caller
exit:
ret void
}
; CHECK-LABEL: define void @test1(
; CHECK: %[[cp:.*]] = cleanuppad within none []
; CHECK-NEXT: call void asm sideeffect "", ""()
; CHECK-NEXT: cleanupret from %[[cp]] unwind to caller
declare void @f(i32)
declare i32 @__CxxFrameHandler3(...)

View File

@ -0,0 +1,393 @@
; RUN: opt -mtriple=x86_64-pc-windows-msvc -S -winehprepare < %s | FileCheck %s
declare i32 @__CxxFrameHandler3(...)
declare i32 @__C_specific_handler(...)
declare void @ProcessCLRException(...)
declare void @f()
declare void @llvm.foo(i32) nounwind
declare void @llvm.bar() nounwind
declare i32 @llvm.qux() nounwind
declare i1 @llvm.baz() nounwind
define void @test1() personality i32 (...)* @__CxxFrameHandler3 {
entry:
; %x def colors: {entry} subset of use colors; must spill
%x = call i32 @llvm.qux()
invoke void @f()
to label %noreturn unwind label %catch.switch
catch.switch:
%cs = catchswitch within none [label %catch] unwind to caller
catch:
%cp = catchpad within %cs []
br label %noreturn
noreturn:
; %x use colors: {entry, cleanup}
call void @llvm.foo(i32 %x)
unreachable
}
; Need two copies of the call to @h, one under entry and one under catch.
; Currently we generate a load for each, though we shouldn't need one
; for the use in entry's copy.
; CHECK-LABEL: define void @test1(
; CHECK: entry:
; CHECK: %x = call i32 @llvm.qux()
; CHECK: invoke void @f()
; CHECK: to label %[[EntryCopy:[^ ]+]] unwind label %catch
; CHECK: catch.switch:
; CHECK: %cs = catchswitch within none [label %catch] unwind to caller
; CHECK: catch:
; CHECK: catchpad within %cs []
; CHECK-NEXT: call void @llvm.foo(i32 %x)
; CHECK: [[EntryCopy]]:
; CHECK: call void @llvm.foo(i32 %x)
define void @test2() personality i32 (...)* @__CxxFrameHandler3 {
entry:
invoke void @f()
to label %exit unwind label %cleanup
cleanup:
cleanuppad within none []
br label %exit
exit:
call void @llvm.bar()
ret void
}
; Need two copies of %exit's call to @f -- the subsequent ret is only
; valid when coming from %entry, but on the path from %cleanup, this
; might be a valid call to @f which might dynamically not return.
; CHECK-LABEL: define void @test2(
; CHECK: entry:
; CHECK: invoke void @f()
; CHECK: to label %[[exit:[^ ]+]] unwind label %cleanup
; CHECK: cleanup:
; CHECK: cleanuppad within none []
; CHECK: call void @llvm.bar()
; CHECK-NEXT: unreachable
; CHECK: [[exit]]:
; CHECK: call void @llvm.bar()
; CHECK-NEXT: ret void
define void @test3() personality i32 (...)* @__CxxFrameHandler3 {
entry:
invoke void @f()
to label %invoke.cont unwind label %catch.switch
invoke.cont:
invoke void @f()
to label %exit unwind label %cleanup
catch.switch:
%cs = catchswitch within none [label %catch] unwind to caller
catch:
catchpad within %cs []
br label %shared
cleanup:
cleanuppad within none []
br label %shared
shared:
call void @llvm.bar()
br label %exit
exit:
ret void
}
; Need two copies of %shared's call to @f (similar to @test2 but
; the two regions here are siblings, not parent-child).
; CHECK-LABEL: define void @test3(
; CHECK: invoke void @f()
; CHECK: invoke void @f()
; CHECK: to label %[[exit:[^ ]+]] unwind
; CHECK: catch:
; CHECK: catchpad within %cs []
; CHECK-NEXT: call void @llvm.bar()
; CHECK-NEXT: unreachable
; CHECK: cleanup:
; CHECK: cleanuppad within none []
; CHECK: call void @llvm.bar()
; CHECK-NEXT: unreachable
; CHECK: [[exit]]:
; CHECK: ret void
define void @test4() personality i32 (...)* @__CxxFrameHandler3 {
entry:
invoke void @f()
to label %shared unwind label %catch.switch
catch.switch:
%cs = catchswitch within none [label %catch] unwind to caller
catch:
catchpad within %cs []
br label %shared
shared:
%x = call i32 @llvm.qux()
%i = call i32 @llvm.qux()
%zero.trip = icmp eq i32 %i, 0
br i1 %zero.trip, label %exit, label %loop
loop:
%i.loop = phi i32 [ %i, %shared ], [ %i.dec, %loop.tail ]
%b = call i1 @llvm.baz()
br i1 %b, label %left, label %right
left:
%y = call i32 @llvm.qux()
br label %loop.tail
right:
call void @llvm.foo(i32 %x)
br label %loop.tail
loop.tail:
%i.dec = sub i32 %i.loop, 1
%done = icmp eq i32 %i.dec, 0
br i1 %done, label %exit, label %loop
exit:
call void @llvm.foo(i32 %x)
unreachable
}
; Make sure we can clone regions that have internal control
; flow and SSA values. Here we need two copies of everything
; from %shared to %exit.
; CHECK-LABEL: define void @test4(
; CHECK: entry:
; CHECK: to label %[[shared_E:[^ ]+]] unwind label %catch.switch
; CHECK: catch:
; CHECK: catchpad within %cs []
; CHECK: [[x_C:%[^ ]+]] = call i32 @llvm.qux()
; CHECK: [[i_C:%[^ ]+]] = call i32 @llvm.qux()
; CHECK: [[zt_C:%[^ ]+]] = icmp eq i32 [[i_C]], 0
; CHECK: br i1 [[zt_C]], label %[[exit_C:[^ ]+]], label %[[loop_C:[^ ]+]]
; CHECK: [[shared_E]]:
; CHECK: [[x_E:%[^ ]+]] = call i32 @llvm.qux()
; CHECK: [[i_E:%[^ ]+]] = call i32 @llvm.qux()
; CHECK: [[zt_E:%[^ ]+]] = icmp eq i32 [[i_E]], 0
; CHECK: br i1 [[zt_E]], label %[[exit_E:[^ ]+]], label %[[loop_E:[^ ]+]]
; CHECK: [[loop_C]]:
; CHECK: [[iloop_C:%[^ ]+]] = phi i32 [ [[i_C]], %catch ], [ [[idec_C:%[^ ]+]], %[[looptail_C:[^ ]+]] ]
; CHECK: [[b_C:%[^ ]+]] = call i1 @llvm.baz()
; CHECK: br i1 [[b_C]], label %[[left_C:[^ ]+]], label %[[right_C:[^ ]+]]
; CHECK: [[loop_E]]:
; CHECK: [[iloop_E:%[^ ]+]] = phi i32 [ [[i_E]], %[[shared_E]] ], [ [[idec_E:%[^ ]+]], %[[looptail_E:[^ ]+]] ]
; CHECK: [[b_E:%[^ ]+]] = call i1 @llvm.baz()
; CHECK: br i1 [[b_E]], label %[[left_E:[^ ]+]], label %[[right_E:[^ ]+]]
; CHECK: [[left_C]]:
; CHECK: [[y_C:%[^ ]+]] = call i32 @llvm.qux()
; CHECK: br label %[[looptail_C]]
; CHECK: [[left_E]]:
; CHECK: [[y_E:%[^ ]+]] = call i32 @llvm.qux()
; CHECK: br label %[[looptail_E]]
; CHECK: [[right_C]]:
; CHECK: call void @llvm.foo(i32 [[x_C]])
; CHECK: br label %[[looptail_C]]
; CHECK: [[right_E]]:
; CHECK: call void @llvm.foo(i32 [[x_E]])
; CHECK: br label %[[looptail_E]]
; CHECK: [[looptail_C]]:
; CHECK: [[idec_C]] = sub i32 [[iloop_C]], 1
; CHECK: [[done_C:%[^ ]+]] = icmp eq i32 [[idec_C]], 0
; CHECK: br i1 [[done_C]], label %[[exit_C]], label %[[loop_C]]
; CHECK: [[looptail_E]]:
; CHECK: [[idec_E]] = sub i32 [[iloop_E]], 1
; CHECK: [[done_E:%[^ ]+]] = icmp eq i32 [[idec_E]], 0
; CHECK: br i1 [[done_E]], label %[[exit_E]], label %[[loop_E]]
; CHECK: [[exit_C]]:
; CHECK: call void @llvm.foo(i32 [[x_C]])
; CHECK: unreachable
; CHECK: [[exit_E]]:
; CHECK: call void @llvm.foo(i32 [[x_E]])
; CHECK: unreachable
define void @test5() personality i32 (...)* @__C_specific_handler {
entry:
invoke void @f()
to label %exit unwind label %outer
outer:
%o = cleanuppad within none []
%x = call i32 @llvm.qux()
invoke void @f() [ "funclet"(token %o) ]
to label %outer.ret unwind label %catch.switch
catch.switch:
%cs = catchswitch within %o [label %inner] unwind to caller
inner:
%i = catchpad within %cs []
catchret from %i to label %outer.post-inner
outer.post-inner:
call void @llvm.foo(i32 %x)
br label %outer.ret
outer.ret:
cleanupret from %o unwind to caller
exit:
ret void
}
; Simple nested case (catch-inside-cleanup). Nothing needs
; to be cloned. The def and use of %x are both in %outer
; and so don't need to be spilled.
; CHECK-LABEL: define void @test5(
; CHECK: outer:
; CHECK: %x = call i32 @llvm.qux()
; CHECK-NEXT: invoke void @f()
; CHECK-NEXT: to label %outer.ret unwind label %catch.switch
; CHECK: inner:
; CHECK-NEXT: %i = catchpad within %cs []
; CHECK-NEXT: catchret from %i to label %outer.post-inner
; CHECK: outer.post-inner:
; CHECK-NEXT: call void @llvm.foo(i32 %x)
; CHECK-NEXT: br label %outer.ret
define void @test10() personality i32 (...)* @__CxxFrameHandler3 {
entry:
invoke void @f()
to label %unreachable unwind label %inner
inner:
%cleanup = cleanuppad within none []
; make sure we don't overlook this cleanupret and try to process
; successor %outer as a child of inner.
cleanupret from %cleanup unwind label %outer
outer:
%cs = catchswitch within none [label %catch.body] unwind to caller
catch.body:
%catch = catchpad within %cs []
catchret from %catch to label %exit
exit:
ret void
unreachable:
unreachable
}
; CHECK-LABEL: define void @test10(
; CHECK-NEXT: entry:
; CHECK-NEXT: invoke
; CHECK-NEXT: to label %unreachable unwind label %inner
; CHECK: inner:
; CHECK-NEXT: %cleanup = cleanuppad within none []
; CHECK-NEXT: cleanupret from %cleanup unwind label %outer
; CHECK: outer:
; CHECK-NEXT: %cs = catchswitch within none [label %catch.body] unwind to caller
; CHECK: catch.body:
; CHECK-NEXT: %catch = catchpad within %cs []
; CHECK-NEXT: catchret from %catch to label %exit
; CHECK: exit:
; CHECK-NEXT: ret void
define void @test11() personality i32 (...)* @__C_specific_handler {
entry:
invoke void @f()
to label %exit unwind label %cleanup.outer
cleanup.outer:
%outer = cleanuppad within none []
invoke void @f() [ "funclet"(token %outer) ]
to label %outer.cont unwind label %cleanup.inner
outer.cont:
br label %merge
cleanup.inner:
%inner = cleanuppad within %outer []
br label %merge
merge:
call void @llvm.bar()
unreachable
exit:
ret void
}
; merge.end will get cloned for outer and inner, but is implausible
; from inner, so the call @f() in inner's copy of merge should be
; rewritten to call @f()
; CHECK-LABEL: define void @test11()
; CHECK: %inner = cleanuppad within %outer []
; CHECK-NEXT: call void @llvm.bar()
; CHECK-NEXT: unreachable
define void @test12() personality i32 (...)* @__CxxFrameHandler3 !dbg !5 {
entry:
invoke void @f()
to label %cont unwind label %left, !dbg !8
cont:
invoke void @f()
to label %exit unwind label %right
left:
cleanuppad within none []
br label %join
right:
cleanuppad within none []
br label %join
join:
; This call will get cloned; make sure we can handle cloning
; instructions with debug metadata attached.
call void @llvm.bar(), !dbg !9
unreachable
exit:
ret void
}
; CHECK-LABEL: define void @test13()
; CHECK: ret void
define void @test13() personality i32 (...)* @__CxxFrameHandler3 {
entry:
ret void
unreachable:
cleanuppad within none []
unreachable
}
define void @test14() personality void (...)* @ProcessCLRException {
entry:
invoke void @f()
to label %cont unwind label %cleanup
cont:
invoke void @f()
to label %exit unwind label %switch.outer
cleanup:
%cleanpad = cleanuppad within none []
invoke void @f() [ "funclet" (token %cleanpad) ]
to label %cleanret unwind label %switch.inner
switch.inner:
%cs.inner = catchswitch within %cleanpad [label %pad.inner] unwind to caller
pad.inner:
%cp.inner = catchpad within %cs.inner [i32 1]
catchret from %cp.inner to label %join
cleanret:
cleanupret from %cleanpad unwind to caller
switch.outer:
%cs.outer = catchswitch within none [label %pad.outer] unwind to caller
pad.outer:
%cp.outer = catchpad within %cs.outer [i32 2]
catchret from %cp.outer to label %join
join:
%phi = phi i32 [ 1, %pad.inner ], [ 2, %pad.outer ]
call void @llvm.foo(i32 %phi)
unreachable
exit:
ret void
}
; Both catchrets target %join, but the catchret from %cp.inner
; returns to %cleanpad and the catchret from %cp.outer returns to the
; main function, so %join needs to get cloned and one of the cleanuprets
; needs to be updated to target the clone
; CHECK-LABEL: define void @test14()
; CHECK: catchret from %cp.inner to label %[[Clone1:.+]]
; CHECK: catchret from %cp.outer to label %[[Clone2:.+]]
; CHECK: [[Clone1]]:
; CHECK-NEXT: call void @llvm.foo(i32 1)
; CHECK-NEXT: unreachable
; CHECK: [[Clone2]]:
; CHECK-NEXT: call void @llvm.foo(i32 2)
; CHECK-NEXT: unreachable
;; Debug info (from test12)
; Make sure the DISubprogram doesn't get cloned
; CHECK-LABEL: !llvm.module.flags
; CHECK-NOT: !DISubprogram
; CHECK: !{{[0-9]+}} = distinct !DISubprogram(name: "test12"
; CHECK-NOT: !DISubprogram
!llvm.module.flags = !{!0}
!llvm.dbg.cu = !{!1}
!0 = !{i32 2, !"Debug Info Version", i32 3}
!1 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !2, producer: "compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !3)
!2 = !DIFile(filename: "test.cpp", directory: ".")
!3 = !{}
!5 = distinct !DISubprogram(name: "test12", scope: !2, file: !2, type: !6, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !1, variables: !3)
!6 = !DISubroutineType(types: !7)
!7 = !{null}
!8 = !DILocation(line: 1, scope: !5)
!9 = !DILocation(line: 2, scope: !5)

View File

@ -0,0 +1,17 @@
; RUN: opt -mtriple=i686-unknown-windows-msvc -S -x86-winehstate < %s | FileCheck %s
$f = comdat any
define void @f() comdat personality i32 (...)* @__CxxFrameHandler3 {
invoke void @g() to label %return unwind label %unwind
return:
ret void
unwind:
%pad = cleanuppad within none []
cleanupret from %pad unwind to caller
}
declare void @g()
declare i32 @__CxxFrameHandler3(...)
; CHECK: define internal i32 @"__ehhandler$f"(i8*, i8*, i8*, i8*){{ .+}} comdat($f) {

View File

@ -0,0 +1,356 @@
; RUN: opt -mtriple=x86_64-pc-windows-msvc -S -winehprepare < %s | FileCheck %s
declare i32 @__CxxFrameHandler3(...)
declare void @f()
declare i32 @g()
declare void @h(i32)
declare i1 @i()
declare void @llvm.bar() nounwind
; CHECK-LABEL: @test1(
define void @test1(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
entry:
; Spill slot should be inserted here
; CHECK: [[Slot:%[^ ]+]] = alloca
; Can't store for %phi at these defs because the lifetimes overlap
; CHECK-NOT: store
%x = call i32 @g()
%y = call i32 @g()
br i1 %B, label %left, label %right
left:
; CHECK: left:
; CHECK-NEXT: store i32 %x, i32* [[Slot]]
; CHECK-NEXT: invoke void @f
invoke void @f()
to label %exit unwind label %merge
right:
; CHECK: right:
; CHECK-NEXT: store i32 %y, i32* [[Slot]]
; CHECK-NEXT: invoke void @f
invoke void @f()
to label %exit unwind label %merge
merge:
; CHECK: merge:
; CHECK-NOT: = phi
%phi = phi i32 [ %x, %left ], [ %y, %right ]
%cs1 = catchswitch within none [label %catch] unwind to caller
catch:
%cp = catchpad within %cs1 []
; CHECK: catch:
; CHECK: [[Reload:%[^ ]+]] = load i32, i32* [[Slot]]
; CHECK-NEXT: call void @h(i32 [[Reload]])
call void @h(i32 %phi) [ "funclet"(token %cp) ]
catchret from %cp to label %exit
exit:
ret void
}
; CHECK-LABEL: @test2(
define void @test2(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
entry:
br i1 %B, label %left, label %right
left:
; Need two stores here because %x and %y interfere so they need 2 slots
; CHECK: left:
; CHECK: store i32 1, i32* [[Slot1:%[^ ]+]]
; CHECK: store i32 1, i32* [[Slot2:%[^ ]+]]
; CHECK-NEXT: invoke void @f
invoke void @f()
to label %exit unwind label %merge.inner
right:
; Need two stores here because %x and %y interfere so they need 2 slots
; CHECK: right:
; CHECK-DAG: store i32 2, i32* [[Slot1]]
; CHECK-DAG: store i32 2, i32* [[Slot2]]
; CHECK: invoke void @f
invoke void @f()
to label %exit unwind label %merge.inner
merge.inner:
; CHECK: merge.inner:
; CHECK-NOT: = phi
; CHECK: catchswitch within none
%x = phi i32 [ 1, %left ], [ 2, %right ]
%cs1 = catchswitch within none [label %catch.inner] unwind label %merge.outer
catch.inner:
%cpinner = catchpad within %cs1 []
; Need just one store here because only %y is affected
; CHECK: catch.inner:
%z = call i32 @g() [ "funclet"(token %cpinner) ]
; CHECK: store i32 %z
; CHECK-NEXT: invoke void @f
invoke void @f() [ "funclet"(token %cpinner) ]
to label %catchret.inner unwind label %merge.outer
catchret.inner:
catchret from %cpinner to label %exit
merge.outer:
%y = phi i32 [ %x, %merge.inner ], [ %z, %catch.inner ]
; CHECK: merge.outer:
; CHECK-NOT: = phi
; CHECK: catchswitch within none
%cs2 = catchswitch within none [label %catch.outer] unwind to caller
catch.outer:
%cpouter = catchpad within %cs2 []
; CHECK: catch.outer:
; CHECK: [[CatchPad:%[^ ]+]] = catchpad within %cs2 []
; Need to load x and y from two different slots since they're both live
; and can have different values (if we came from catch.inner)
; CHECK-DAG: load i32, i32* [[Slot1]]
; CHECK-DAG: load i32, i32* [[Slot2]]
; CHECK: catchret from [[CatchPad]] to label
call void @h(i32 %x) [ "funclet"(token %cpouter) ]
call void @h(i32 %y) [ "funclet"(token %cpouter) ]
catchret from %cpouter to label %exit
exit:
ret void
}
; test4: don't need stores for %phi.inner, as its only use is to feed %phi.outer
; %phi.outer needs stores in %left, %right, and %join
; CHECK-LABEL: @test4(
define void @test4(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
entry:
; CHECK: entry:
; CHECK: [[Slot:%[^ ]+]] = alloca
; CHECK-NEXT: br
br i1 %B, label %left, label %right
left:
; CHECK: left:
; CHECK-NOT: store
; CHECK: store i32 %l, i32* [[Slot]]
; CHECK-NEXT: invoke void @f
%l = call i32 @g()
invoke void @f()
to label %join unwind label %catchpad.inner
right:
; CHECK: right:
; CHECK-NOT: store
; CHECK: store i32 %r, i32* [[Slot]]
; CHECK-NEXT: invoke void @f
%r = call i32 @g()
invoke void @f()
to label %join unwind label %catchpad.inner
catchpad.inner:
; CHECK: catchpad.inner:
; CHECK-NEXT: catchswitch within none
%phi.inner = phi i32 [ %l, %left ], [ %r, %right ]
%cs1 = catchswitch within none [label %catch.inner] unwind label %catchpad.outer
catch.inner:
%cp1 = catchpad within %cs1 []
catchret from %cp1 to label %join
join:
; CHECK: join:
; CHECK-NOT: store
; CHECK: store i32 %j, i32* [[Slot]]
; CHECK-NEXT: invoke void @f
%j = call i32 @g()
invoke void @f()
to label %exit unwind label %catchpad.outer
catchpad.outer:
; CHECK: catchpad.outer:
; CHECK-NEXT: catchswitch within none
%phi.outer = phi i32 [ %phi.inner, %catchpad.inner ], [ %j, %join ]
%cs2 = catchswitch within none [label %catch.outer] unwind to caller
catch.outer:
; CHECK: catch.outer:
; CHECK: [[Reload:%[^ ]+]] = load i32, i32* [[Slot]]
; CHECK: call void @h(i32 [[Reload]])
%cp2 = catchpad within %cs2 []
call void @h(i32 %phi.outer) [ "funclet"(token %cp2) ]
catchret from %cp2 to label %exit
exit:
ret void
}
; CHECK-LABEL: @test5(
define void @test5() personality i32 (...)* @__CxxFrameHandler3 {
entry:
; need store for %phi.cleanup
; CHECK: entry:
; CHECK: store i32 1, i32* [[CleanupSlot:%[^ ]+]]
; CHECK-NEXT: invoke void @f
invoke void @f()
to label %invoke.cont unwind label %cleanup
invoke.cont:
; need store for %phi.cleanup
; CHECK: invoke.cont:
; CHECK-NEXT: store i32 2, i32* [[CleanupSlot]]
; CHECK-NEXT: invoke void @f
invoke void @f()
to label %invoke.cont2 unwind label %cleanup
cleanup:
; cleanup phi can be loaded at cleanup entry
; CHECK: cleanup:
; CHECK-NEXT: cleanuppad within none []
; CHECK: [[CleanupReload:%[^ ]+]] = load i32, i32* [[CleanupSlot]]
%phi.cleanup = phi i32 [ 1, %entry ], [ 2, %invoke.cont ]
%cp = cleanuppad within none []
%b = call i1 @i() [ "funclet"(token %cp) ]
br i1 %b, label %left, label %right
left:
; CHECK: left:
; CHECK: call void @h(i32 [[CleanupReload]]
call void @h(i32 %phi.cleanup) [ "funclet"(token %cp) ]
br label %merge
right:
; CHECK: right:
; CHECK: call void @h(i32 [[CleanupReload]]
call void @h(i32 %phi.cleanup) [ "funclet"(token %cp) ]
br label %merge
merge:
; need store for %phi.catch
; CHECK: merge:
; CHECK-NEXT: store i32 [[CleanupReload]], i32* [[CatchSlot:%[^ ]+]]
; CHECK-NEXT: cleanupret
cleanupret from %cp unwind label %catchswitch
invoke.cont2:
; need store for %phi.catch
; CHECK: invoke.cont2:
; CHECK-NEXT: store i32 3, i32* [[CatchSlot]]
; CHECK-NEXT: invoke void @f
invoke void @f()
to label %exit unwind label %catchswitch
catchswitch:
; CHECK: catchswitch:
; CHECK-NEXT: catchswitch within none
%phi.catch = phi i32 [ %phi.cleanup, %merge ], [ 3, %invoke.cont2 ]
%cs1 = catchswitch within none [label %catch] unwind to caller
catch:
; CHECK: catch:
; CHECK: catchpad within %cs1
; CHECK: [[CatchReload:%[^ ]+]] = load i32, i32* [[CatchSlot]]
; CHECK: call void @h(i32 [[CatchReload]]
%cp2 = catchpad within %cs1 []
call void @h(i32 %phi.catch) [ "funclet"(token %cp2) ]
catchret from %cp2 to label %exit
exit:
ret void
}
; We used to demote %x, but we don't need to anymore.
; CHECK-LABEL: @test6(
define void @test6() personality i32 (...)* @__CxxFrameHandler3 {
entry:
; CHECK: entry:
; CHECK: %x = invoke i32 @g()
; CHECK-NEXT: to label %loop unwind label %to_caller
%x = invoke i32 @g()
to label %loop unwind label %to_caller
to_caller:
%cp1 = cleanuppad within none []
cleanupret from %cp1 unwind to caller
loop:
invoke void @f()
to label %loop unwind label %cleanup
cleanup:
; CHECK: cleanup:
; CHECK: call void @h(i32 %x)
%cp2 = cleanuppad within none []
call void @h(i32 %x) [ "funclet"(token %cp2) ]
cleanupret from %cp2 unwind to caller
}
; CHECK-LABEL: @test7(
define void @test7() personality i32 (...)* @__CxxFrameHandler3 {
entry:
; %x is an EH pad phi, so gets stored in pred here
; CHECK: entry:
; CHECK: store i32 1, i32* [[SlotX:%[^ ]+]]
; CHECK: invoke void @f()
invoke void @f()
to label %invoke.cont unwind label %catchpad
invoke.cont:
; %x is an EH pad phi, so gets stored in pred here
; CHECK: invoke.cont:
; CHECK: store i32 2, i32* [[SlotX]]
; CHECK: invoke void @f()
invoke void @f()
to label %exit unwind label %catchpad
catchpad:
; %x phi should be eliminated
; CHECK: catchpad:
; CHECK-NEXT: catchswitch within none
%x = phi i32 [ 1, %entry ], [ 2, %invoke.cont ]
%cs1 = catchswitch within none [label %catch] unwind to caller
catch:
; CHECK: catch:
; CHECK-NEXT: %[[CatchPad:[^ ]+]] = catchpad within %cs1 []
%cp = catchpad within %cs1 []
%b = call i1 @i() [ "funclet"(token %cp) ]
br i1 %b, label %left, label %right
left:
; Edge from %left to %join needs to be split so that
; the load of %x can be inserted *after* the catchret
; CHECK: left:
; CHECK-NEXT: catchret from %[[CatchPad]] to label %[[SplitLeft:[^ ]+]]
catchret from %cp to label %join
; CHECK: [[SplitLeft]]:
; CHECK: [[LoadX:%[^ ]+]] = load i32, i32* [[SlotX]]
; CHECK: br label %join
right:
; Edge from %right to %join needs to be split so that
; the load of %y can be inserted *after* the catchret
; CHECK: right:
; CHECK: %y = call i32 @g()
; CHECK: catchret from %[[CatchPad]] to label %join
%y = call i32 @g() [ "funclet"(token %cp) ]
catchret from %cp to label %join
join:
; CHECK: join:
; CHECK: %phi = phi i32 [ [[LoadX]], %[[SplitLeft]] ], [ %y, %right ]
%phi = phi i32 [ %x, %left ], [ %y, %right ]
call void @h(i32 %phi)
br label %exit
exit:
ret void
}
; CHECK-LABEL: @test8(
define void @test8() personality i32 (...)* @__CxxFrameHandler3 { entry:
invoke void @f()
to label %done unwind label %cleanup1
invoke void @f()
to label %done unwind label %cleanup2
done:
ret void
cleanup1:
; CHECK: [[CleanupPad1:%[^ ]+]] = cleanuppad within none []
; CHECK-NEXT: call void @llvm.bar()
; CHECK-NEXT: cleanupret from [[CleanupPad1]]
%cp0 = cleanuppad within none []
br label %cleanupexit
cleanup2:
; CHECK: cleanuppad within none []
; CHECK-NEXT: call void @llvm.bar()
; CHECK-NEXT: unreachable
%cp1 = cleanuppad within none []
br label %cleanupexit
cleanupexit:
call void @llvm.bar()
cleanupret from %cp0 unwind label %cleanup2
}

View File

@ -0,0 +1,26 @@
; RUN: sed -e s/.T1:// %s | not opt -lint -disable-output 2>&1 | FileCheck --check-prefix=CHECK1 %s
; RUN: sed -e s/.T2:// %s | not opt -lint -disable-output 2>&1 | FileCheck --check-prefix=CHECK2 %s
target triple = "x86_64-pc-windows-msvc"
declare void @f()
;T1: declare i8* @llvm.eh.exceptionpointer.p0i8(i32)
;T1:
;T1: define void @test1() personality i32 (...)* @__CxxFrameHandler3 {
;T1: call i8* @llvm.eh.exceptionpointer.p0i8(i32 0)
;T1: ret void
;T1: }
;CHECK1: Intrinsic has incorrect argument type!
;CHECK1-NEXT: i8* (i32)* @llvm.eh.exceptionpointer.p0i8
;T2: declare i8* @llvm.eh.exceptionpointer.p0i8(token)
;T2:
;T2: define void @test2() personality i32 (...)* @__CxxFrameHandler3 {
;T2: call i8* @llvm.eh.exceptionpointer.p0i8(token undef)
;T2: ret void
;T2: }
;CHECK2: eh.exceptionpointer argument must be a catchpad
;CHECK2-NEXT: call i8* @llvm.eh.exceptionpointer.p0i8(token undef)
declare i32 @__CxxFrameHandler3(...)

View File

@ -0,0 +1,44 @@
; RUN: opt -lint -disable-output < %s
; This test is meant to prove that the verifier does not report errors for correct
; use of the llvm.eh.exceptionpointer intrinsic.
target triple = "x86_64-pc-windows-msvc"
declare i8* @llvm.eh.exceptionpointer.p0i8(token)
declare i8 addrspace(1)* @llvm.eh.exceptionpointer.p1i8(token)
declare void @f(...)
define void @test1() personality i32 (...)* @__CxxFrameHandler3 {
entry:
invoke void (...) @f(i32 1)
to label %exit unwind label %catchpad
catchpad:
%cs1 = catchswitch within none [label %do_catch] unwind to caller
do_catch:
%catch = catchpad within %cs1 [i32 1]
%exn = call i8* @llvm.eh.exceptionpointer.p0i8(token %catch)
call void (...) @f(i8* %exn)
catchret from %catch to label %exit
exit:
ret void
}
define void @test2() personality i32 (...)* @ProcessManagedException {
entry:
invoke void (...) @f(i32 1)
to label %exit unwind label %catchpad
catchpad:
%cs1 = catchswitch within none [label %do_catch] unwind to caller
do_catch:
%catch = catchpad within %cs1 [i32 1]
%exn = call i8 addrspace(1)* @llvm.eh.exceptionpointer.p1i8(token %catch)
call void (...) @f(i8 addrspace(1)* %exn)
catchret from %catch to label %exit
exit:
ret void
}
declare i32 @__CxxFrameHandler3(...)
declare i32 @ProcessManagedException(...)

View File

@ -0,0 +1,55 @@
; RUN: llc < %s | FileCheck %s
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc18.0.0"
; Function Attrs: uwtable
define void @f() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
invoke void @g()
to label %try.cont unwind label %catch.dispatch
catch.dispatch: ; preds = %entry
%0 = catchswitch within none [label %catch] unwind label %ehcleanup
catch: ; preds = %catch.dispatch
%1 = catchpad within %0 [i8* null, i32 64, i8* null]
invoke void @g() [ "funclet"(token %1) ]
to label %dtor.exit unwind label %catch.dispatch.i
catch.dispatch.i: ; preds = %catch
%2 = catchswitch within %1 [label %catch.i] unwind to caller
catch.i: ; preds = %catch.dispatch.i
%3 = catchpad within %2 [i8* null, i32 64, i8* null]
catchret from %3 to label %dtor.exit
dtor.exit:
catchret from %1 to label %try.cont
try.cont:
ret void
ehcleanup: ; preds = %catch.dispatch
%4 = cleanuppad within none []
call void @dtor() #1 [ "funclet"(token %4) ]
cleanupret from %4 unwind to caller
}
declare void @g()
declare i32 @__CxxFrameHandler3(...)
; Function Attrs: nounwind
declare void @dtor() #1
attributes #0 = { uwtable }
attributes #1 = { nounwind }
; CHECK-LABEL: $ip2state$f:
; CHECK: -1
; CHECK: 1
; CHECK: -1
; CHECK: 4
; CHECK: 2
; CHECK: 3
; CHECK: 2

View File

@ -0,0 +1,130 @@
; RUN: opt -mtriple=x86_x64-pc-windows-msvc -S -winehprepare -disable-demotion -disable-cleanups < %s | FileCheck %s
declare i32 @__CxxFrameHandler3(...)
declare i32 @__C_specific_handler(...)
declare void @f()
declare i32 @g()
declare void @h(i32)
; CHECK-LABEL: @test1(
define void @test1(i1 %bool) personality i32 (...)* @__C_specific_handler {
entry:
invoke void @f()
to label %invoke.cont unwind label %left
invoke.cont:
invoke void @f()
to label %exit unwind label %inner
left:
%0 = cleanuppad within none []
br i1 %bool, label %shared, label %cleanupret
cleanupret:
cleanupret from %0 unwind label %right
right:
%1 = cleanuppad within none []
br label %shared
shared:
%x = call i32 @g()
invoke void @f()
to label %shared.cont unwind label %inner
shared.cont:
unreachable
inner:
%phi = phi i32 [ %x, %shared ], [ 0, %invoke.cont ]
%i = cleanuppad within none []
call void @h(i32 %phi)
unreachable
; CHECK: %phi = phi i32 [ %x, %shared ], [ 0, %invoke.cont ], [ %x.for.left, %shared.for.left ]
; CHECK: %i = cleanuppad within none []
; CHECK: call void @h(i32 %phi)
exit:
unreachable
}
; CHECK-LABEL: @test2(
define void @test2(i1 %bool) personality i32 (...)* @__C_specific_handler {
entry:
invoke void @f()
to label %shared.cont unwind label %left
left:
%0 = cleanuppad within none []
br i1 %bool, label %shared, label %cleanupret
cleanupret:
cleanupret from %0 unwind label %right
right:
%1 = cleanuppad within none []
br label %shared
shared:
%x = call i32 @g()
invoke void @f()
to label %shared.cont unwind label %inner
shared.cont:
unreachable
inner:
%i = cleanuppad within none []
call void @h(i32 %x)
unreachable
; CHECK: %x1 = phi i32 [ %x.for.left, %shared.for.left ], [ %x, %shared ]
; CHECK: %i = cleanuppad within none []
; CHECK: call void @h(i32 %x1)
exit:
unreachable
}
; CHECK-LABEL: @test4(
define void @test4(i1 %x) personality i32 (...)* @__CxxFrameHandler3 {
entry:
invoke void @f()
to label %invoke.cont1 unwind label %left
invoke.cont1:
invoke void @f()
to label %exit unwind label %right
left:
%0 = cleanuppad within none []
br label %shared
right:
%1 = cleanuppad within none []
br i1 %x, label %shared, label %right.other
right.other:
br label %shared
shared:
%phi = phi i32 [ 1, %left ], [ 0, %right ], [ -1, %right.other ]
call void @h(i32 %phi)
unreachable
; CHECK: %phi = phi i32 [ 0, %right ], [ -1, %right.other ]
; CHECK: call void @h(i32 %phi)
; CHECK: %phi.for.left = phi i32 [ 1, %left ]
; CHECK: call void @h(i32 %phi.for.left)
exit:
unreachable
}
declare void @__std_terminate()

View File

@ -0,0 +1,80 @@
; RUN: sed -e s/.Cxx:// %s | llc -mtriple=x86_64-pc-windows-msvc | FileCheck %s --check-prefix=CXX
; RUN: sed -e s/.Seh:// %s | llc -mtriple=x86_64-pc-windows-msvc | FileCheck %s --check-prefix=SEH
declare i32 @__CxxFrameHandler3(...)
declare i32 @__C_specific_handler(...)
declare void @dummy_filter()
declare void @f(i32)
;Cxx: define void @test() personality i32 (...)* @__CxxFrameHandler3 {
;Seh: define void @test() personality i32 (...)* @__C_specific_handler {
entry:
invoke void @f(i32 1)
to label %invoke.cont unwind label %catch.dispatch
catch.dispatch:
%cs1 = catchswitch within none [label %catch.body] unwind label %catch.dispatch.2
catch.body:
;Cxx: %catch = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
;Seh: %catch = catchpad within %cs1 [void ()* @dummy_filter]
invoke void @f(i32 2) [ "funclet"(token %catch) ]
to label %unreachable unwind label %terminate
terminate:
%cleanup = cleanuppad within %catch []
call void @f(i32 3) [ "funclet"(token %cleanup) ]
unreachable
unreachable:
unreachable
invoke.cont:
ret void
catch.dispatch.2:
%cs2 = catchswitch within none [label %catch.body.2] unwind to caller
catch.body.2:
;Cxx: %catch2 = catchpad within %cs2 [i8* null, i32 u0x40, i8* null]
;Seh: %catch2 = catchpad within %cs2 [void ()* @dummy_filter]
unreachable
}
; CXX-LABEL: test:
; CXX-LABEL: $ip2state$test:
; CXX-NEXT: .long .Lfunc_begin0@IMGREL
; CXX-NEXT: .long -1
; CXX-NEXT: .long .Ltmp0@IMGREL+1
; CXX-NEXT: .long 1
; CXX-NEXT: .long .Ltmp1@IMGREL+1
; CXX-NEXT: .long -1
; CXX-NEXT: .long "?catch$3@?0?test@4HA"@IMGREL
; CXX-NEXT: .long 2
; CXX-NEXT: .long .Ltmp2@IMGREL+1
; CXX-NEXT: .long 3
; CXX-NEXT: .long .Ltmp3@IMGREL+1
; CXX-NEXT: .long 2
; CXX-NEXT: .long "?catch$5@?0?test@4HA"@IMGREL
; CXX-NEXT: .long 4
; SEH-LABEL: test:
; SEH-LABEL: .Llsda_begin0:
; SEH-NEXT: .long .Ltmp0@IMGREL+1
; SEH-NEXT: .long .Ltmp1@IMGREL+1
; SEH-NEXT: .long dummy_filter@IMGREL
; SEH-NEXT: .long .LBB0_3@IMGREL
; SEH-NEXT: .long .Ltmp0@IMGREL+1
; SEH-NEXT: .long .Ltmp1@IMGREL+1
; SEH-NEXT: .long dummy_filter@IMGREL
; SEH-NEXT: .long .LBB0_5@IMGREL
; SEH-NEXT: .long .Ltmp2@IMGREL+1
; SEH-NEXT: .long .Ltmp3@IMGREL+1
; SEH-NEXT: .long "?dtor$2@?0?test@4HA"@IMGREL
; SEH-NEXT: .long 0
; SEH-NEXT: .long .Ltmp2@IMGREL+1
; SEH-NEXT: .long .Ltmp3@IMGREL+1
; SEH-NEXT: .long dummy_filter@IMGREL
; SEH-NEXT: .long .LBB0_5@IMGREL
; SEH-NEXT: .Llsda_end0:

View File

@ -0,0 +1,75 @@
; RUN: opt -mtriple=i686-pc-windows-msvc -S -x86-winehstate < %s | FileCheck %s
target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
target triple = "i686-pc-windows-msvc"
@jb = external global i8
define i32 @test1() personality i32 (...)* @__CxxFrameHandler3 {
entry:
; CHECK-LABEL: define i32 @test1(
; CHECK: %[[eh_reg:.*]] = alloca
; CHECK: %[[gep:.*]] = getelementptr inbounds {{.*}}, {{.*}} %[[eh_reg]], i32 0, i32 2
; CHECK: store i32 -1, i32* %[[gep]]
; CHECK: %[[gep:.*]] = getelementptr inbounds {{.*}}, {{.*}} %[[eh_reg]], i32 0, i32 2
; CHECK: store i32 0, i32* %[[gep]]
; CHECK: %[[lsda:.*]] = call i8* @llvm.x86.seh.lsda(i8* bitcast (i32 ()* @test1 to i8*))
; CHECK: invoke i32 (i8*, i32, ...) @_setjmp3(i8* @jb, i32 3, void (i8*)* @__CxxLongjmpUnwind, i32 0, i8* %[[lsda]])
%inv = invoke i32 (i8*, i32, ...) @_setjmp3(i8* @jb, i32 0) #2
to label %invoke.cont unwind label %ehcleanup
invoke.cont:
; CHECK: %[[gep:.*]] = getelementptr inbounds {{.*}}, {{.*}} %[[eh_reg]], i32 0, i32 2
; CHECK: store i32 -1, i32* %[[gep]]
; CHECK: %[[lsda:.*]] = call i8* @llvm.x86.seh.lsda(i8* bitcast (i32 ()* @test1 to i8*))
; CHECK: call i32 (i8*, i32, ...) @_setjmp3(i8* @jb, i32 3, void (i8*)* @__CxxLongjmpUnwind, i32 -1, i8* %[[lsda]])
call i32 (i8*, i32, ...) @_setjmp3(i8* @jb, i32 0)
call void @cleanup()
ret i32 %inv
ehcleanup:
%cp = cleanuppad within none []
; CHECK: %[[gep:.*]] = getelementptr inbounds {{.*}}, {{.*}} %[[eh_reg]], i32 0, i32 2
; CHECK: %[[load:.*]] = load i32, i32* %[[gep]]
; CHECK: %[[lsda:.*]] = call i8* @llvm.x86.seh.lsda(i8* bitcast (i32 ()* @test1 to i8*))
; CHECK: call i32 (i8*, i32, ...) @_setjmp3(i8* @jb, i32 3, void (i8*)* @__CxxLongjmpUnwind, i32 %[[load]], i8* %[[lsda]]) [ "funclet"(token %cp) ]
%cal = call i32 (i8*, i32, ...) @_setjmp3(i8* @jb, i32 0) [ "funclet"(token %cp) ]
call void @cleanup() [ "funclet"(token %cp) ]
cleanupret from %cp unwind to caller
}
define i32 @test2() personality i32 (...)* @_except_handler3 {
entry:
; CHECK-LABEL: define i32 @test2(
; CHECK: %[[eh_reg:.*]] = alloca
; CHECK: %[[gep:.*]] = getelementptr inbounds {{.*}}, {{.*}} %[[eh_reg]], i32 0, i32 4
; CHECK: store i32 -1, i32* %[[gep]]
; CHECK: %[[gep:.*]] = getelementptr inbounds {{.*}}, {{.*}} %[[eh_reg]], i32 0, i32 4
; CHECK: store i32 0, i32* %[[gep]]
; CHECK: invoke i32 (i8*, i32, ...) @_setjmp3(i8* @jb, i32 2, void (i8*)* @_seh_longjmp_unwind, i32 0)
%inv = invoke i32 (i8*, i32, ...) @_setjmp3(i8* @jb, i32 0) #2
to label %invoke.cont unwind label %ehcleanup
invoke.cont:
; CHECK: %[[gep:.*]] = getelementptr inbounds {{.*}}, {{.*}} %[[eh_reg]], i32 0, i32 4
; CHECK: store i32 -1, i32* %[[gep]]
; CHECK: call i32 (i8*, i32, ...) @_setjmp3(i8* @jb, i32 2, void (i8*)* @_seh_longjmp_unwind, i32 -1)
call i32 (i8*, i32, ...) @_setjmp3(i8* @jb, i32 0)
call void @cleanup()
ret i32 %inv
ehcleanup:
%cp = cleanuppad within none []
call void @cleanup() [ "funclet"(token %cp) ]
cleanupret from %cp unwind to caller
}
; Function Attrs: returns_twice
declare i32 @_setjmp3(i8*, i32, ...) #2
declare i32 @__CxxFrameHandler3(...)
declare i32 @_except_handler3(...)
declare void @cleanup()
attributes #2 = { returns_twice }

View File

@ -0,0 +1,61 @@
; RUN: sed -e s/.Cxx:// %s | opt -mtriple=x86-pc-windows-msvc -S -x86-winehstate | FileCheck %s
; RUN: sed -e s/.SEH:// %s | opt -mtriple=x86-pc-windows-msvc -S -x86-winehstate | FileCheck %s
declare i32 @__CxxFrameHandler3(...)
declare i32 @_except_handler3(...)
declare void @dummy_filter()
declare void @f(i32)
; CHECK-LABEL: define void @test2(
;Cxx: define void @test2(i1 %b) personality i32 (...)* @__CxxFrameHandler3 {
;SEH: define void @test2(i1 %b) personality i32 (...)* @_except_handler3 {
entry:
; CHECK: entry:
; CHECK: store i32 1
; CHECK: invoke void @f(i32 1)
invoke void @f(i32 1)
to label %exit unwind label %cleanup.pad
cleanup.pad:
%cleanup = cleanuppad within none []
br i1 %b, label %left, label %right
left:
cleanupret from %cleanup unwind label %catch.pad
right:
cleanupret from %cleanup unwind label %catch.pad
catch.pad:
%cs1 = catchswitch within none [label %catch.body] unwind to caller
catch.body:
;Cxx: %catch = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
;SEH: %catch = catchpad within %cs1 [void ()* @dummy_filter]
catchret from %catch to label %exit
exit:
ret void
}
; CHECK-LABEL: define void @test3(
;Cxx: define void @test3() personality i32 (...)* @__CxxFrameHandler3 {
;SEH: define void @test3() personality i32 (...)* @_except_handler3 {
entry:
; CHECK: entry:
; CHECK: store i32 0
; CHECK: invoke void @f(i32 1)
invoke void @f(i32 1)
to label %exit unwind label %cleanup.pad
cleanup.pad:
; CHECK: cleanup.pad:
; CHECK: invoke void @f(i32 0)
%cleanup = cleanuppad within none []
invoke void @f(i32 0)
to label %unreachable unwind label %catch.pad
unreachable:
unreachable
catch.pad:
%cs1 = catchswitch within none [label %catch.body] unwind to caller
catch.body:
;Cxx: %catch = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
;SEH: %catch = catchpad within %cs1 [void ()* @dummy_filter]
catchret from %catch to label %exit
exit:
ret void
}

View File

@ -0,0 +1,219 @@
; RUN: opt -mtriple=i686-pc-windows-msvc -S -x86-winehstate < %s | FileCheck %s
target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
target triple = "i686-pc-windows-msvc"
%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
%eh.CatchableType = type { i32, i8*, i32, i32, i32, i32, i8* }
%eh.CatchableTypeArray.1 = type { i32, [1 x %eh.CatchableType*] }
%eh.ThrowInfo = type { i32, i8*, i8*, i8* }
$"\01??_R0H@8" = comdat any
$"_CT??_R0H@84" = comdat any
$_CTA1H = comdat any
$_TI1H = comdat any
@"\01??_7type_info@@6B@" = external constant i8*
@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
@"_CT??_R0H@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 0, i32 -1, i32 0, i32 4, i8* null }, section ".xdata", comdat
@_CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x %eh.CatchableType*] [%eh.CatchableType* @"_CT??_R0H@84"] }, section ".xdata", comdat
@_TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i8* null, i8* null, i8* bitcast (%eh.CatchableTypeArray.1* @_CTA1H to i8*) }, section ".xdata", comdat
define i32 @main() #0 personality i32 (...)* @__CxxFrameHandler3 {
entry:
%tmp = alloca i32, align 4
; CHECK: entry:
; CHECK: store i32 -1
; CHECK: call void @g(i32 3)
; CHECK-NEXT: call void @g(i32 4)
; CHECK-NEXT: call void @g(i32 5)
call void @g(i32 3)
call void @g(i32 4)
call void @g(i32 5)
store i32 0, i32* %tmp, align 4
%0 = bitcast i32* %tmp to i8*
; CHECK: store i32 0
; CHECK: invoke void @_CxxThrowException(
invoke void @_CxxThrowException(i8* %0, %eh.ThrowInfo* nonnull @_TI1H) #1
to label %unreachable.for.entry unwind label %catch.dispatch
catch.dispatch: ; preds = %entry
%cs1 = catchswitch within none [label %catch] unwind to caller
catch: ; preds = %catch.dispatch
%1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
; CHECK: catch:
; CHECK: store i32 2
; CHECK: invoke void @_CxxThrowException(
invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) [ "funclet"(token %1) ]
to label %unreachable unwind label %catch.dispatch.1
catch.dispatch.1: ; preds = %catch
%cs2 = catchswitch within %1 [label %catch.3] unwind to caller
catch.3: ; preds = %catch.dispatch.1
%2 = catchpad within %cs2 [i8* null, i32 u0x40, i8* null]
; CHECK: catch.3:
; CHECK: store i32 3
; CHECK: call void @g(i32 1)
; CHECK-NEXT: call void @g(i32 2)
; CHECK-NEXT: call void @g(i32 3)
call void @g(i32 1)
call void @g(i32 2)
call void @g(i32 3)
catchret from %2 to label %try.cont
try.cont: ; preds = %catch.3
; CHECK: try.cont:
; CHECK: store i32 1
; CHECK: call void @g(i32 2)
; CHECK-NEXT: call void @g(i32 3)
; CHECK-NEXT: call void @g(i32 4)
call void @g(i32 2)
call void @g(i32 3)
call void @g(i32 4)
unreachable
unreachable: ; preds = %catch
unreachable
unreachable.for.entry: ; preds = %entry
unreachable
}
define i32 @nopads() #0 personality i32 (...)* @__CxxFrameHandler3 {
ret i32 0
}
; CHECK-LABEL: define i32 @nopads()
; CHECK-NEXT: ret i32 0
; CHECK-NOT: __ehhandler$nopads
; CHECK-LABEL: define void @PR25926()
define void @PR25926() personality i32 (...)* @__CxxFrameHandler3 {
entry:
; CHECK: entry:
; CHECK: store i32 -1
; CHECK: store i32 0
; CHECK: invoke void @_CxxThrowException(
invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null)
to label %unreachable unwind label %catch.dispatch
catch.dispatch: ; preds = %entry
%0 = catchswitch within none [label %catch] unwind to caller
catch: ; preds = %catch.dispatch
%1 = catchpad within %0 [i8* null, i32 64, i8* null]
; CHECK: catch:
; CHECK: store i32 3
; CHECK: invoke void @_CxxThrowException(
invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) [ "funclet"(token %1) ]
to label %unreachable1 unwind label %catch.dispatch1
catch.dispatch1: ; preds = %catch
%2 = catchswitch within %1 [label %catch2] unwind label %ehcleanup
catch2: ; preds = %catch.dispatch1
%3 = catchpad within %2 [i8* null, i32 64, i8* null]
catchret from %3 to label %try.cont
try.cont: ; preds = %catch2
; CHECK: try.cont:
; CHECK: store i32 1
; CHECK: call void @dtor()
; CHECK-NEXT: call void @dtor()
; CHECK-NEXT: call void @dtor()
call void @dtor() #3 [ "funclet"(token %1) ]
call void @dtor() #3 [ "funclet"(token %1) ]
call void @dtor() #3 [ "funclet"(token %1) ]
catchret from %1 to label %try.cont4
try.cont4: ; preds = %try.cont
ret void
ehcleanup: ; preds = %catch.dispatch1
%4 = cleanuppad within %1 []
; CHECK: ehcleanup:
; CHECK: call void @dtor()
call void @dtor() #3 [ "funclet"(token %4) ]
cleanupret from %4 unwind to caller
unreachable: ; preds = %entry
unreachable
unreachable1: ; preds = %catch
unreachable
}
; CHECK-LABEL: define void @required_state_store(
define void @required_state_store(i1 zeroext %cond) personality i32 (...)* @_except_handler3 {
entry:
%__exception_code = alloca i32, align 4
call void (...) @llvm.localescape(i32* nonnull %__exception_code)
; CHECK: store i32 -1
; CHECK: call void @g(i32 0)
call void @g(i32 0)
br i1 %cond, label %if.then, label %if.end
if.then: ; preds = %entry
; CHECK: store i32 0
; CHECK-NEXT: invoke void @g(i32 1)
invoke void @g(i32 1)
to label %if.end unwind label %catch.dispatch
catch.dispatch: ; preds = %if.then
%0 = catchswitch within none [label %__except.ret] unwind to caller
__except.ret: ; preds = %catch.dispatch
%1 = catchpad within %0 [i8* bitcast (i32 ()* @"\01?filt$0@0@required_state_store@@" to i8*)]
catchret from %1 to label %if.end
if.end: ; preds = %if.then, %__except.ret, %entry
; CHECK: store i32 -1
; CHECK-NEXT: call void @dtor()
call void @dtor()
ret void
}
define internal i32 @"\01?filt$0@0@required_state_store@@"() {
entry:
%0 = tail call i8* @llvm.frameaddress(i32 1)
%1 = tail call i8* @llvm.x86.seh.recoverfp(i8* bitcast (void (i1)* @required_state_store to i8*), i8* %0)
%2 = tail call i8* @llvm.localrecover(i8* bitcast (void (i1)* @required_state_store to i8*), i8* %1, i32 0)
%__exception_code = bitcast i8* %2 to i32*
%3 = getelementptr inbounds i8, i8* %0, i32 -20
%4 = bitcast i8* %3 to { i32*, i8* }**
%5 = load { i32*, i8* }*, { i32*, i8* }** %4, align 4
%6 = getelementptr inbounds { i32*, i8* }, { i32*, i8* }* %5, i32 0, i32 0
%7 = load i32*, i32** %6, align 4
%8 = load i32, i32* %7, align 4
store i32 %8, i32* %__exception_code, align 4
ret i32 1
}
declare void @g(i32) #0
declare void @dtor()
declare x86_stdcallcc void @_CxxThrowException(i8*, %eh.ThrowInfo*)
declare i32 @__CxxFrameHandler3(...)
declare i8* @llvm.frameaddress(i32)
declare i8* @llvm.x86.seh.recoverfp(i8*, i8*)
declare i8* @llvm.localrecover(i8*, i8*, i32)
declare void @llvm.localescape(...)
declare i32 @_except_handler3(...)
attributes #0 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { noreturn }
!llvm.ident = !{!0}
!0 = !{!"clang version 3.8.0 (trunk 245153) (llvm/trunk 245238)"}