1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
; RUN: opt %s -pnacl-sjlj-eh -S | FileCheck %s
; This must be declared for expanding "invoke" and "landingpad" instructions.
@__pnacl_eh_stack = external thread_local global i8*
; This must be declared for expanding "resume" instructions.
declare void @__pnacl_eh_resume(i32* %exception)
declare i32 @external_func(i64 %arg)
; CHECK: %ExceptionFrame = type { [1024 x i8], %ExceptionFrame*, i32 }
define i32 @invoke_test(i64 %arg) {
%result = invoke i32 @external_func(i64 %arg)
to label %cont unwind label %lpad
cont:
ret i32 %result
lpad:
%lp = landingpad { i8*, i32 } personality i8* null cleanup
ret i32 999
}
; CHECK: define i32 @invoke_test
; CHECK-NEXT: %invoke_frame = alloca %ExceptionFrame, align 8
; CHECK-NEXT: %exc_info_ptr = getelementptr %ExceptionFrame* %invoke_frame, i32 0, i32 2
; CHECK-NEXT: %invoke_next = getelementptr %ExceptionFrame* %invoke_frame, i32 0, i32 1
; CHECK-NEXT: %invoke_jmp_buf = getelementptr %ExceptionFrame* %invoke_frame, i32 0, i32 0, i32 0
; CHECK-NEXT: %pnacl_eh_stack = bitcast i8** @__pnacl_eh_stack to %ExceptionFrame**
; CHECK-NEXT: %invoke_sj = call i32 @llvm.nacl.setjmp(i8* %invoke_jmp_buf)
; CHECK-NEXT: %invoke_sj_is_zero = icmp eq i32 %invoke_sj, 0
; CHECK-NEXT: br i1 %invoke_sj_is_zero, label %invoke_do_call, label %lpad
; CHECK: invoke_do_call:
; CHECK-NEXT: %old_eh_stack = load %ExceptionFrame** %pnacl_eh_stack
; CHECK-NEXT: store %ExceptionFrame* %old_eh_stack, %ExceptionFrame** %invoke_next
; CHECK-NEXT: store i32 {{[0-9]+}}, i32* %exc_info_ptr
; CHECK-NEXT: store %ExceptionFrame* %invoke_frame, %ExceptionFrame** %pnacl_eh_stack
; CHECK-NEXT: %result = call i32 @external_func(i64 %arg)
; CHECK-NEXT: store %ExceptionFrame* %old_eh_stack, %ExceptionFrame** %pnacl_eh_stack
; CHECK-NEXT: br label %cont
; CHECK: cont:
; CHECK-NEXT: ret i32 %result
; CHECK: lpad:
; CHECK-NEXT: %landingpad_ptr = bitcast i8* %invoke_jmp_buf to { i8*, i32 }*
; CHECK-NEXT: %lp = load { i8*, i32 }* %landingpad_ptr
; CHECK-NEXT: ret i32 999
; A landingpad block may be used by multiple "invoke" instructions.
define i32 @shared_landingpad(i64 %arg) {
%result1 = invoke i32 @external_func(i64 %arg)
to label %cont1 unwind label %lpad
cont1:
%result2 = invoke i32 @external_func(i64 %arg)
to label %cont2 unwind label %lpad
cont2:
ret i32 %result2
lpad:
%lp = landingpad { i8*, i32 } personality i8* null cleanup
ret i32 999
}
; CHECK: define i32 @shared_landingpad
; CHECK: br i1 %invoke_sj_is_zero, label %invoke_do_call, label %lpad
; CHECK: br i1 %invoke_sj_is_zero2, label %invoke_do_call3, label %lpad
; Check that the pass can handle a landingpad appearing before an invoke.
define i32 @landingpad_before_invoke() {
ret i32 123
dead_block:
%lp = landingpad i32 personality i8* null cleanup
ret i32 %lp
}
; CHECK: define i32 @landingpad_before_invoke
; CHECK: %lp = load i32* %landingpad_ptr
; Test the expansion of the "resume" instruction.
define void @test_resume({ i8*, i32 } %arg) {
resume { i8*, i32 } %arg
}
; CHECK: define void @test_resume
; CHECK-NEXT: %resume_exc = extractvalue { i8*, i32 } %arg, 0
; CHECK-NEXT: %resume_cast = bitcast i8* %resume_exc to i32*
; CHECK-NEXT: call void @__pnacl_eh_resume(i32* %resume_cast)
; CHECK-NEXT: unreachable
; Check that call attributes are preserved.
define i32 @call_attrs(i64 %arg) {
%result = invoke fastcc i32 @external_func(i64 inreg %arg) noreturn
to label %cont unwind label %lpad
cont:
ret i32 %result
lpad:
%lp = landingpad { i8*, i32 } personality i8* null cleanup
ret i32 999
}
; CHECK: define i32 @call_attrs
; CHECK: %result = call fastcc i32 @external_func(i64 inreg %arg) [[NORETURN:#[0-9]+]]
; Check that any PHI nodes referring to the result of an "invoke" are
; updated to refer to the correct basic block.
define i32 @invoke_with_phi_nodes(i64 %arg) {
entry:
%result = invoke i32 @external_func(i64 %arg)
to label %cont unwind label %lpad
cont:
%cont_phi = phi i32 [ 100, %entry ]
ret i32 %cont_phi
lpad:
%lpad_phi = phi i32 [ 200, %entry ]
%lp = landingpad { i8*, i32 } personality i8* null cleanup
ret i32 %lpad_phi
}
; CHECK: define i32 @invoke_with_phi_nodes
; CHECK: %result = call i32 @external_func(i64 %arg)
; CHECK: cont:
; CHECK-NEXT: %cont_phi = phi i32 [ 100, %invoke_do_call ]
; CHECK-NEXT: ret i32 %cont_phi
; CHECK: lpad:
; CHECK-NEXT: %lpad_phi = phi i32 [ 200, %entry ]
; CHECK: ret i32 %lpad_phi
; CHECK: attributes [[NORETURN]] = { noreturn }
|