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