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 @@ -76,9 +76,13 @@ !ETy->getTypeAtIndex(2U)->isPointerTy()) return false; // Not (int, ptr, ptr). - // Collect the contents of @llvm.global_dtors, collated by priority and - // associated symbol. - std::map>> DtorFuncs; + // Collect the contents of @llvm.global_dtors, ordered by priority. Within a + // priority, sequences of destructors with the same associated object are + // recorded so that we can register them as a group. + std::map< + uint16_t, + std::vector>> + > DtorFuncs; for (Value *O : InitList->operands()) { auto *CS = dyn_cast(O); if (!CS) @@ -96,7 +100,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 +142,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 +162,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 +171,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,18 @@ 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 @orig_dtor65535c0() declare void @after_the_null() -@associated1c0 = external global i8 -@associated1c1 = external global i8 +@associatedc0 = external global i8 +@associatedc1 = external global i8 +@associatedc2 = global i8 42 +@associatedc3 = global i8 84 @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] @@ -26,15 +33,20 @@ ] @llvm.global_dtors = appending global -[9 x { i32, void ()*, i8* }] +[14 x { i32, void ()*, i8* }] [ { i32, void ()*, i8* } { i32 0, void ()* @orig_dtor0, i8* null }, { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1a, i8* null }, { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1b, i8* null }, - { 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_dtor1c0, i8* @associatedc0 }, + { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1c1a, i8* @associatedc1 }, + { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1c1b, i8* @associatedc1 }, + { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1c2a, i8* @associatedc2 }, + { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1c2b, i8* @associatedc2 }, + { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1c3, i8* @associatedc3 }, + { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1d, i8* null }, + { i32, void ()*, i8* } { i32 65535, void ()* @orig_dtor65535c0, i8* @associatedc0 }, + { 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 +66,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: call $push3=, __cxa_atexit, $pop2, $pop1, $pop0{{$}} @@ -70,13 +82,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.associatedc0: +; CHECK-NEXT: .functype .Lcall_dtors.1$1.associatedc0 (i32) -> (){{$}} ; CHECK-NEXT: call orig_dtor1c0{{$}} -; CHECK-LABEL: .Lregister_call_dtors.1.associated1c0: +; CHECK-LABEL: .Lregister_call_dtors.1$1.associatedc0: ; CHECK: block -; CHECK-NEXT: i32.const $push2=, .Lcall_dtors.1.associated1c0{{$}} +; CHECK-NEXT: i32.const $push2=, .Lcall_dtors.1$1.associatedc0{{$}} ; CHECK-NEXT: i32.const $push1=, 0 ; CHECK-NEXT: i32.const $push0=, __dso_handle ; CHECK-NEXT: call $push3=, __cxa_atexit, $pop2, $pop1, $pop0{{$}} @@ -84,14 +96,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.associatedc1: +; CHECK-NEXT: .functype .Lcall_dtors.1$2.associatedc1 (i32) -> (){{$}} ; CHECK-NEXT: call orig_dtor1c1b{{$}} +; CHECK-NEXT: call orig_dtor1c1a{{$}} + +; CHECK-LABEL: .Lregister_call_dtors.1$2.associatedc1: +; CHECK: block +; CHECK-NEXT: i32.const $push2=, .Lcall_dtors.1$2.associatedc1{{$}} +; CHECK-NEXT: i32.const $push1=, 0 +; CHECK-NEXT: i32.const $push0=, __dso_handle +; CHECK-NEXT: 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.associatedc2: +; CHECK-NEXT: .functype .Lcall_dtors.1$3.associatedc2 (i32) -> (){{$}} +; CHECK-NEXT: call orig_dtor1c2b{{$}} +; CHECK-NEXT: call orig_dtor1c2a{{$}} + +; CHECK-LABEL: .Lregister_call_dtors.1$3.associatedc2: +; CHECK: block +; CHECK-NEXT: i32.const $push2=, .Lcall_dtors.1$3.associatedc2{{$}} +; CHECK-NEXT: i32.const $push1=, 0 +; CHECK-NEXT: i32.const $push0=, __dso_handle +; CHECK-NEXT: 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.associatedc3: +; CHECK-NEXT: .functype .Lcall_dtors.1$4.associatedc3 (i32) -> (){{$}} +; CHECK-NEXT: call orig_dtor1c3{{$}} + +; CHECK-LABEL: .Lregister_call_dtors.1$4.associatedc3: +; CHECK: block +; CHECK-NEXT: i32.const $push2=, .Lcall_dtors.1$4.associatedc3{{$}} +; CHECK-NEXT: i32.const $push1=, 0 +; CHECK-NEXT: i32.const $push0=, __dso_handle +; CHECK-NEXT: call $push3=, __cxa_atexit, $pop2, $pop1, $pop0{{$}} +; CHECK-NEXT: i32.eqz $push4=, $pop3 +; CHECK-NEXT: br_if 0, $pop4 +; CHECK-NEXT: unreachable -; CHECK-LABEL: .Lregister_call_dtors.1.associated1c1: +; 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$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: call $push3=, __cxa_atexit, $pop2, $pop1, $pop0{{$}} @@ -99,13 +154,17 @@ ; CHECK-NEXT: br_if 0, $pop4 ; CHECK-NEXT: unreachable -; CHECK-LABEL: .Lcall_dtors: -; CHECK-NEXT: .functype .Lcall_dtors (i32) -> (){{$}} -; CHECK-NEXT: call orig_dtor65536{{$}} +; CHECK-LABEL: .Lcall_dtors$0.associatedc0: +; CHECK-NEXT: .functype .Lcall_dtors$0.associatedc0 (i32) -> (){{$}} +; CHECK-NEXT: call orig_dtor65535c0 + +; CHECK-LABEL: .Lcall_dtors$1: +; CHECK-NEXT: .functype .Lcall_dtors$1 (i32) -> (){{$}} +; CHECK-NEXT: call orig_dtor65535{{$}} -; CHECK-LABEL: .Lregister_call_dtors: +; CHECK-LABEL: .Lregister_call_dtors$1: ; CHECK: block -; CHECK-NEXT: i32.const $push2=, .Lcall_dtors{{$}} +; CHECK-NEXT: i32.const $push2=, .Lcall_dtors$1{{$}} ; CHECK-NEXT: i32.const $push1=, 0 ; CHECK-NEXT: i32.const $push0=, __dso_handle ; CHECK-NEXT: call $push3=, __cxa_atexit, $pop2, $pop1, $pop0{{$}} @@ -116,11 +175,14 @@ ; 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.associatedc2{{$}} +; CHECK-NEXT: .int32 .Lregister_call_dtors.1$4.associatedc3{{$}} +; CHECK-NEXT: .int32 .Lregister_call_dtors.1$5{{$}} ; CHECK-LABEL: .section .init_array.200,"",@ ; CHECK: .int32 orig_ctor{{$}} ; CHECK-LABEL: .section .init_array,"",@ -; CHECK: .int32 .Lregister_call_dtors{{$}} +; CHECK: .int32 .Lregister_call_dtors$1{{$}} ; CHECK-LABEL: .weak __dso_handle