xref: /llvm-project/llvm/test/CodeGen/WebAssembly/lower-global-dtors.ll (revision 73856247eef35f5336e485dc009842a5b991c421)
1; RUN: llc < %s -asm-verbose=false -wasm-keep-registers | FileCheck --check-prefix=CHECK --check-prefix=FINI --check-prefix=NULL %s
2
3target triple = "wasm32-unknown-unknown"
4
5; Test that @llvm.global_dtors is properly lowered into @llvm.global_ctors,
6; grouping dtor calls by priority and associated symbol.
7
8declare void @orig_ctor()
9declare void @orig_dtor0()
10declare void @orig_dtor1a()
11declare void @orig_dtor1b()
12declare void @orig_dtor1c0()
13declare void @orig_dtor1c1a()
14declare void @orig_dtor1c1b()
15declare void @orig_dtor1c2a()
16declare void @orig_dtor1c2b()
17declare void @orig_dtor1c3()
18declare void @orig_dtor1d()
19declare void @orig_dtor65535()
20declare void @orig_dtor65535c0()
21declare void @after_the_null()
22
23@associatedc0 = external global i8
24@associatedc1 = external global i8
25@associatedc2 = global i8 42
26@associatedc3 = global i8 84
27
28@llvm.global_ctors = appending global
29[1 x { i32, ptr, ptr }]
30[
31  { i32, ptr, ptr } { i32 200, ptr @orig_ctor, ptr null }
32]
33
34@llvm.global_dtors = appending global
35[14 x { i32, ptr, ptr }]
36[
37  { i32, ptr, ptr } { i32 0, ptr @orig_dtor0, ptr null },
38  { i32, ptr, ptr } { i32 1, ptr @orig_dtor1a, ptr null },
39  { i32, ptr, ptr } { i32 1, ptr @orig_dtor1b, ptr null },
40  { i32, ptr, ptr } { i32 1, ptr @orig_dtor1c0, ptr @associatedc0 },
41  { i32, ptr, ptr } { i32 1, ptr @orig_dtor1c1a, ptr @associatedc1 },
42  { i32, ptr, ptr } { i32 1, ptr @orig_dtor1c1b, ptr @associatedc1 },
43  { i32, ptr, ptr } { i32 1, ptr @orig_dtor1c2a, ptr @associatedc2 },
44  { i32, ptr, ptr } { i32 1, ptr @orig_dtor1c2b, ptr @associatedc2 },
45  { i32, ptr, ptr } { i32 1, ptr @orig_dtor1c3, ptr @associatedc3 },
46  { i32, ptr, ptr } { i32 1, ptr @orig_dtor1d, ptr null },
47  { i32, ptr, ptr } { i32 65535, ptr @orig_dtor65535c0, ptr @associatedc0 },
48  { i32, ptr, ptr } { i32 65535, ptr @orig_dtor65535, ptr null },
49  { i32, ptr, ptr } { i32 65535, ptr null, ptr null },
50  { i32, ptr, ptr } { i32 65535, ptr @after_the_null, ptr null }
51]
52
53; CHECK-LABEL: .functype __cxa_atexit (i32, i32, i32) -> (i32){{$}}
54
55; CHECK-LABEL: .Lcall_dtors.0:
56; CHECK-NEXT: .functype .Lcall_dtors.0 (i32) -> (){{$}}
57; CHECK-NEXT: call            orig_dtor0{{$}}
58
59; CHECK-LABEL: .Lregister_call_dtors.0:
60; CHECK:      block
61; CHECK-NEXT: i32.const       $push2=, .Lcall_dtors.0{{$}}
62; CHECK-NEXT: i32.const       $push1=, 0
63; CHECK-NEXT: i32.const       $push0=, __dso_handle
64; CHECK-NEXT: call            $push3=, __cxa_atexit, $pop2, $pop1, $pop0{{$}}
65; CHECK-NEXT: i32.eqz         $push4=, $pop3
66; CHECK-NEXT: br_if           0, $pop4
67; CHECK-NEXT: unreachable
68;      CHECK: end_block
69
70; CHECK-LABEL: .Lcall_dtors.1$0:
71; CHECK-NEXT: .functype .Lcall_dtors.1$0 (i32) -> (){{$}}
72; CHECK-NEXT: call            orig_dtor1b{{$}}
73; CHECK-NEXT: call            orig_dtor1a{{$}}
74
75; CHECK-LABEL: .Lregister_call_dtors.1$0:
76; CHECK:      block
77; CHECK-NEXT: i32.const       $push2=, .Lcall_dtors.1$0{{$}}
78; CHECK-NEXT: i32.const       $push1=, 0
79; CHECK-NEXT: i32.const       $push0=, __dso_handle
80; CHECK-NEXT: call            $push3=, __cxa_atexit, $pop2, $pop1, $pop0{{$}}
81; CHECK-NEXT: i32.eqz         $push4=, $pop3
82; CHECK-NEXT: br_if           0, $pop4
83; CHECK-NEXT: unreachable
84;      CHECK: end_block
85
86; CHECK-LABEL: .Lcall_dtors.1$1.associatedc0:
87; CHECK-NEXT: .functype .Lcall_dtors.1$1.associatedc0 (i32) -> (){{$}}
88; CHECK-NEXT: call            orig_dtor1c0{{$}}
89
90; CHECK-LABEL: .Lregister_call_dtors.1$1.associatedc0:
91; CHECK:      block
92; CHECK-NEXT: i32.const       $push2=, .Lcall_dtors.1$1.associatedc0{{$}}
93; CHECK-NEXT: i32.const       $push1=, 0
94; CHECK-NEXT: i32.const       $push0=, __dso_handle
95; CHECK-NEXT: call            $push3=, __cxa_atexit, $pop2, $pop1, $pop0{{$}}
96; CHECK-NEXT: i32.eqz         $push4=, $pop3
97; CHECK-NEXT: br_if           0, $pop4
98; CHECK-NEXT: unreachable
99
100; CHECK-LABEL: .Lcall_dtors.1$2.associatedc1:
101; CHECK-NEXT: .functype .Lcall_dtors.1$2.associatedc1 (i32) -> (){{$}}
102; CHECK-NEXT: call            orig_dtor1c1b{{$}}
103; CHECK-NEXT: call            orig_dtor1c1a{{$}}
104
105; CHECK-LABEL: .Lregister_call_dtors.1$2.associatedc1:
106; CHECK:      block
107; CHECK-NEXT: i32.const       $push2=, .Lcall_dtors.1$2.associatedc1{{$}}
108; CHECK-NEXT: i32.const       $push1=, 0
109; CHECK-NEXT: i32.const       $push0=, __dso_handle
110; CHECK-NEXT: call            $push3=, __cxa_atexit, $pop2, $pop1, $pop0{{$}}
111; CHECK-NEXT: i32.eqz         $push4=, $pop3
112; CHECK-NEXT: br_if           0, $pop4
113; CHECK-NEXT: unreachable
114
115; CHECK-LABEL: .Lcall_dtors.1$3.associatedc2:
116; CHECK-NEXT: .functype .Lcall_dtors.1$3.associatedc2 (i32) -> (){{$}}
117; CHECK-NEXT: call            orig_dtor1c2b{{$}}
118; CHECK-NEXT: call            orig_dtor1c2a{{$}}
119
120; CHECK-LABEL: .Lregister_call_dtors.1$3.associatedc2:
121; CHECK:      block
122; CHECK-NEXT: i32.const       $push2=, .Lcall_dtors.1$3.associatedc2{{$}}
123; CHECK-NEXT: i32.const       $push1=, 0
124; CHECK-NEXT: i32.const       $push0=, __dso_handle
125; CHECK-NEXT: call            $push3=, __cxa_atexit, $pop2, $pop1, $pop0{{$}}
126; CHECK-NEXT: i32.eqz         $push4=, $pop3
127; CHECK-NEXT: br_if           0, $pop4
128; CHECK-NEXT: unreachable
129
130; CHECK-LABEL: .Lcall_dtors.1$4.associatedc3:
131; CHECK-NEXT: .functype .Lcall_dtors.1$4.associatedc3 (i32) -> (){{$}}
132; CHECK-NEXT: call            orig_dtor1c3{{$}}
133
134; CHECK-LABEL: .Lregister_call_dtors.1$4.associatedc3:
135; CHECK:      block
136; CHECK-NEXT: i32.const       $push2=, .Lcall_dtors.1$4.associatedc3{{$}}
137; CHECK-NEXT: i32.const       $push1=, 0
138; CHECK-NEXT: i32.const       $push0=, __dso_handle
139; CHECK-NEXT: call            $push3=, __cxa_atexit, $pop2, $pop1, $pop0{{$}}
140; CHECK-NEXT: i32.eqz         $push4=, $pop3
141; CHECK-NEXT: br_if           0, $pop4
142; CHECK-NEXT: unreachable
143
144; CHECK-LABEL: .Lcall_dtors.1$5:
145; CHECK-NEXT: .functype .Lcall_dtors.1$5 (i32) -> (){{$}}
146; CHECK-NEXT: call            orig_dtor1d{{$}}
147
148; CHECK-LABEL: .Lregister_call_dtors.1$5:
149; CHECK:      block
150; CHECK-NEXT: i32.const       $push2=, .Lcall_dtors.1$5{{$}}
151; CHECK-NEXT: i32.const       $push1=, 0
152; CHECK-NEXT: i32.const       $push0=, __dso_handle
153; CHECK-NEXT: call            $push3=, __cxa_atexit, $pop2, $pop1, $pop0{{$}}
154; CHECK-NEXT: i32.eqz         $push4=, $pop3
155; CHECK-NEXT: br_if           0, $pop4
156; CHECK-NEXT: unreachable
157
158; CHECK-LABEL: .Lcall_dtors$0.associatedc0:
159; CHECK-NEXT: .functype .Lcall_dtors$0.associatedc0 (i32) -> (){{$}}
160; CHECK-NEXT: call            orig_dtor65535c0
161
162; CHECK-LABEL: .Lcall_dtors$1:
163; CHECK-NEXT: .functype .Lcall_dtors$1 (i32) -> (){{$}}
164; CHECK-NEXT: call            orig_dtor65535{{$}}
165
166; CHECK-LABEL: .Lregister_call_dtors$1:
167; CHECK:      block
168; CHECK-NEXT: i32.const       $push2=, .Lcall_dtors$1{{$}}
169; CHECK-NEXT: i32.const       $push1=, 0
170; CHECK-NEXT: i32.const       $push0=, __dso_handle
171; CHECK-NEXT: call            $push3=, __cxa_atexit, $pop2, $pop1, $pop0{{$}}
172; CHECK-NEXT: i32.eqz         $push4=, $pop3
173; CHECK-NEXT: br_if           0, $pop4
174; CHECK-NEXT: unreachable
175
176; CHECK-LABEL: .section .init_array.0,"",@
177;      CHECK: .int32  .Lregister_call_dtors.0{{$}}
178; CHECK-LABEL: .section .init_array.1,"",@
179;      CHECK: .int32  .Lregister_call_dtors.1$0{{$}}
180; CHECK-NEXT: .int32  .Lregister_call_dtors.1$3.associatedc2{{$}}
181; CHECK-NEXT: .int32  .Lregister_call_dtors.1$4.associatedc3{{$}}
182; CHECK-NEXT: .int32  .Lregister_call_dtors.1$5{{$}}
183; CHECK-LABEL: .section .init_array.200,"",@
184;      CHECK: .int32  orig_ctor{{$}}
185; CHECK-LABEL: .section .init_array,"",@
186;      CHECK: .int32  .Lregister_call_dtors$1{{$}}
187
188; CHECK-LABEL: .weak __dso_handle
189
190; We shouldn't make use of a .fini_array section.
191
192; FINI-NOT: fini_array
193
194; This function is listed after the null terminator, so it should
195; be excluded.
196
197; NULL-NOT: after_the_null
198