diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerGlobalDtors.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerGlobalDtors.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerGlobalDtors.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerGlobalDtors.cpp @@ -78,7 +78,10 @@ // Collect the contents of @llvm.global_dtors, collated by priority and // associated symbol. - std::map>> DtorFuncs; + std::map< + uint16_t, + std::vector>> + > DtorFuncs; for (Value *O : InitList->operands()) { auto *CS = dyn_cast(O); if (!CS) @@ -96,7 +99,14 @@ Constant *Associated = CS->getOperand(2); Associated = cast(Associated->stripPointerCasts()); - DtorFuncs[PriorityValue][Associated].push_back(DtorFunc); + auto &AtThisPriority = DtorFuncs[PriorityValue]; + if (AtThisPriority.empty() || AtThisPriority.back().first != Associated) { + std::vector NewList; + NewList.push_back(DtorFunc); + AtThisPriority.push_back(std::make_pair(Associated, NewList)); + } else { + AtThisPriority.back().second.push_back(DtorFunc); + } } if (DtorFuncs.empty()) return false; @@ -131,14 +141,19 @@ // first function with __cxa_atexit. for (auto &PriorityAndMore : DtorFuncs) { uint16_t Priority = PriorityAndMore.first; - for (auto &AssociatedAndMore : PriorityAndMore.second) { + uint64_t Id = 0; + auto &AtThisPriority = PriorityAndMore.second; + for (auto &AssociatedAndMore : AtThisPriority) { Constant *Associated = AssociatedAndMore.first; + auto ThisId = Id++; Function *CallDtors = Function::Create( AtExitFuncTy, Function::PrivateLinkage, "call_dtors" + (Priority != UINT16_MAX ? (Twine(".") + Twine(Priority)) : Twine()) + + (AtThisPriority.size() > 1 ? Twine("$") + Twine(ThisId) + : Twine()) + (!Associated->isNullValue() ? (Twine(".") + Associated->getName()) : Twine()), &M); @@ -146,7 +161,7 @@ FunctionType *VoidVoid = FunctionType::get(Type::getVoidTy(C), /*isVarArg=*/false); - for (auto Dtor : AssociatedAndMore.second) + for (auto Dtor : reverse(AssociatedAndMore.second)) CallInst::Create(VoidVoid, Dtor, "", BB); ReturnInst::Create(C, BB); @@ -155,6 +170,8 @@ "register_call_dtors" + (Priority != UINT16_MAX ? (Twine(".") + Twine(Priority)) : Twine()) + + (AtThisPriority.size() > 1 ? Twine("$") + Twine(ThisId) + : Twine()) + (!Associated->isNullValue() ? (Twine(".") + Associated->getName()) : Twine()), &M); diff --git a/llvm/test/CodeGen/WebAssembly/lower-global-dtors.ll b/llvm/test/CodeGen/WebAssembly/lower-global-dtors.ll --- a/llvm/test/CodeGen/WebAssembly/lower-global-dtors.ll +++ b/llvm/test/CodeGen/WebAssembly/lower-global-dtors.ll @@ -13,11 +13,17 @@ declare void @orig_dtor1c0() declare void @orig_dtor1c1a() declare void @orig_dtor1c1b() -declare void @orig_dtor65536() +declare void @orig_dtor1c2a() +declare void @orig_dtor1c2b() +declare void @orig_dtor1c3() +declare void @orig_dtor1d() +declare void @orig_dtor65535() declare void @after_the_null() @associated1c0 = external global i8 @associated1c1 = external global i8 +@associated1c2 = global i8 42 +@associated1c3 = global i8 84 @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] @@ -26,7 +32,7 @@ ] @llvm.global_dtors = appending global -[9 x { i32, void ()*, i8* }] +[13 x { i32, void ()*, i8* }] [ { i32, void ()*, i8* } { i32 0, void ()* @orig_dtor0, i8* null }, { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1a, i8* null }, @@ -34,7 +40,11 @@ { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1c0, i8* @associated1c0 }, { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1c1a, i8* @associated1c1 }, { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1c1b, i8* @associated1c1 }, - { i32, void ()*, i8* } { i32 65535, void ()* @orig_dtor65536, i8* null }, + { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1c2a, i8* @associated1c2 }, + { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1c2b, i8* @associated1c2 }, + { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1c3, i8* @associated1c3 }, + { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1d, i8* null }, + { i32, void ()*, i8* } { i32 65535, void ()* @orig_dtor65535, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* null, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @after_the_null, i8* null } ] @@ -54,14 +64,14 @@ ; CHECK-NEXT: unreachable ; CHECK: end_block -; CHECK-LABEL: .Lcall_dtors.1: -; CHECK-NEXT: .functype .Lcall_dtors.1 (i32) -> (){{$}} -; CHECK-NEXT: call orig_dtor1a{{$}} +; CHECK-LABEL: .Lcall_dtors.1$0: +; CHECK-NEXT: .functype .Lcall_dtors.1$0 (i32) -> (){{$}} ; CHECK-NEXT: call orig_dtor1b{{$}} +; CHECK-NEXT: call orig_dtor1a{{$}} -; CHECK-LABEL: .Lregister_call_dtors.1: +; CHECK-LABEL: .Lregister_call_dtors.1$0: ; CHECK: block -; CHECK-NEXT: i32.const $push2=, .Lcall_dtors.1{{$}} +; CHECK-NEXT: i32.const $push2=, .Lcall_dtors.1$0{{$}} ; CHECK-NEXT: i32.const $push1=, 0 ; CHECK-NEXT: i32.const $push0=, __dso_handle ; CHECK-NEXT: i32.call $push3=, __cxa_atexit, $pop2, $pop1, $pop0{{$}} @@ -70,13 +80,13 @@ ; CHECK-NEXT: unreachable ; CHECK: end_block -; CHECK-LABEL: .Lcall_dtors.1.associated1c0: -; CHECK-NEXT: .functype .Lcall_dtors.1.associated1c0 (i32) -> (){{$}} +; CHECK-LABEL: .Lcall_dtors.1$1.associated1c0: +; CHECK-NEXT: .functype .Lcall_dtors.1$1.associated1c0 (i32) -> (){{$}} ; CHECK-NEXT: call orig_dtor1c0{{$}} -; CHECK-LABEL: .Lregister_call_dtors.1.associated1c0: +; CHECK-LABEL: .Lregister_call_dtors.1$1.associated1c0: ; CHECK: block -; CHECK-NEXT: i32.const $push2=, .Lcall_dtors.1.associated1c0{{$}} +; CHECK-NEXT: i32.const $push2=, .Lcall_dtors.1$1.associated1c0{{$}} ; CHECK-NEXT: i32.const $push1=, 0 ; CHECK-NEXT: i32.const $push0=, __dso_handle ; CHECK-NEXT: i32.call $push3=, __cxa_atexit, $pop2, $pop1, $pop0{{$}} @@ -84,14 +94,57 @@ ; CHECK-NEXT: br_if 0, $pop4 ; CHECK-NEXT: unreachable -; CHECK-LABEL: .Lcall_dtors.1.associated1c1: -; CHECK-NEXT: .functype .Lcall_dtors.1.associated1c1 (i32) -> (){{$}} -; CHECK-NEXT: call orig_dtor1c1a{{$}} +; CHECK-LABEL: .Lcall_dtors.1$2.associated1c1: +; CHECK-NEXT: .functype .Lcall_dtors.1$2.associated1c1 (i32) -> (){{$}} ; CHECK-NEXT: call orig_dtor1c1b{{$}} +; CHECK-NEXT: call orig_dtor1c1a{{$}} + +; CHECK-LABEL: .Lregister_call_dtors.1$2.associated1c1: +; CHECK: block +; CHECK-NEXT: i32.const $push2=, .Lcall_dtors.1$2.associated1c1{{$}} +; CHECK-NEXT: i32.const $push1=, 0 +; CHECK-NEXT: i32.const $push0=, __dso_handle +; CHECK-NEXT: i32.call $push3=, __cxa_atexit, $pop2, $pop1, $pop0{{$}} +; CHECK-NEXT: i32.eqz $push4=, $pop3 +; CHECK-NEXT: br_if 0, $pop4 +; CHECK-NEXT: unreachable + +; CHECK-LABEL: .Lcall_dtors.1$3.associated1c2: +; CHECK-NEXT: .functype .Lcall_dtors.1$3.associated1c2 (i32) -> (){{$}} +; CHECK-NEXT: call orig_dtor1c2b{{$}} +; CHECK-NEXT: call orig_dtor1c2a{{$}} + +; CHECK-LABEL: .Lregister_call_dtors.1$3.associated1c2: +; CHECK: block +; CHECK-NEXT: i32.const $push2=, .Lcall_dtors.1$3.associated1c2{{$}} +; CHECK-NEXT: i32.const $push1=, 0 +; CHECK-NEXT: i32.const $push0=, __dso_handle +; CHECK-NEXT: i32.call $push3=, __cxa_atexit, $pop2, $pop1, $pop0{{$}} +; CHECK-NEXT: i32.eqz $push4=, $pop3 +; CHECK-NEXT: br_if 0, $pop4 +; CHECK-NEXT: unreachable + +; CHECK-LABEL: .Lcall_dtors.1$4.associated1c3: +; CHECK-NEXT: .functype .Lcall_dtors.1$4.associated1c3 (i32) -> (){{$}} +; CHECK-NEXT: call orig_dtor1c3{{$}} + +; CHECK-LABEL: .Lregister_call_dtors.1$4.associated1c3: +; CHECK: block +; CHECK-NEXT: i32.const $push2=, .Lcall_dtors.1$4.associated1c3{{$}} +; CHECK-NEXT: i32.const $push1=, 0 +; CHECK-NEXT: i32.const $push0=, __dso_handle +; CHECK-NEXT: i32.call $push3=, __cxa_atexit, $pop2, $pop1, $pop0{{$}} +; CHECK-NEXT: i32.eqz $push4=, $pop3 +; CHECK-NEXT: br_if 0, $pop4 +; CHECK-NEXT: unreachable + +; CHECK-LABEL: .Lcall_dtors.1$5: +; CHECK-NEXT: .functype .Lcall_dtors.1$5 (i32) -> (){{$}} +; CHECK-NEXT: call orig_dtor1d{{$}} -; CHECK-LABEL: .Lregister_call_dtors.1.associated1c1: +; CHECK-LABEL: .Lregister_call_dtors.1$5: ; CHECK: block -; CHECK-NEXT: i32.const $push2=, .Lcall_dtors.1.associated1c1{{$}} +; CHECK-NEXT: i32.const $push2=, .Lcall_dtors.1$5{{$}} ; CHECK-NEXT: i32.const $push1=, 0 ; CHECK-NEXT: i32.const $push0=, __dso_handle ; CHECK-NEXT: i32.call $push3=, __cxa_atexit, $pop2, $pop1, $pop0{{$}} @@ -101,7 +154,7 @@ ; CHECK-LABEL: .Lcall_dtors: ; CHECK-NEXT: .functype .Lcall_dtors (i32) -> (){{$}} -; CHECK-NEXT: call orig_dtor65536{{$}} +; CHECK-NEXT: call orig_dtor65535{{$}} ; CHECK-LABEL: .Lregister_call_dtors: ; CHECK: block @@ -116,7 +169,10 @@ ; CHECK-LABEL: .section .init_array.0,"",@ ; CHECK: .int32 .Lregister_call_dtors.0{{$}} ; CHECK-LABEL: .section .init_array.1,"",@ -; CHECK: .int32 .Lregister_call_dtors.1{{$}} +; CHECK: .int32 .Lregister_call_dtors.1$0{{$}} +; CHECK-NEXT: .int32 .Lregister_call_dtors.1$3.associated1c2{{$}} +; CHECK-NEXT: .int32 .Lregister_call_dtors.1$4.associated1c3{{$}} +; CHECK-NEXT: .int32 .Lregister_call_dtors.1$5{{$}} ; CHECK-LABEL: .section .init_array.200,"",@ ; CHECK: .int32 orig_ctor{{$}} ; CHECK-LABEL: .section .init_array,"",@