Index: include/llvm/CodeGen/TargetLoweringObjectFileImpl.h =================================================================== --- include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ include/llvm/CodeGen/TargetLoweringObjectFileImpl.h @@ -171,6 +171,28 @@ const GlobalValue *GV) const override; }; +class TargetLoweringObjectFileWasm : public TargetLoweringObjectFile { +public: + TargetLoweringObjectFileWasm() {} + + ~TargetLoweringObjectFileWasm() override {} + + MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind, + const TargetMachine &TM) const override; + + MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind, + const TargetMachine &TM) const override; + + bool shouldPutJumpTableInFunctionSection(bool UsesLabelDifference, + const Function &F) const override; + + void InitializeWasm(); + + const MCExpr *lowerRelativeReference(const GlobalValue *LHS, + const GlobalValue *RHS, + const TargetMachine &TM) const override; +}; + void emitLinkerFlagsForGlobalCOFF(raw_ostream &OS, const GlobalValue *GV, const Triple &TT, Mangler &Mangler); Index: include/llvm/MC/MCContext.h =================================================================== --- include/llvm/MC/MCContext.h +++ include/llvm/MC/MCContext.h @@ -33,6 +33,7 @@ class MCSection; class MCSymbol; class MCSymbolELF; + class MCSymbolWasm; class MCLabel; struct MCDwarfFile; class MCDwarfLoc; @@ -43,6 +44,7 @@ class MCSectionMachO; class MCSectionELF; class MCSectionCOFF; + class MCSectionWasm; class CodeViewContext; /// Context object for machine code objects. This class owns all of the @@ -82,6 +84,7 @@ SpecificBumpPtrAllocator COFFAllocator; SpecificBumpPtrAllocator ELFAllocator; SpecificBumpPtrAllocator MachOAllocator; + SpecificBumpPtrAllocator WasmAllocator; /// Bindings of names to symbols. SymbolTable Symbols; @@ -211,10 +214,28 @@ } }; + struct WasmSectionKey { + std::string SectionName; + StringRef GroupName; + unsigned UniqueID; + WasmSectionKey(StringRef SectionName, StringRef GroupName, + unsigned UniqueID) + : SectionName(SectionName), GroupName(GroupName), UniqueID(UniqueID) { + } + bool operator<(const WasmSectionKey &Other) const { + if (SectionName != Other.SectionName) + return SectionName < Other.SectionName; + if (GroupName != Other.GroupName) + return GroupName < Other.GroupName; + return UniqueID < Other.UniqueID; + } + }; + StringMap MachOUniquingMap; std::map ELFUniquingMap; std::map COFFUniquingMap; - StringMap ELFRelSecNames; + std::map WasmUniquingMap; + StringMap RelSecNames; SpecificBumpPtrAllocator MCSubtargetAllocator; @@ -409,6 +430,54 @@ getAssociativeCOFFSection(MCSectionCOFF *Sec, const MCSymbol *KeySym, unsigned UniqueID = GenericSectionID); + MCSectionWasm *getWasmSection(const Twine &Section, unsigned Type, + unsigned Flags) { + return getWasmSection(Section, Type, Flags, nullptr); + } + + MCSectionWasm *getWasmSection(const Twine &Section, unsigned Type, + unsigned Flags, const char *BeginSymName) { + return getWasmSection(Section, Type, Flags, "", BeginSymName); + } + + MCSectionWasm *getWasmSection(const Twine &Section, unsigned Type, + unsigned Flags, const Twine &Group) { + return getWasmSection(Section, Type, Flags, Group, nullptr); + } + + MCSectionWasm *getWasmSection(const Twine &Section, unsigned Type, + unsigned Flags, const Twine &Group, + const char *BeginSymName) { + return getWasmSection(Section, Type, Flags, Group, ~0, BeginSymName); + } + + MCSectionWasm *getWasmSection(const Twine &Section, unsigned Type, + unsigned Flags, const Twine &Group, + unsigned UniqueID) { + return getWasmSection(Section, Type, Flags, Group, UniqueID, nullptr); + } + + MCSectionWasm *getWasmSection(const Twine &Section, unsigned Type, + unsigned Flags, const Twine &Group, + unsigned UniqueID, const char *BeginSymName); + + MCSectionWasm *getWasmSection(const Twine &Section, unsigned Type, + unsigned Flags, const MCSymbolWasm *Group, + unsigned UniqueID, const char *BeginSymName); + + /// Get a section with the provided group identifier. This section is + /// named by concatenating \p Prefix with '.' then \p Suffix. The \p Type + /// describes the type of the section and \p Flags are used to further + /// configure this named section. + MCSectionWasm *getWasmNamedSection(const Twine &Prefix, const Twine &Suffix, + unsigned Type, unsigned Flags); + + MCSectionWasm *createWasmRelSection(const Twine &Name, unsigned Type, + unsigned Flags, + const MCSymbolWasm *Group); + + void renameWasmSection(MCSectionWasm *Section, StringRef Name); + // Create and save a copy of STI and return a reference to the copy. MCSubtargetInfo &getSubtargetCopy(const MCSubtargetInfo &STI); Index: include/llvm/MC/MCObjectFileInfo.h =================================================================== --- include/llvm/MC/MCObjectFileInfo.h +++ include/llvm/MC/MCObjectFileInfo.h @@ -129,7 +129,7 @@ /// it'll go here. MCSection *TLSExtraDataSection; - /// Section directive for Thread Local data. ELF, MachO and COFF. + /// Section directive for Thread Local data. ELF, MachO, COFF, and Wasm. MCSection *TLSDataSection; // Defaults to ".tdata". /// Section directive for Thread Local uninitialized data. @@ -338,7 +338,7 @@ return EHFrameSection; } - enum Environment { IsMachO, IsELF, IsCOFF }; + enum Environment { IsMachO, IsELF, IsCOFF, IsWasm }; Environment getObjectFileType() const { return Env; } bool isPositionIndependent() const { return PositionIndependent; } @@ -353,6 +353,7 @@ void initMachOMCObjectFileInfo(const Triple &T); void initELFMCObjectFileInfo(const Triple &T); void initCOFFMCObjectFileInfo(const Triple &T); + void initWasmMCObjectFileInfo(const Triple &T); public: const Triple &getTargetTriple() const { return TT; } Index: include/llvm/MC/MCSection.h =================================================================== --- include/llvm/MC/MCSection.h +++ include/llvm/MC/MCSection.h @@ -38,7 +38,7 @@ /// current translation unit. The MCContext class uniques and creates these. class MCSection { public: - enum SectionVariant { SV_COFF = 0, SV_ELF, SV_MachO }; + enum SectionVariant { SV_COFF = 0, SV_ELF, SV_MachO, SV_Wasm }; /// \brief Express the state of bundle locked groups while emitting code. enum BundleLockStateType { Index: include/llvm/MC/MCStreamer.h =================================================================== --- include/llvm/MC/MCStreamer.h +++ include/llvm/MC/MCStreamer.h @@ -44,6 +44,7 @@ class MCSection; class MCStreamer; class MCSymbolRefExpr; +class MCSymbolWasm; class MCSubtargetInfo; class raw_ostream; class Twine; Index: include/llvm/MC/MCSymbol.h =================================================================== --- include/llvm/MC/MCSymbol.h +++ include/llvm/MC/MCSymbol.h @@ -48,6 +48,7 @@ SymbolKindCOFF, SymbolKindELF, SymbolKindMachO, + SymbolKindWasm, }; /// A symbol can contain an Offset, or Value, or be Common, but never more @@ -100,7 +101,7 @@ /// LLVM RTTI discriminator. This is actually a SymbolKind enumerator, but is /// unsigned to avoid sign extension and achieve better bitpacking with MSVC. - unsigned Kind : 2; + unsigned Kind : 3; /// True if we have created a relocation that uses this symbol. mutable unsigned IsUsedInReloc : 1; @@ -284,6 +285,8 @@ bool isMachO() const { return Kind == SymbolKindMachO; } + bool isWasm() const { return Kind == SymbolKindWasm; } + /// @} /// \name Variable Symbols /// @{ Index: include/llvm/Support/TargetRegistry.h =================================================================== --- include/llvm/Support/TargetRegistry.h +++ include/llvm/Support/TargetRegistry.h @@ -68,6 +68,9 @@ raw_pwrite_stream &OS, MCCodeEmitter *CE, bool RelaxAll, bool DWARFMustBeAtTheEnd, bool LabelSections = false); +MCStreamer *createWasmStreamer(MCContext &Ctx, MCAsmBackend &TAB, + raw_pwrite_stream &OS, MCCodeEmitter *CE, + bool RelaxAll); MCRelocationInfo *createMCRelocationInfo(const Triple &TT, MCContext &Ctx); @@ -143,6 +146,11 @@ MCCodeEmitter *Emitter, bool RelaxAll, bool IncrementalLinkerCompatible); + typedef MCStreamer *(*WasmStreamerCtorTy)(const Triple &T, MCContext &Ctx, + MCAsmBackend &TAB, + raw_pwrite_stream &OS, + MCCodeEmitter *Emitter, + bool RelaxAll); typedef MCTargetStreamer *(*NullTargetStreamerCtorTy)(MCStreamer &S); typedef MCTargetStreamer *(*AsmTargetStreamerCtorTy)( MCStreamer &S, formatted_raw_ostream &OS, MCInstPrinter *InstPrint, @@ -227,6 +235,7 @@ COFFStreamerCtorTy COFFStreamerCtorFn; MachOStreamerCtorTy MachOStreamerCtorFn; ELFStreamerCtorTy ELFStreamerCtorFn; + WasmStreamerCtorTy WasmStreamerCtorFn; /// Construction function for this target's null TargetStreamer, if /// registered (default = nullptr). @@ -251,7 +260,8 @@ public: Target() : COFFStreamerCtorFn(nullptr), MachOStreamerCtorFn(nullptr), - ELFStreamerCtorFn(nullptr), NullTargetStreamerCtorFn(nullptr), + ELFStreamerCtorFn(nullptr), WasmStreamerCtorFn(nullptr), + NullTargetStreamerCtorFn(nullptr), AsmTargetStreamerCtorFn(nullptr), ObjectTargetStreamerCtorFn(nullptr), MCRelocationInfoCtorFn(nullptr), MCSymbolizerCtorFn(nullptr) {} @@ -461,6 +471,12 @@ else S = createELFStreamer(Ctx, TAB, OS, Emitter, RelaxAll); break; + case Triple::Wasm: + if (WasmStreamerCtorFn) + S = WasmStreamerCtorFn(T, Ctx, TAB, OS, Emitter, RelaxAll); + else + S = createWasmStreamer(Ctx, TAB, OS, Emitter, RelaxAll); + break; } if (ObjectTargetStreamerCtorFn) ObjectTargetStreamerCtorFn(*S, STI); @@ -800,6 +816,10 @@ T.ELFStreamerCtorFn = Fn; } + static void RegisterWasmStreamer(Target &T, Target::WasmStreamerCtorTy Fn) { + T.WasmStreamerCtorFn = Fn; + } + static void RegisterNullTargetStreamer(Target &T, Target::NullTargetStreamerCtorTy Fn) { T.NullTargetStreamerCtorFn = Fn; Index: lib/CodeGen/TargetLoweringObjectFileImpl.cpp =================================================================== --- lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -30,8 +30,10 @@ #include "llvm/MC/MCSectionCOFF.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCSectionWasm.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbolELF.h" +#include "llvm/MC/MCSymbolWasm.h" #include "llvm/MC/MCValue.h" #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/COFF.h" @@ -1155,3 +1157,53 @@ raw_ostream &OS, const GlobalValue *GV) const { emitLinkerFlagsForGlobalCOFF(OS, GV, getTargetTriple(), getMangler()); } + +//===----------------------------------------------------------------------===// +// Wasm +//===----------------------------------------------------------------------===// + +MCSection *TargetLoweringObjectFileWasm::getExplicitSectionGlobal( + const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { + llvm_unreachable("getExplicitSectionGlobal not yet implemented"); + return nullptr; +} + +MCSection *TargetLoweringObjectFileWasm::SelectSectionForGlobal( + const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { + if (Kind.isText()) + return TextSection; + assert(!Kind.isMetadata() && "metadata sections not yet implemented"); + return DataSection; +} + +bool TargetLoweringObjectFileWasm::shouldPutJumpTableInFunctionSection( + bool UsesLabelDifference, const Function &F) const { + // We can always create relative relocations, so use another section + // that can be marked non-executable. + return false; +} + +const MCExpr *TargetLoweringObjectFileWasm::lowerRelativeReference( + const GlobalValue *LHS, const GlobalValue *RHS, + const TargetMachine &TM) const { + // We may only use a PLT-relative relocation to refer to unnamed_addr + // functions. + if (!LHS->hasGlobalUnnamedAddr() || !LHS->getValueType()->isFunctionTy()) + return nullptr; + + // Basic sanity checks. + if (LHS->getType()->getPointerAddressSpace() != 0 || + RHS->getType()->getPointerAddressSpace() != 0 || LHS->isThreadLocal() || + RHS->isThreadLocal()) + return nullptr; + + return MCBinaryExpr::createSub( + MCSymbolRefExpr::create(TM.getSymbol(LHS), MCSymbolRefExpr::VK_None, + getContext()), + MCSymbolRefExpr::create(TM.getSymbol(RHS), getContext()), getContext()); +} + +void +TargetLoweringObjectFileWasm::InitializeWasm() { + // TODO: Initialize StaticCtorSection and StaticDtorSection. +} Index: lib/MC/CMakeLists.txt =================================================================== --- lib/MC/CMakeLists.txt +++ lib/MC/CMakeLists.txt @@ -6,6 +6,7 @@ MCAsmInfoCOFF.cpp MCAsmInfoDarwin.cpp MCAsmInfoELF.cpp + MCAsmInfoWasm.cpp MCAsmStreamer.cpp MCAssembler.cpp MCCodeEmitter.cpp @@ -34,17 +35,21 @@ MCSectionCOFF.cpp MCSectionELF.cpp MCSectionMachO.cpp + MCSectionWasm.cpp MCStreamer.cpp MCSubtargetInfo.cpp MCSymbol.cpp MCSymbolELF.cpp MCTargetOptions.cpp MCValue.cpp + MCWasmObjectTargetWriter.cpp + MCWasmStreamer.cpp MCWin64EH.cpp MCWinEH.cpp MachObjectWriter.cpp StringTableBuilder.cpp SubtargetFeature.cpp + WasmObjectWriter.cpp WinCOFFObjectWriter.cpp WinCOFFStreamer.cpp Index: lib/MC/MCContext.cpp =================================================================== --- lib/MC/MCContext.cpp +++ lib/MC/MCContext.cpp @@ -20,10 +20,12 @@ #include "llvm/MC/MCSectionCOFF.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCSectionWasm.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbolCOFF.h" #include "llvm/MC/MCSymbolELF.h" #include "llvm/MC/MCSymbolMachO.h" +#include "llvm/MC/MCSymbolWasm.h" #include "llvm/Support/COFF.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ELF.h" @@ -149,6 +151,8 @@ return new (Name, *this) MCSymbolELF(Name, IsTemporary); case MCObjectFileInfo::IsMachO: return new (Name, *this) MCSymbolMachO(Name, IsTemporary); + case MCObjectFileInfo::IsWasm: + return new (Name, *this) MCSymbolWasm(Name, IsTemporary); } } return new (Name, *this) MCSymbol(MCSymbol::SymbolKindUnset, Name, @@ -342,7 +346,7 @@ StringMap::iterator I; bool Inserted; std::tie(I, Inserted) = - ELFRelSecNames.insert(std::make_pair(Name.str(), true)); + RelSecNames.insert(std::make_pair(Name.str(), true)); return createELFSectionImpl(I->getKey(), Type, Flags, SectionKind::getReadOnly(), EntrySize, Group, @@ -474,6 +478,80 @@ "", 0, UniqueID); } +void MCContext::renameWasmSection(MCSectionWasm *Section, StringRef Name) { + StringRef GroupName; + assert(!Section->getGroup() && "not yet implemented"); + + unsigned UniqueID = Section->getUniqueID(); + WasmUniquingMap.erase( + WasmSectionKey{Section->getSectionName(), GroupName, UniqueID}); + auto I = WasmUniquingMap.insert(std::make_pair( + WasmSectionKey{Name, GroupName, UniqueID}, + Section)) + .first; + StringRef CachedName = I->first.SectionName; + const_cast(Section)->setSectionName(CachedName); +} + +MCSectionWasm *MCContext::createWasmRelSection(const Twine &Name, unsigned Type, + unsigned Flags, + const MCSymbolWasm *Group) { + StringMap::iterator I; + bool Inserted; + std::tie(I, Inserted) = + RelSecNames.insert(std::make_pair(Name.str(), true)); + + return new (WasmAllocator.Allocate()) + MCSectionWasm(I->getKey(), Type, Flags, SectionKind::getReadOnly(), + Group, ~0, nullptr); +} + +MCSectionWasm *MCContext::getWasmNamedSection(const Twine &Prefix, + const Twine &Suffix, unsigned Type, + unsigned Flags) { + return getWasmSection(Prefix + "." + Suffix, Type, Flags, Suffix); +} + +MCSectionWasm *MCContext::getWasmSection(const Twine &Section, unsigned Type, + unsigned Flags, + const Twine &Group, unsigned UniqueID, + const char *BeginSymName) { + MCSymbolWasm *GroupSym = nullptr; + if (!Group.isTriviallyEmpty() && !Group.str().empty()) + GroupSym = cast(getOrCreateSymbol(Group)); + + return getWasmSection(Section, Type, Flags, GroupSym, UniqueID, BeginSymName); +} + +MCSectionWasm *MCContext::getWasmSection(const Twine &Section, unsigned Type, + unsigned Flags, + const MCSymbolWasm *GroupSym, + unsigned UniqueID, + const char *BeginSymName) { + StringRef Group = ""; + if (GroupSym) + Group = GroupSym->getName(); + // Do the lookup, if we have a hit, return it. + auto IterBool = WasmUniquingMap.insert( + std::make_pair(WasmSectionKey{Section.str(), Group, UniqueID}, nullptr)); + auto &Entry = *IterBool.first; + if (!IterBool.second) + return Entry.second; + + StringRef CachedName = Entry.first.SectionName; + + SectionKind Kind = SectionKind::getText(); + + MCSymbol *Begin = nullptr; + if (BeginSymName) + Begin = createTempSymbol(BeginSymName, false); + + MCSectionWasm *Result = new (WasmAllocator.Allocate()) + MCSectionWasm(CachedName, Type, Flags, Kind, GroupSym, UniqueID, Begin); + Entry.second = Result; + return Result; +} + MCSubtargetInfo &MCContext::getSubtargetCopy(const MCSubtargetInfo &STI) { return *new (MCSubtargetAllocator.Allocate()) MCSubtargetInfo(STI); } Index: lib/MC/MCObjectFileInfo.cpp =================================================================== --- lib/MC/MCObjectFileInfo.cpp +++ lib/MC/MCObjectFileInfo.cpp @@ -16,6 +16,7 @@ #include "llvm/MC/MCSectionCOFF.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCSectionWasm.h" #include "llvm/Support/COFF.h" using namespace llvm; @@ -797,6 +798,30 @@ SectionKind::getReadOnly()); } +void MCObjectFileInfo::initWasmMCObjectFileInfo(const Triple &T) { + // TODO: Set the section types and flags. + TextSection = Ctx->getWasmSection("", 0, 0); + DataSection = Ctx->getWasmSection("", 0, 0); + + // TODO: Set the section types and flags. + DwarfLineSection = Ctx->getWasmSection(".debug_line", 0, 0); + DwarfStrSection = Ctx->getWasmSection(".debug_str", 0, 0); + DwarfLocSection = Ctx->getWasmSection(".debug_loc", 0, 0); + DwarfAbbrevSection = Ctx->getWasmSection(".debug_abbrev", 0, 0, "section_abbrev"); + DwarfARangesSection = Ctx->getWasmSection(".debug_aranges", 0, 0); + DwarfRangesSection = Ctx->getWasmSection(".debug_ranges", 0, 0, "debug_range"); + DwarfMacinfoSection = Ctx->getWasmSection(".debug_macinfo", 0, 0, "debug_macinfo"); + DwarfAddrSection = Ctx->getWasmSection(".debug_addr", 0, 0); + DwarfCUIndexSection = Ctx->getWasmSection(".debug_cu_index", 0, 0); + DwarfTUIndexSection = Ctx->getWasmSection(".debug_tu_index", 0, 0); + DwarfInfoSection = Ctx->getWasmSection(".debug_info", 0, 0, "section_info"); + DwarfFrameSection = Ctx->getWasmSection(".debug_frame", 0, 0); + DwarfPubNamesSection = Ctx->getWasmSection(".debug_pubnames", 0, 0); + DwarfPubTypesSection = Ctx->getWasmSection(".debug_pubtypes", 0, 0); + + // TODO: Define more sections. +} + void MCObjectFileInfo::InitMCObjectFileInfo(const Triple &TheTriple, bool PIC, CodeModel::Model cm, MCContext &ctx) { @@ -842,7 +867,8 @@ initELFMCObjectFileInfo(TT); break; case Triple::Wasm: - report_fatal_error("Cannot initialize MC for wasm object file format yet."); + Env = IsWasm; + initWasmMCObjectFileInfo(TT); break; case Triple::UnknownObjectFormat: report_fatal_error("Cannot initialize MC for unknown object file format."); Index: lib/MC/MCParser/AsmParser.cpp =================================================================== --- lib/MC/MCParser/AsmParser.cpp +++ lib/MC/MCParser/AsmParser.cpp @@ -597,6 +597,9 @@ case MCObjectFileInfo::IsELF: PlatformParser.reset(createELFAsmParser()); break; + case MCObjectFileInfo::IsWasm: + llvm_unreachable("Wasm parsing not supported yet"); + break; } PlatformParser->Initialize(*this); Index: lib/Target/ARM/AsmParser/ARMAsmParser.cpp =================================================================== --- lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -5484,7 +5484,8 @@ enum { COFF = (1 << MCObjectFileInfo::IsCOFF), ELF = (1 << MCObjectFileInfo::IsELF), - MACHO = (1 << MCObjectFileInfo::IsMachO) + MACHO = (1 << MCObjectFileInfo::IsMachO), + WASM = (1 << MCObjectFileInfo::IsWasm), }; static const struct PrefixEntry { const char *Spelling; @@ -5518,6 +5519,9 @@ case MCObjectFileInfo::IsCOFF: CurrentFormat = COFF; break; + case MCObjectFileInfo::IsWasm: + CurrentFormat = WASM; + break; } if (~Prefix->SupportedFormats & CurrentFormat) { Index: lib/Target/WebAssembly/MCTargetDesc/CMakeLists.txt =================================================================== --- lib/Target/WebAssembly/MCTargetDesc/CMakeLists.txt +++ lib/Target/WebAssembly/MCTargetDesc/CMakeLists.txt @@ -5,4 +5,5 @@ WebAssemblyMCCodeEmitter.cpp WebAssemblyMCTargetDesc.cpp WebAssemblyTargetStreamer.cpp + WebAssemblyWasmObjectWriter.cpp ) Index: lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp =================================================================== --- lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp +++ lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp @@ -17,6 +17,7 @@ #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCWasmObjectWriter.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCFixupKindInfo.h" #include "llvm/MC/MCObjectWriter.h" @@ -27,6 +28,40 @@ using namespace llvm; namespace { +class WebAssemblyAsmBackendELF final : public MCAsmBackend { + bool Is64Bit; + +public: + explicit WebAssemblyAsmBackendELF(bool Is64Bit) + : MCAsmBackend(), Is64Bit(Is64Bit) {} + ~WebAssemblyAsmBackendELF() override {} + + void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, + uint64_t Value, bool IsPCRel) const override; + + MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override; + + // No instruction requires relaxation + bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, + const MCRelaxableFragment *DF, + const MCAsmLayout &Layout) const override { + return false; + } + + unsigned getNumFixupKinds() const override { + // We currently just use the generic fixups in MCFixup.h and don't have any + // target-specific fixups. + return 0; + } + + bool mayNeedRelaxation(const MCInst &Inst) const override { return false; } + + void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, + MCInst &Res) const override {} + + bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override; +}; + class WebAssemblyAsmBackend final : public MCAsmBackend { bool Is64Bit; @@ -61,6 +96,41 @@ bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override; }; +bool WebAssemblyAsmBackendELF::writeNopData(uint64_t Count, + MCObjectWriter *OW) const { + for (uint64_t i = 0; i < Count; ++i) + OW->write8(WebAssembly::Nop); + + return true; +} + +void WebAssemblyAsmBackendELF::applyFixup(const MCFixup &Fixup, char *Data, + unsigned DataSize, uint64_t Value, + bool IsPCRel) const { + const MCFixupKindInfo &Info = getFixupKindInfo(Fixup.getKind()); + assert(Info.Flags == 0 && "WebAssembly does not use MCFixupKindInfo flags"); + + unsigned NumBytes = alignTo(Info.TargetSize, 8) / 8; + if (Value == 0) + return; // Doesn't change encoding. + + // Shift the value into position. + Value <<= Info.TargetOffset; + + unsigned Offset = Fixup.getOffset(); + assert(Offset + NumBytes <= DataSize && "Invalid fixup offset!"); + + // For each byte of the fragment that the fixup touches, mask in the + // bits from the fixup value. + for (unsigned i = 0; i != NumBytes; ++i) + Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff); +} + +MCObjectWriter * +WebAssemblyAsmBackendELF::createObjectWriter(raw_pwrite_stream &OS) const { + return createWebAssemblyELFObjectWriter(OS, Is64Bit, 0); +} + bool WebAssemblyAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const { if (Count == 0) @@ -78,7 +148,7 @@ const MCFixupKindInfo &Info = getFixupKindInfo(Fixup.getKind()); assert(Info.Flags == 0 && "WebAssembly does not use MCFixupKindInfo flags"); - unsigned NumBytes = (Info.TargetSize + 7) / 8; + unsigned NumBytes = alignTo(Info.TargetSize, 8) / 8; if (Value == 0) return; // Doesn't change encoding. @@ -96,10 +166,12 @@ MCObjectWriter * WebAssemblyAsmBackend::createObjectWriter(raw_pwrite_stream &OS) const { - return createWebAssemblyELFObjectWriter(OS, Is64Bit, 0); + return createWebAssemblyWasmObjectWriter(OS, Is64Bit); } } // end anonymous namespace MCAsmBackend *llvm::createWebAssemblyAsmBackend(const Triple &TT) { + if (TT.isOSBinFormatELF()) + return new WebAssemblyAsmBackendELF(TT.isArch64Bit()); return new WebAssemblyAsmBackend(TT.isArch64Bit()); } Index: lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.h =================================================================== --- lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.h +++ lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.h @@ -16,12 +16,19 @@ #define LLVM_LIB_TARGET_WEBASSEMBLY_MCTARGETDESC_WEBASSEMBLYMCASMINFO_H #include "llvm/MC/MCAsmInfoELF.h" +#include "llvm/MC/MCAsmInfoWasm.h" namespace llvm { class Triple; -class WebAssemblyMCAsmInfo final : public MCAsmInfoELF { +class WebAssemblyMCAsmInfoELF final : public MCAsmInfoELF { +public: + explicit WebAssemblyMCAsmInfoELF(const Triple &T); + ~WebAssemblyMCAsmInfoELF() override; +}; + +class WebAssemblyMCAsmInfo final : public MCAsmInfoWasm { public: explicit WebAssemblyMCAsmInfo(const Triple &T); ~WebAssemblyMCAsmInfo() override; Index: lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp =================================================================== --- lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp +++ lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp @@ -19,9 +19,9 @@ #define DEBUG_TYPE "wasm-mc-asm-info" -WebAssemblyMCAsmInfo::~WebAssemblyMCAsmInfo() {} +WebAssemblyMCAsmInfoELF::~WebAssemblyMCAsmInfoELF() {} -WebAssemblyMCAsmInfo::WebAssemblyMCAsmInfo(const Triple &T) { +WebAssemblyMCAsmInfoELF::WebAssemblyMCAsmInfoELF(const Triple &T) { PointerSize = CalleeSaveStackSlotSize = T.isArch64Bit() ? 8 : 4; // TODO: What should MaxInstLength be? @@ -51,3 +51,33 @@ // WebAssembly's stack is never executable. UsesNonexecutableStackSection = false; } + +WebAssemblyMCAsmInfo::~WebAssemblyMCAsmInfo() {} + +WebAssemblyMCAsmInfo::WebAssemblyMCAsmInfo(const Triple &T) { + PointerSize = CalleeSaveStackSlotSize = T.isArch64Bit() ? 8 : 4; + + // TODO: What should MaxInstLength be? + + UseDataRegionDirectives = true; + + // Use .skip instead of .zero because .zero is confusing when used with two + // arguments (it doesn't actually zero things out). + ZeroDirective = "\t.skip\t"; + + Data8bitsDirective = "\t.int8\t"; + Data16bitsDirective = "\t.int16\t"; + Data32bitsDirective = "\t.int32\t"; + Data64bitsDirective = "\t.int64\t"; + + AlignmentIsInBytes = false; + COMMDirectiveAlignmentIsInBytes = false; + LCOMMDirectiveAlignmentType = LCOMM::Log2Alignment; + + SupportsDebugInformation = true; + + // For now, WebAssembly does not support exceptions. + ExceptionsType = ExceptionHandling::None; + + // TODO: UseIntegratedAssembler? +} Index: lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h =================================================================== --- lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -41,6 +41,9 @@ MCObjectWriter *createWebAssemblyELFObjectWriter(raw_pwrite_stream &OS, bool Is64Bit, uint8_t OSABI); +MCObjectWriter *createWebAssemblyWasmObjectWriter(raw_pwrite_stream &OS, + bool Is64Bit); + namespace WebAssembly { enum OperandType { /// Basic block label in a branch construct. Index: lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp =================================================================== --- lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp +++ lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp @@ -36,6 +36,8 @@ static MCAsmInfo *createMCAsmInfo(const MCRegisterInfo & /*MRI*/, const Triple &TT) { + if (TT.isOSBinFormatELF()) + return new WebAssemblyMCAsmInfoELF(TT); return new WebAssemblyMCAsmInfo(TT); } @@ -88,8 +90,12 @@ } static MCTargetStreamer * -createObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo & /*STI*/) { - return new WebAssemblyTargetELFStreamer(S); +createObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) { + const Triple &TT = STI.getTargetTriple(); + if (TT.isOSBinFormatELF()) + return new WebAssemblyTargetELFStreamer(S); + + return new WebAssemblyTargetWasmStreamer(S); } static MCTargetStreamer *createAsmTargetStreamer(MCStreamer &S, Index: lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h =================================================================== --- lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h +++ lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h @@ -22,6 +22,7 @@ namespace llvm { class MCELFStreamer; +class MCWasmStreamer; /// WebAssembly-specific streamer interface, to implement support /// WebAssembly-specific assembly directives. @@ -83,6 +84,22 @@ void emitGlobalImport(StringRef name) override; }; +/// This part is for Wasm object output +class WebAssemblyTargetWasmStreamer final : public WebAssemblyTargetStreamer { +public: + explicit WebAssemblyTargetWasmStreamer(MCStreamer &S); + + void emitParam(ArrayRef Types) override; + void emitResult(ArrayRef Types) override; + void emitLocal(ArrayRef Types) override; + void emitEndFunc() override; + void emitIndirectFunctionType(StringRef name, + SmallVectorImpl &Params, + SmallVectorImpl &Results) override; + void emitIndIdx(const MCExpr *Value) override; + void emitGlobalImport(StringRef name) override; +}; + } // end namespace llvm #endif Index: lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp =================================================================== --- lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp +++ lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp @@ -18,9 +18,10 @@ #include "WebAssemblyMCTargetDesc.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCSectionWasm.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbolELF.h" -#include "llvm/Support/ELF.h" +#include "llvm/MC/MCSymbolWasm.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormattedStream.h" using namespace llvm; @@ -35,6 +36,9 @@ WebAssemblyTargetELFStreamer::WebAssemblyTargetELFStreamer(MCStreamer &S) : WebAssemblyTargetStreamer(S) {} +WebAssemblyTargetWasmStreamer::WebAssemblyTargetWasmStreamer(MCStreamer &S) + : WebAssemblyTargetStreamer(S) {} + static void PrintTypes(formatted_raw_ostream &OS, ArrayRef Types) { bool First = true; for (MVT Type : Types) { @@ -117,4 +121,35 @@ } void WebAssemblyTargetELFStreamer::emitGlobalImport(StringRef name) { -} \ No newline at end of file +} + +void WebAssemblyTargetWasmStreamer::emitParam(ArrayRef Types) { + // Nothing to emit; params are declared as part of the function signature. +} + +void WebAssemblyTargetWasmStreamer::emitResult(ArrayRef Types) { + // Nothing to emit; results are declared as part of the function signature. +} + +void WebAssemblyTargetWasmStreamer::emitLocal(ArrayRef Types) { + Streamer.EmitULEB128IntValue(Types.size()); + for (MVT Type : Types) + Streamer.EmitIntValue(int64_t(WebAssembly::toValType(Type)), 1); +} + +void WebAssemblyTargetWasmStreamer::emitEndFunc() { + Streamer.EmitIntValue(WebAssembly::End, 1); +} + +void WebAssemblyTargetWasmStreamer::emitIndIdx(const MCExpr *Value) { + llvm_unreachable(".indidx encoding not yet implemented"); +} + +void WebAssemblyTargetWasmStreamer::emitIndirectFunctionType( + StringRef name, SmallVectorImpl &Params, SmallVectorImpl &Results) { + // Nothing to emit here. TODO: Re-design how linking works and re-evaluate + // whether it's necessary for .o files to declare indirect function types. +} + +void WebAssemblyTargetWasmStreamer::emitGlobalImport(StringRef name) { +} Index: lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -74,7 +74,11 @@ : "e-m:e-p:32:32-i64:64-n32:64-S128", TT, CPU, FS, Options, getEffectiveRelocModel(RM), CM, OL), - TLOF(make_unique()) { + TLOF(TT.isOSBinFormatELF() ? + static_cast( + new WebAssemblyTargetObjectFileELF()) : + static_cast( + new WebAssemblyTargetObjectFile())) { // WebAssembly type-checks instructions, but a noreturn function with a return // type that doesn't match the context will cause a check failure. So we lower // LLVM 'unreachable' to ISD::TRAP and then lower that to WebAssembly's Index: lib/Target/WebAssembly/WebAssemblyTargetObjectFile.h =================================================================== --- lib/Target/WebAssembly/WebAssemblyTargetObjectFile.h +++ lib/Target/WebAssembly/WebAssemblyTargetObjectFile.h @@ -20,7 +20,13 @@ namespace llvm { -class WebAssemblyTargetObjectFile final : public TargetLoweringObjectFileELF { +class WebAssemblyTargetObjectFileELF final + : public TargetLoweringObjectFileELF { +public: + void Initialize(MCContext &Ctx, const TargetMachine &TM) override; +}; + +class WebAssemblyTargetObjectFile final : public TargetLoweringObjectFileWasm { public: void Initialize(MCContext &Ctx, const TargetMachine &TM) override; }; Index: lib/Target/WebAssembly/WebAssemblyTargetObjectFile.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyTargetObjectFile.cpp +++ lib/Target/WebAssembly/WebAssemblyTargetObjectFile.cpp @@ -17,8 +17,14 @@ #include "WebAssemblyTargetMachine.h" using namespace llvm; -void WebAssemblyTargetObjectFile::Initialize(MCContext &Ctx, - const TargetMachine &TM) { +void WebAssemblyTargetObjectFileELF::Initialize(MCContext &Ctx, + const TargetMachine &TM) { TargetLoweringObjectFileELF::Initialize(Ctx, TM); InitializeELF(TM.Options.UseInitArray); } + +void WebAssemblyTargetObjectFile::Initialize(MCContext &Ctx, + const TargetMachine &TM) { + TargetLoweringObjectFileWasm::Initialize(Ctx, TM); + InitializeWasm(); +}