1; RUN: llc < %s -asm-verbose=false | FileCheck --check-prefix=CHECK --check-prefix=FINI --check-prefix=NULL %s
2
3target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
4target triple = "wasm32-unknown-unknown"
5
6; Test that @llvm.global_dtors is properly lowered into @llvm.global_ctors,
7; grouping dtor calls by priority and associated symbol.
8
9declare void @orig_ctor()
10declare void @orig_dtor0()
11declare void @orig_dtor1a()
12declare void @orig_dtor1b()
13declare void @orig_dtor1c0()
14declare void @orig_dtor1c1a()
15declare void @orig_dtor1c1b()
16declare void @orig_dtor65536()
17declare void @after_the_null()
18
19@associated1c0 = external global i8
20@associated1c1 = external global i8
21
22@llvm.global_ctors = appending global
23[1 x { i32, void ()*, i8* }]
24[
25  { i32, void ()*, i8* } { i32 200, void ()* @orig_ctor, i8* null }
26]
27
28@llvm.global_dtors = appending global
29[9 x { i32, void ()*, i8* }]
30[
31  { i32, void ()*, i8* } { i32 0, void ()* @orig_dtor0, i8* null },
32  { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1a, i8* null },
33  { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1b, i8* null },
34  { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1c0, i8* @associated1c0 },
35  { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1c1a, i8* @associated1c1 },
36  { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1c1b, i8* @associated1c1 },
37  { i32, void ()*, i8* } { i32 65535, void ()* @orig_dtor65536, i8* null },
38  { i32, void ()*, i8* } { i32 65535, void ()* null, i8* null },
39  { i32, void ()*, i8* } { i32 65535, void ()* @after_the_null, i8* null }
40]
41
42; CHECK-LABEL: .Lcall_dtors.0:
43; CHECK-NEXT: .param          i32{{$}}
44; CHECK-NEXT: call            orig_dtor0@FUNCTION{{$}}
45
46; CHECK-LABEL: .Lregister_call_dtors.0:
47; CHECK-NEXT: block
48; CHECK-NEXT: i32.const       $push2=, .Lcall_dtors.0@FUNCTION{{$}}
49; CHECK-NEXT: i32.const       $push1=, 0
50; CHECK-NEXT: i32.const       $push0=, __dso_handle
51; CHECK-NEXT: i32.call        $push3=, __cxa_atexit@FUNCTION, $pop2, $pop1, $pop0{{$}}
52; CHECK-NEXT: br_if           0, $pop3
53; CHECK-NEXT: return
54;      CHECK: end_block
55; CHECK-NEXT: unreachable
56
57; CHECK-LABEL: .Lcall_dtors.1:
58; CHECK-NEXT: .param          i32{{$}}
59; CHECK-NEXT: call            orig_dtor1a@FUNCTION{{$}}
60; CHECK-NEXT: call            orig_dtor1b@FUNCTION{{$}}
61
62; CHECK-LABEL: .Lregister_call_dtors.1:
63; CHECK-NEXT: block
64; CHECK-NEXT: i32.const       $push2=, .Lcall_dtors.1@FUNCTION{{$}}
65; CHECK-NEXT: i32.const       $push1=, 0
66; CHECK-NEXT: i32.const       $push0=, __dso_handle
67; CHECK-NEXT: i32.call        $push3=, __cxa_atexit@FUNCTION, $pop2, $pop1, $pop0{{$}}
68; CHECK-NEXT: br_if           0, $pop3
69; CHECK-NEXT: return
70;      CHECK: end_block
71; CHECK-NEXT: unreachable
72
73; CHECK-LABEL: .Lcall_dtors.1.associated1c0:
74; CHECK-NEXT: .param          i32{{$}}
75; CHECK-NEXT: call            orig_dtor1c0@FUNCTION{{$}}
76
77; CHECK-LABEL: .Lregister_call_dtors.1.associated1c0:
78; CHECK-NEXT: block
79; CHECK-NEXT: i32.const       $push2=, .Lcall_dtors.1.associated1c0@FUNCTION{{$}}
80; CHECK-NEXT: i32.const       $push1=, 0
81; CHECK-NEXT: i32.const       $push0=, __dso_handle
82; CHECK-NEXT: i32.call        $push3=, __cxa_atexit@FUNCTION, $pop2, $pop1, $pop0{{$}}
83; CHECK-NEXT: br_if           0, $pop3
84; CHECK-NEXT: return
85;      CHECK: end_block
86; CHECK-NEXT: unreachable
87
88; CHECK-LABEL: .Lcall_dtors.1.associated1c1:
89; CHECK-NEXT: .param          i32{{$}}
90; CHECK-NEXT: call            orig_dtor1c1a@FUNCTION{{$}}
91; CHECK-NEXT: call            orig_dtor1c1b@FUNCTION{{$}}
92
93; CHECK-LABEL: .Lregister_call_dtors.1.associated1c1:
94; CHECK-NEXT: block
95; CHECK-NEXT: i32.const       $push2=, .Lcall_dtors.1.associated1c1@FUNCTION{{$}}
96; CHECK-NEXT: i32.const       $push1=, 0
97; CHECK-NEXT: i32.const       $push0=, __dso_handle
98; CHECK-NEXT: i32.call        $push3=, __cxa_atexit@FUNCTION, $pop2, $pop1, $pop0{{$}}
99; CHECK-NEXT: br_if           0, $pop3
100; CHECK-NEXT: return
101;      CHECK: end_block
102; CHECK-NEXT: unreachable
103
104; CHECK-LABEL: .Lcall_dtors:
105; CHECK-NEXT: .param          i32{{$}}
106; CHECK-NEXT: call            orig_dtor65536@FUNCTION{{$}}
107
108; CHECK-LABEL: .Lregister_call_dtors:
109; CHECK-NEXT: block
110; CHECK-NEXT: i32.const       $push2=, .Lcall_dtors@FUNCTION{{$}}
111; CHECK-NEXT: i32.const       $push1=, 0
112; CHECK-NEXT: i32.const       $push0=, __dso_handle
113; CHECK-NEXT: i32.call        $push3=, __cxa_atexit@FUNCTION, $pop2, $pop1, $pop0{{$}}
114; CHECK-NEXT: br_if           0, $pop3
115; CHECK-NEXT: return
116;      CHECK: end_block
117; CHECK-NEXT: unreachable
118
119; CHECK-LABEL: .section .init_array.0,"",@
120;      CHECK: .int32  .Lregister_call_dtors.0@FUNCTION{{$}}
121; CHECK-LABEL: .section .init_array.1,"",@
122;      CHECK: .int32  .Lregister_call_dtors.1@FUNCTION{{$}}
123; CHECK-LABEL: .section .init_array.200,"",@
124;      CHECK: .int32  orig_ctor@FUNCTION{{$}}
125; CHECK-LABEL: .section .init_array,"",@
126;      CHECK: .int32  .Lregister_call_dtors@FUNCTION{{$}}
127
128; CHECK-LABEL: .weak __dso_handle
129
130; CHECK-LABEL: .functype __cxa_atexit, i32, i32, i32, i32{{$}}
131
132; We shouldn't make use of a .fini_array section.
133
134; FINI-NOT: fini_array
135
136; This function is listed after the null terminator, so it should
137; be excluded.
138
139; NULL-NOT: after_the_null
140