[llvm] r320774 - [WebAssembly] Implement @llvm.global_ctors and @llvm.global_dtors
Sam Clegg via llvm-commits
llvm-commits at lists.llvm.org
Thu Dec 14 16:17:10 PST 2017
Author: sbc
Date: Thu Dec 14 16:17:10 2017
New Revision: 320774
URL: http://llvm.org/viewvc/llvm-project?rev=320774&view=rev
Log:
[WebAssembly] Implement @llvm.global_ctors and @llvm.global_dtors
Summary:
- lowers @llvm.global_dtors by adding @llvm.global_ctors
functions which register the destructors with `__cxa_atexit`.
- impements @llvm.global_ctors with wasm start functions and linker metadata
See [here](https://github.com/WebAssembly/tool-conventions/issues/25) for more background.
Subscribers: jfb, dschuff, mgorny, jgravelle-google, aheejin, sunfish
Differential Revision: https://reviews.llvm.org/D41211
Added:
llvm/trunk/lib/Target/WebAssembly/WebAssemblyLowerGlobalDtors.cpp (with props)
llvm/trunk/test/CodeGen/WebAssembly/lower-global-dtors.ll
Modified:
llvm/trunk/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
llvm/trunk/lib/MC/WasmObjectWriter.cpp
llvm/trunk/lib/Target/WebAssembly/CMakeLists.txt
llvm/trunk/lib/Target/WebAssembly/WebAssembly.h
llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
llvm/trunk/test/MC/WebAssembly/init-fini-array.ll
Modified: llvm/trunk/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h?rev=320774&r1=320773&r2=320774&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h (original)
+++ llvm/trunk/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h Thu Dec 14 16:17:10 2017
@@ -182,6 +182,10 @@ public:
const Function &F) const override;
void InitializeWasm();
+ MCSection *getStaticCtorSection(unsigned Priority,
+ const MCSymbol *KeySym) const override;
+ MCSection *getStaticDtorSection(unsigned Priority,
+ const MCSymbol *KeySym) const override;
const MCExpr *lowerRelativeReference(const GlobalValue *LHS,
const GlobalValue *RHS,
Modified: llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp?rev=320774&r1=320773&r2=320774&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp (original)
+++ llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp Thu Dec 14 16:17:10 2017
@@ -1359,6 +1359,18 @@ const MCExpr *TargetLoweringObjectFileWa
void TargetLoweringObjectFileWasm::InitializeWasm() {
StaticCtorSection =
getContext().getWasmSection(".init_array", SectionKind::getData());
- StaticDtorSection =
- getContext().getWasmSection(".fini_array", SectionKind::getData());
+}
+
+MCSection *TargetLoweringObjectFileWasm::getStaticCtorSection(
+ unsigned Priority, const MCSymbol *KeySym) const {
+ return Priority == UINT16_MAX ?
+ StaticCtorSection :
+ getContext().getWasmSection(".init_array." + utostr(Priority),
+ SectionKind::getData());
+}
+
+MCSection *TargetLoweringObjectFileWasm::getStaticDtorSection(
+ unsigned Priority, const MCSymbol *KeySym) const {
+ llvm_unreachable("@llvm.global_dtors should have been lowered already");
+ return nullptr;
}
Modified: llvm/trunk/lib/MC/WasmObjectWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/WasmObjectWriter.cpp?rev=320774&r1=320773&r2=320774&view=diff
==============================================================================
--- llvm/trunk/lib/MC/WasmObjectWriter.cpp (original)
+++ llvm/trunk/lib/MC/WasmObjectWriter.cpp Thu Dec 14 16:17:10 2017
@@ -284,7 +284,8 @@ private:
void writeDataRelocSection();
void writeLinkingMetaDataSection(
ArrayRef<WasmDataSegment> Segments, uint32_t DataSize,
- SmallVector<std::pair<StringRef, uint32_t>, 4> SymbolFlags);
+ const SmallVector<std::pair<StringRef, uint32_t>, 4> &SymbolFlags,
+ const SmallVector<std::pair<uint16_t, uint32_t>, 2> &InitFuncs);
uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry);
void applyRelocations(ArrayRef<WasmRelocationEntry> Relocations,
@@ -366,6 +367,10 @@ void WasmObjectWriter::recordRelocation(
uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
MCContext &Ctx = Asm.getContext();
+ // The .init_array isn't translated as data, so don't do relocations in it.
+ if (FixupSection.getSectionName().startswith(".init_array"))
+ return;
+
if (const MCSymbolRefExpr *RefB = Target.getSymB()) {
assert(RefB->getKind() == MCSymbolRefExpr::VK_None &&
"Should not have constructed this");
@@ -905,7 +910,8 @@ void WasmObjectWriter::writeDataRelocSec
void WasmObjectWriter::writeLinkingMetaDataSection(
ArrayRef<WasmDataSegment> Segments, uint32_t DataSize,
- SmallVector<std::pair<StringRef, uint32_t>, 4> SymbolFlags) {
+ const SmallVector<std::pair<StringRef, uint32_t>, 4> &SymbolFlags,
+ const SmallVector<std::pair<uint16_t, uint32_t>, 2> &InitFuncs) {
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_CUSTOM, "linking");
SectionBookkeeping SubSection;
@@ -937,6 +943,16 @@ void WasmObjectWriter::writeLinkingMetaD
endSection(SubSection);
}
+ if (!InitFuncs.empty()) {
+ startSection(SubSection, wasm::WASM_INIT_FUNCS);
+ encodeULEB128(InitFuncs.size(), getStream());
+ for (auto &StartFunc : InitFuncs) {
+ encodeULEB128(StartFunc.first, getStream()); // priority
+ encodeULEB128(StartFunc.second, getStream()); // function index
+ }
+ endSection(SubSection);
+ }
+
endSection(Section);
}
@@ -977,6 +993,7 @@ void WasmObjectWriter::writeObject(MCAss
SmallVector<WasmImport, 4> Imports;
SmallVector<WasmExport, 4> Exports;
SmallVector<std::pair<StringRef, uint32_t>, 4> SymbolFlags;
+ SmallVector<std::pair<uint16_t, uint32_t>, 2> InitFuncs;
SmallPtrSet<const MCSymbolWasm *, 4> IsAddressTaken;
unsigned NumFuncImports = 0;
SmallVector<WasmDataSegment, 4> DataSegments;
@@ -1132,6 +1149,10 @@ void WasmObjectWriter::writeObject(MCAss
if (!Section.isWasmData())
continue;
+ // .init_array sections are handled specially elsewhere.
+ if (cast<MCSectionWasm>(Sec).getSectionName().startswith(".init_array"))
+ continue;
+
DataSize = alignTo(DataSize, Section.getAlignment());
DataSegments.emplace_back();
WasmDataSegment &Segment = DataSegments.back();
@@ -1291,6 +1312,56 @@ void WasmObjectWriter::writeObject(MCAss
registerFunctionType(*Fixup.Symbol);
}
+ // Translate .init_array section contents into start functions.
+ for (const MCSection &S : Asm) {
+ const auto &WS = static_cast<const MCSectionWasm &>(S);
+ if (WS.getSectionName().startswith(".fini_array"))
+ report_fatal_error(".fini_array sections are unsupported");
+ if (!WS.getSectionName().startswith(".init_array"))
+ continue;
+ if (WS.getFragmentList().empty())
+ continue;
+ if (WS.getFragmentList().size() != 2)
+ report_fatal_error("only one .init_array section fragment supported");
+ const MCFragment &AlignFrag = *WS.begin();
+ if (AlignFrag.getKind() != MCFragment::FT_Align)
+ report_fatal_error(".init_array section should be aligned");
+ if (cast<MCAlignFragment>(AlignFrag).getAlignment() != (is64Bit() ? 8 : 4))
+ report_fatal_error(".init_array section should be aligned for pointers");
+ const MCFragment &Frag = *std::next(WS.begin());
+ if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data)
+ report_fatal_error("only data supported in .init_array section");
+ uint16_t Priority = UINT16_MAX;
+ if (WS.getSectionName().size() != 11) {
+ if (WS.getSectionName()[11] != '.')
+ report_fatal_error(".init_array section priority should start with '.'");
+ if (WS.getSectionName().substr(12).getAsInteger(10, Priority))
+ report_fatal_error("invalid .init_array section priority");
+ }
+ const auto &DataFrag = cast<MCDataFragment>(Frag);
+ const SmallVectorImpl<char> &Contents = DataFrag.getContents();
+ for (const uint8_t *p = (const uint8_t *)Contents.data(),
+ *end = (const uint8_t *)Contents.data() + Contents.size();
+ p != end; ++p) {
+ if (*p != 0)
+ report_fatal_error("non-symbolic data in .init_array section");
+ }
+ for (const MCFixup &Fixup : DataFrag.getFixups()) {
+ assert(Fixup.getKind() == MCFixup::getKindForSize(is64Bit() ? 8 : 4, false));
+ const MCExpr *Expr = Fixup.getValue();
+ auto *Sym = dyn_cast<MCSymbolRefExpr>(Expr);
+ if (!Sym)
+ report_fatal_error("fixups in .init_array should be symbol references");
+ if (Sym->getKind() != MCSymbolRefExpr::VK_WebAssembly_FUNCTION)
+ report_fatal_error("symbols in .init_array should be for functions");
+ auto I = SymbolIndices.find(cast<MCSymbolWasm>(&Sym->getSymbol()));
+ if (I == SymbolIndices.end())
+ report_fatal_error("symbols in .init_array should be defined");
+ uint32_t Index = I->second;
+ InitFuncs.push_back(std::make_pair(Priority, Index));
+ }
+ }
+
// Write out the Wasm header.
writeHeader(Asm);
@@ -1301,14 +1372,14 @@ void WasmObjectWriter::writeObject(MCAss
// Skip the "memory" section; we import the memory instead.
writeGlobalSection();
writeExportSection(Exports);
- // TODO: Start Section
writeElemSection(TableElems);
writeCodeSection(Asm, Layout, Functions);
writeDataSection(DataSegments);
writeNameSection(Functions, Imports, NumFuncImports);
writeCodeRelocSection();
writeDataRelocSection();
- writeLinkingMetaDataSection(DataSegments, DataSize, SymbolFlags);
+ writeLinkingMetaDataSection(DataSegments, DataSize, SymbolFlags,
+ InitFuncs);
// TODO: Translate the .comment section to the output.
// TODO: Translate debug sections to the output.
Modified: llvm/trunk/lib/Target/WebAssembly/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/CMakeLists.txt?rev=320774&r1=320773&r2=320774&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/CMakeLists.txt (original)
+++ llvm/trunk/lib/Target/WebAssembly/CMakeLists.txt Thu Dec 14 16:17:10 2017
@@ -25,6 +25,7 @@ add_llvm_target(WebAssemblyCodeGen
WebAssemblyInstrInfo.cpp
WebAssemblyLowerBrUnless.cpp
WebAssemblyLowerEmscriptenEHSjLj.cpp
+ WebAssemblyLowerGlobalDtors.cpp
WebAssemblyMachineFunctionInfo.cpp
WebAssemblyMCInstLower.cpp
WebAssemblyOptimizeLiveIntervals.cpp
Modified: llvm/trunk/lib/Target/WebAssembly/WebAssembly.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssembly.h?rev=320774&r1=320773&r2=320774&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssembly.h (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssembly.h Thu Dec 14 16:17:10 2017
@@ -28,6 +28,7 @@ class FunctionPass;
// LLVM IR passes.
ModulePass *createWebAssemblyLowerEmscriptenEHSjLj(bool DoEH, bool DoSjLj);
void initializeWebAssemblyLowerEmscriptenEHSjLjPass(PassRegistry &);
+ModulePass *createWebAssemblyLowerGlobalDtors();
ModulePass *createWebAssemblyFixFunctionBitcasts();
FunctionPass *createWebAssemblyOptimizeReturned();
Added: llvm/trunk/lib/Target/WebAssembly/WebAssemblyLowerGlobalDtors.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyLowerGlobalDtors.cpp?rev=320774&view=auto
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyLowerGlobalDtors.cpp (added)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyLowerGlobalDtors.cpp Thu Dec 14 16:17:10 2017
@@ -0,0 +1,191 @@
+//===-- WebAssemblyLowerGlobalDtors.cpp - Lower @llvm.global_dtors --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Lower @llvm.global_dtors.
+///
+/// WebAssembly doesn't have a builtin way to invoke static destructors.
+/// Implement @llvm.global_dtors by creating wrapper functions that are
+/// registered in @llvm.global_ctors and which contain a call to
+/// `__cxa_atexit` to register their destructor functions.
+///
+//===----------------------------------------------------------------------===//
+
+#include "WebAssembly.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
+#include "llvm/Pass.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace llvm;
+
+#define DEBUG_TYPE "wasm-lower-global-dtors"
+
+namespace {
+class LowerGlobalDtors final : public ModulePass {
+ StringRef getPassName() const override {
+ return "WebAssembly Lower @llvm.global_dtors";
+ }
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.setPreservesCFG();
+ ModulePass::getAnalysisUsage(AU);
+ }
+
+ bool runOnModule(Module &M) override;
+
+public:
+ static char ID;
+ LowerGlobalDtors() : ModulePass(ID) {}
+};
+} // End anonymous namespace
+
+char LowerGlobalDtors::ID = 0;
+ModulePass *llvm::createWebAssemblyLowerGlobalDtors() {
+ return new LowerGlobalDtors();
+}
+
+bool LowerGlobalDtors::runOnModule(Module &M) {
+ GlobalVariable *GV = M.getGlobalVariable("llvm.global_dtors");
+ if (!GV)
+ return false;
+
+ const ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer());
+ if (!InitList)
+ return false;
+
+ // Sanity-check @llvm.global_dtor's type.
+ StructType *ETy = dyn_cast<StructType>(InitList->getType()->getElementType());
+ if (!ETy || ETy->getNumElements() != 3 ||
+ !ETy->getTypeAtIndex(0U)->isIntegerTy() ||
+ !ETy->getTypeAtIndex(1U)->isPointerTy() ||
+ !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<uint16_t, MapVector<Constant *, std::vector<Constant *> > > DtorFuncs;
+ for (Value *O : InitList->operands()) {
+ ConstantStruct *CS = dyn_cast<ConstantStruct>(O);
+ if (!CS) continue; // Malformed.
+
+ ConstantInt *Priority = dyn_cast<ConstantInt>(CS->getOperand(0));
+ if (!Priority) continue; // Malformed.
+ uint16_t PriorityValue = Priority->getLimitedValue(UINT16_MAX);
+
+ Constant *DtorFunc = CS->getOperand(1);
+ if (DtorFunc->isNullValue())
+ break; // Found a null terminator, skip the rest.
+
+ Constant *Associated = CS->getOperand(2);
+ Associated = cast<Constant>(Associated->stripPointerCastsNoFollowAliases());
+
+ DtorFuncs[PriorityValue][Associated].push_back(DtorFunc);
+ }
+ if (DtorFuncs.empty())
+ return false;
+
+ // extern "C" int __cxa_atexit(void (*f)(void *), void *p, void *d);
+ LLVMContext &C = M.getContext();
+ PointerType *VoidStar = Type::getInt8PtrTy(C);
+ Type *AtExitFuncArgs[] = { VoidStar };
+ FunctionType *AtExitFuncTy = FunctionType::get(
+ Type::getVoidTy(C),
+ AtExitFuncArgs,
+ /*isVarArg=*/false);
+
+ Type *AtExitArgs[] = {
+ PointerType::get(AtExitFuncTy, 0),
+ VoidStar,
+ VoidStar
+ };
+ FunctionType *AtExitTy = FunctionType::get(
+ Type::getInt32Ty(C),
+ AtExitArgs,
+ /*isVarArg=*/false);
+ Constant *AtExit = M.getOrInsertFunction("__cxa_atexit", AtExitTy);
+
+ // Declare __dso_local.
+ Constant *DsoHandle = M.getNamedValue("__dso_handle");
+ if (!DsoHandle) {
+ Type *DsoHandleTy = Type::getInt8Ty(C);
+ GlobalVariable *Handle =
+ new GlobalVariable(M, DsoHandleTy, /*isConstant=*/true,
+ GlobalVariable::ExternalWeakLinkage,
+ nullptr, "__dso_handle");
+ Handle->setVisibility(GlobalVariable::HiddenVisibility);
+ DsoHandle = Handle;
+ }
+
+ // For each unique priority level and associated symbol, generate a function
+ // to call all the destructors at that level, and a function to register the
+ // first function with __cxa_atexit.
+ for (auto &PriorityAndMore : DtorFuncs) {
+ uint16_t Priority = PriorityAndMore.first;
+ for (auto &AssociatedAndMore : PriorityAndMore.second) {
+ Constant *Associated = AssociatedAndMore.first;
+
+ Function *CallDtors = Function::Create(
+ AtExitFuncTy, Function::PrivateLinkage,
+ "call_dtors" +
+ (Priority != UINT16_MAX ?
+ (Twine(".") + Twine(Priority)) : Twine()) +
+ (!Associated->isNullValue() ?
+ (Twine(".") + Associated->getName()) : Twine()),
+ &M);
+ BasicBlock *BB = BasicBlock::Create(C, "body", CallDtors);
+
+ for (auto Dtor : AssociatedAndMore.second)
+ CallInst::Create(Dtor, "", BB);
+ ReturnInst::Create(C, BB);
+
+ FunctionType *VoidVoid = FunctionType::get(Type::getVoidTy(C),
+ /*isVarArg=*/false);
+ Function *RegisterCallDtors = Function::Create(
+ VoidVoid, Function::PrivateLinkage,
+ "register_call_dtors" +
+ (Priority != UINT16_MAX ?
+ (Twine(".") + Twine(Priority)) : Twine()) +
+ (!Associated->isNullValue() ?
+ (Twine(".") + Associated->getName()) : Twine()),
+ &M);
+ BasicBlock *EntryBB = BasicBlock::Create(C, "entry", RegisterCallDtors);
+ BasicBlock *FailBB = BasicBlock::Create(C, "fail", RegisterCallDtors);
+ BasicBlock *RetBB = BasicBlock::Create(C, "return", RegisterCallDtors);
+
+ Value *Null = ConstantPointerNull::get(VoidStar);
+ Value *Args[] = { CallDtors, Null, DsoHandle };
+ Value *Res = CallInst::Create(AtExit, Args, "call", EntryBB);
+ Value *Cmp = new ICmpInst(*EntryBB, ICmpInst::ICMP_NE, Res,
+ Constant::getNullValue(Res->getType()));
+ BranchInst::Create(FailBB, RetBB, Cmp, EntryBB);
+
+ // If `__cxa_atexit` hits out-of-memory, trap, so that we don't misbehave.
+ // This should be very rare, because if the process is running out of memory
+ // before main has even started, something is wrong.
+ CallInst::Create(Intrinsic::getDeclaration(&M, Intrinsic::trap),
+ "", FailBB);
+ new UnreachableInst(C, FailBB);
+
+ ReturnInst::Create(C, RetBB);
+
+ // Now register the registration function with @llvm.global_ctors.
+ appendToGlobalCtors(M, RegisterCallDtors, Priority, Associated);
+ }
+ }
+
+ // Now that we've lowered everything, remove @llvm.global_dtors.
+ GV->eraseFromParent();
+
+ return true;
+}
Propchange: llvm/trunk/lib/Target/WebAssembly/WebAssemblyLowerGlobalDtors.cpp
------------------------------------------------------------------------------
svn:eol-style = LF
Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp?rev=320774&r1=320773&r2=320774&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp Thu Dec 14 16:17:10 2017
@@ -175,6 +175,9 @@ void WebAssemblyPassConfig::addIRPasses(
// control specifically what gets lowered.
addPass(createAtomicExpandPass());
+ // Lower .llvm.global_dtors into .llvm_global_ctors with __cxa_atexit calls.
+ addPass(createWebAssemblyLowerGlobalDtors());
+
// Fix function bitcasts, as WebAssembly requires caller and callee signatures
// to match.
addPass(createWebAssemblyFixFunctionBitcasts());
Added: llvm/trunk/test/CodeGen/WebAssembly/lower-global-dtors.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/lower-global-dtors.ll?rev=320774&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/lower-global-dtors.ll (added)
+++ llvm/trunk/test/CodeGen/WebAssembly/lower-global-dtors.ll Thu Dec 14 16:17:10 2017
@@ -0,0 +1,139 @@
+; RUN: llc < %s -asm-verbose=false | FileCheck --check-prefix=CHECK --check-prefix=FINI --check-prefix=NULL %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+; Test that @llvm.global_dtors is properly lowered into @llvm.global_ctors,
+; grouping dtor calls by priority and associated symbol.
+
+declare void @orig_ctor()
+declare void @orig_dtor0()
+declare void @orig_dtor1a()
+declare void @orig_dtor1b()
+declare void @orig_dtor1c0()
+declare void @orig_dtor1c1a()
+declare void @orig_dtor1c1b()
+declare void @orig_dtor65536()
+declare void @after_the_null()
+
+ at associated1c0 = external global i8
+ at associated1c1 = external global i8
+
+ at llvm.global_ctors = appending global
+[1 x { i32, void ()*, i8* }]
+[
+ { i32, void ()*, i8* } { i32 200, void ()* @orig_ctor, i8* null }
+]
+
+ at llvm.global_dtors = appending global
+[9 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 65535, void ()* null, i8* null },
+ { i32, void ()*, i8* } { i32 65535, void ()* @after_the_null, i8* null }
+]
+
+; CHECK-LABEL: .Lcall_dtors.0:
+; CHECK-NEXT: .param i32{{$}}
+; CHECK-NEXT: call orig_dtor0 at FUNCTION{{$}}
+
+; CHECK-LABEL: .Lregister_call_dtors.0:
+; CHECK-NEXT: block
+; CHECK-NEXT: i32.const $push2=, .Lcall_dtors.0 at FUNCTION{{$}}
+; CHECK-NEXT: i32.const $push1=, 0
+; CHECK-NEXT: i32.const $push0=, __dso_handle
+; CHECK-NEXT: i32.call $push3=, __cxa_atexit at FUNCTION, $pop2, $pop1, $pop0{{$}}
+; CHECK-NEXT: br_if 0, $pop3
+; CHECK-NEXT: return
+; CHECK: end_block
+; CHECK-NEXT: unreachable
+
+; CHECK-LABEL: .Lcall_dtors.1:
+; CHECK-NEXT: .param i32{{$}}
+; CHECK-NEXT: call orig_dtor1a at FUNCTION{{$}}
+; CHECK-NEXT: call orig_dtor1b at FUNCTION{{$}}
+
+; CHECK-LABEL: .Lregister_call_dtors.1:
+; CHECK-NEXT: block
+; CHECK-NEXT: i32.const $push2=, .Lcall_dtors.1 at FUNCTION{{$}}
+; CHECK-NEXT: i32.const $push1=, 0
+; CHECK-NEXT: i32.const $push0=, __dso_handle
+; CHECK-NEXT: i32.call $push3=, __cxa_atexit at FUNCTION, $pop2, $pop1, $pop0{{$}}
+; CHECK-NEXT: br_if 0, $pop3
+; CHECK-NEXT: return
+; CHECK: end_block
+; CHECK-NEXT: unreachable
+
+; CHECK-LABEL: .Lcall_dtors.1.associated1c0:
+; CHECK-NEXT: .param i32{{$}}
+; CHECK-NEXT: call orig_dtor1c0 at FUNCTION{{$}}
+
+; CHECK-LABEL: .Lregister_call_dtors.1.associated1c0:
+; CHECK-NEXT: block
+; CHECK-NEXT: i32.const $push2=, .Lcall_dtors.1.associated1c0 at FUNCTION{{$}}
+; CHECK-NEXT: i32.const $push1=, 0
+; CHECK-NEXT: i32.const $push0=, __dso_handle
+; CHECK-NEXT: i32.call $push3=, __cxa_atexit at FUNCTION, $pop2, $pop1, $pop0{{$}}
+; CHECK-NEXT: br_if 0, $pop3
+; CHECK-NEXT: return
+; CHECK: end_block
+; CHECK-NEXT: unreachable
+
+; CHECK-LABEL: .Lcall_dtors.1.associated1c1:
+; CHECK-NEXT: .param i32{{$}}
+; CHECK-NEXT: call orig_dtor1c1a at FUNCTION{{$}}
+; CHECK-NEXT: call orig_dtor1c1b at FUNCTION{{$}}
+
+; CHECK-LABEL: .Lregister_call_dtors.1.associated1c1:
+; CHECK-NEXT: block
+; CHECK-NEXT: i32.const $push2=, .Lcall_dtors.1.associated1c1 at FUNCTION{{$}}
+; CHECK-NEXT: i32.const $push1=, 0
+; CHECK-NEXT: i32.const $push0=, __dso_handle
+; CHECK-NEXT: i32.call $push3=, __cxa_atexit at FUNCTION, $pop2, $pop1, $pop0{{$}}
+; CHECK-NEXT: br_if 0, $pop3
+; CHECK-NEXT: return
+; CHECK: end_block
+; CHECK-NEXT: unreachable
+
+; CHECK-LABEL: .Lcall_dtors:
+; CHECK-NEXT: .param i32{{$}}
+; CHECK-NEXT: call orig_dtor65536 at FUNCTION{{$}}
+
+; CHECK-LABEL: .Lregister_call_dtors:
+; CHECK-NEXT: block
+; CHECK-NEXT: i32.const $push2=, .Lcall_dtors at FUNCTION{{$}}
+; CHECK-NEXT: i32.const $push1=, 0
+; CHECK-NEXT: i32.const $push0=, __dso_handle
+; CHECK-NEXT: i32.call $push3=, __cxa_atexit at FUNCTION, $pop2, $pop1, $pop0{{$}}
+; CHECK-NEXT: br_if 0, $pop3
+; CHECK-NEXT: return
+; CHECK: end_block
+; CHECK-NEXT: unreachable
+
+; CHECK-LABEL: .section .init_array.0,"",@
+; CHECK: .int32 .Lregister_call_dtors.0 at FUNCTION{{$}}
+; CHECK-LABEL: .section .init_array.1,"",@
+; CHECK: .int32 .Lregister_call_dtors.1 at FUNCTION{{$}}
+; CHECK-LABEL: .section .init_array.200,"",@
+; CHECK: .int32 orig_ctor at FUNCTION{{$}}
+; CHECK-LABEL: .section .init_array,"",@
+; CHECK: .int32 .Lregister_call_dtors at FUNCTION{{$}}
+
+; CHECK-LABEL: .weak __dso_handle
+
+; CHECK-LABEL: .functype __cxa_atexit, i32, i32, i32, i32{{$}}
+
+; We shouldn't make use of a .fini_array section.
+
+; FINI-NOT: fini_array
+
+; This function is listed after the null terminator, so it should
+; be excluded.
+
+; NULL-NOT: after_the_null
Modified: llvm/trunk/test/MC/WebAssembly/init-fini-array.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/WebAssembly/init-fini-array.ll?rev=320774&r1=320773&r2=320774&view=diff
==============================================================================
--- llvm/trunk/test/MC/WebAssembly/init-fini-array.ll (original)
+++ llvm/trunk/test/MC/WebAssembly/init-fini-array.ll Thu Dec 14 16:17:10 2017
@@ -2,13 +2,14 @@
@global1 = global i32 1025, align 8
+declare void @func0()
declare void @func1()
-
declare void @func2()
+declare void @func3()
- at llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @func1, i8* null }]
+ at llvm.global_ctors = appending global [2 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @func0, i8* null }, { i32, void ()*, i8* } { i32 42, void ()* @func1, i8* null }]
- at llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @func2, i8* null }]
+ at llvm.global_dtors = appending global [2 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @func2, i8* null }, { i32, void ()*, i8* } { i32 42, void ()* @func3, i8* null }]
; CHECK: - Type: IMPORT
@@ -16,23 +17,42 @@ declare void @func2()
; CHECK-NEXT: - Module: env
; CHECK-NEXT: Field: __linear_memory
; CHECK-NEXT: Kind: MEMORY
-; CHECK-NEXT: Memory:
+; CHECK-NEXT: Memory:
; CHECK-NEXT: Initial: 0x00000001
; CHECK-NEXT: - Module: env
; CHECK-NEXT: Field: __indirect_function_table
; CHECK-NEXT: Kind: TABLE
-; CHECK-NEXT: Table:
+; CHECK-NEXT: Table:
; CHECK-NEXT: ElemType: ANYFUNC
-; CHECK-NEXT: Limits:
+; CHECK-NEXT: Limits:
; CHECK-NEXT: Initial: 0x00000002
; CHECK-NEXT: - Module: env
-; CHECK-NEXT: Field: func1
+; CHECK-NEXT: Field: func3
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: SigIndex: 1
+; CHECK-NEXT: - Module: env
+; CHECK-NEXT: Field: __dso_handle
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: GlobalType: I32
+; CHECK-NEXT: GlobalMutable: false
+; CHECK-NEXT: - Module: env
+; CHECK-NEXT: Field: __cxa_atexit
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: SigIndex: 0
+; CHECK-NEXT: SigIndex: 2
; CHECK-NEXT: - Module: env
; CHECK-NEXT: Field: func2
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: SigIndex: 0
+; CHECK-NEXT: SigIndex: 1
+; CHECK-NEXT: - Module: env
+; CHECK-NEXT: Field: func1
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: SigIndex: 1
+; CHECK-NEXT: - Module: env
+; CHECK-NEXT: Field: func0
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: SigIndex: 1
+; CHECK-NEXT: - Type: FUNCTION
+; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 1 ]
; CHECK-NEXT: - Type: GLOBAL
; CHECK-NEXT: Globals:
; CHECK-NEXT: - Type: I32
@@ -42,23 +62,63 @@ declare void @func2()
; CHECK-NEXT: Value: 0
; CHECK-NEXT: - Type: EXPORT
; CHECK-NEXT: Exports:
+; CHECK-NEXT: - Name: .Lcall_dtors.42
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 5
+; CHECK-NEXT: - Name: .Lregister_call_dtors.42
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 6
+; CHECK-NEXT: - Name: .Lcall_dtors
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 7
+; CHECK-NEXT: - Name: .Lregister_call_dtors
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 8
; CHECK-NEXT: - Name: global1
; CHECK-NEXT: Kind: GLOBAL
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: - Type: ELEM
; CHECK-NEXT: Segments:
; CHECK-NEXT: - Offset:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 0
-; CHECK-NEXT: Functions: [ 0, 1 ]
-; CHECK-NEXT: - Type: DATA
+; CHECK-NEXT: Functions: [ 5, 7 ]
+; CHECK-NEXT: - Type: CODE
; CHECK-NEXT: Relocations:
-; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32
+; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB
+; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Offset: 0x00000004
+; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB
; CHECK-NEXT: Index: 0
; CHECK-NEXT: Offset: 0x0000000F
-; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32
+; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB
+; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Offset: 0x00000017
+; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: Offset: 0x0000001D
+; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB
+; CHECK-NEXT: Index: 2
+; CHECK-NEXT: Offset: 0x0000002C
+; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB
; CHECK-NEXT: Index: 1
-; CHECK-NEXT: Offset: 0x00000018
+; CHECK-NEXT: Offset: 0x00000037
+; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB
+; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Offset: 0x0000003F
+; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: Offset: 0x00000045
+; CHECK-NEXT: Functions:
+; CHECK-NEXT: - Locals:
+; CHECK-NEXT: Body: 1080808080000B
+; CHECK-NEXT: - Locals:
+; CHECK-NEXT: Body: 0240418080808000410041FFFFFFFF7F1081808080000D000F0B00000B
+; CHECK-NEXT: - Locals:
+; CHECK-NEXT: Body: 1082808080000B
+; CHECK-NEXT: - Locals:
+; CHECK-NEXT: Body: 0240418180808000410041FFFFFFFF7F1081808080000D000F0B00000B
+; CHECK-NEXT: - Type: DATA
; CHECK-NEXT: Segments:
; CHECK-NEXT: - SectionOffset: 6
; CHECK-NEXT: MemoryIndex: 0
@@ -66,40 +126,53 @@ declare void @func2()
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 0
; CHECK-NEXT: Content: '01040000'
-; CHECK-NEXT: - SectionOffset: 15
-; CHECK-NEXT: MemoryIndex: 0
-; CHECK-NEXT: Offset:
-; CHECK-NEXT: Opcode: I32_CONST
-; CHECK-NEXT: Value: 4
-; CHECK-NEXT: Content: '00000000'
-; CHECK-NEXT: - SectionOffset: 24
-; CHECK-NEXT: MemoryIndex: 0
-; CHECK-NEXT: Offset:
-; CHECK-NEXT: Opcode: I32_CONST
-; CHECK-NEXT: Value: 8
-; CHECK-NEXT: Content: '01000000'
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: name
; CHECK-NEXT: FunctionNames:
; CHECK-NEXT: - Index: 0
-; CHECK-NEXT: Name: func1
+; CHECK-NEXT: Name: func3
; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Name: __cxa_atexit
+; CHECK-NEXT: - Index: 2
; CHECK-NEXT: Name: func2
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Name: func1
+; CHECK-NEXT: - Index: 4
+; CHECK-NEXT: Name: func0
+; CHECK-NEXT: - Index: 5
+; CHECK-NEXT: Name: .Lcall_dtors.42
+; CHECK-NEXT: - Index: 6
+; CHECK-NEXT: Name: .Lregister_call_dtors.42
+; CHECK-NEXT: - Index: 7
+; CHECK-NEXT: Name: .Lcall_dtors
+; CHECK-NEXT: - Index: 8
+; CHECK-NEXT: Name: .Lregister_call_dtors
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: linking
-; CHECK-NEXT: DataSize: 12
-; CHECK-NEXT: SegmentInfo:
+; CHECK-NEXT: DataSize: 4
+; CHECK-NEXT: SymbolInfo:
+; CHECK-NEXT: - Name: __dso_handle
+; CHECK-NEXT: Flags: [ BINDING_WEAK, VISIBILITY_HIDDEN ]
+; CHECK-NEXT: - Name: .Lcall_dtors.42
+; CHECK-NEXT: Flags: [ BINDING_LOCAL ]
+; CHECK-NEXT: - Name: .Lregister_call_dtors.42
+; CHECK-NEXT: Flags: [ BINDING_LOCAL ]
+; CHECK-NEXT: - Name: .Lcall_dtors
+; CHECK-NEXT: Flags: [ BINDING_LOCAL ]
+; CHECK-NEXT: - Name: .Lregister_call_dtors
+; CHECK-NEXT: Flags: [ BINDING_LOCAL ]
+; CHECK-NEXT: SegmentInfo:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: Name: .data.global1
; CHECK-NEXT: Alignment: 8
; CHECK-NEXT: Flags: [ ]
-; CHECK-NEXT: - Index: 1
-; CHECK-NEXT: Name: .init_array
-; CHECK-NEXT: Alignment: 4
-; CHECK-NEXT: Flags: [ ]
-; CHECK-NEXT: - Index: 2
-; CHECK-NEXT: Name: .fini_array
-; CHECK-NEXT: Alignment: 4
-; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: InitFunctions:
+; CHECK-NEXT: - Priority: 42
+; CHECK-NEXT: FunctionIndex: 3
+; CHECK-NEXT: - Priority: 42
+; CHECK-NEXT: FunctionIndex: 6
+; CHECK-NEXT: - Priority: 65535
+; CHECK-NEXT: FunctionIndex: 4
+; CHECK-NEXT: - Priority: 65535
+; CHECK-NEXT: FunctionIndex: 8
; CHECK-NEXT: ...
-
More information about the llvm-commits
mailing list