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