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; +}; + } // end namespace llvm #endif Index: include/llvm/MC/MCAsmInfoWasm.h =================================================================== --- /dev/null +++ include/llvm/MC/MCAsmInfoWasm.h @@ -0,0 +1,24 @@ +//===-- llvm/MC/MCAsmInfoWasm.h - Wasm Asm info -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MC_MCASMINFOWASM_H +#define LLVM_MC_MCASMINFOWASM_H + +#include "llvm/MC/MCAsmInfo.h" + +namespace llvm { +class MCAsmInfoWasm : public MCAsmInfo { + virtual void anchor(); + +protected: + MCAsmInfoWasm(); +}; +} + +#endif Index: include/llvm/MC/MCContext.h =================================================================== --- include/llvm/MC/MCContext.h +++ include/llvm/MC/MCContext.h @@ -32,6 +32,7 @@ class MCSection; class MCSymbol; class MCSymbolELF; + class MCSymbolWasm; class MCLabel; struct MCDwarfFile; class MCDwarfLoc; @@ -42,6 +43,7 @@ class MCSectionMachO; class MCSectionELF; class MCSectionCOFF; + class MCSectionWasm; class CodeViewContext; /// Context object for machine code objects. This class owns all of the @@ -78,6 +80,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; @@ -415,6 +436,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 @@ -39,7 +39,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/MCSectionWasm.h =================================================================== --- /dev/null +++ include/llvm/MC/MCSectionWasm.h @@ -0,0 +1,80 @@ +//===- MCSectionWasm.h - Wasm Machine Code Sections -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the MCSectionWasm class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MC_MCSECTIONWASM_H +#define LLVM_MC_MCSECTIONWASM_H + +#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCSymbolWasm.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { + +class MCSymbol; + +/// This represents a section on linux, lots of unix variants and some bare +/// metal systems. +class MCSectionWasm final : public MCSection { + /// This is the name of the section. The referenced memory is owned by + /// TargetLoweringObjectFileWasm's WasmUniqueMap. + StringRef SectionName; + + /// This is the sh_type field of a section, drawn from the enums below. + unsigned Type; + + /// This is the sh_flags field of a section, drawn from the enums below. + unsigned Flags; + + unsigned UniqueID; + + const MCSymbolWasm *Group; + +private: + friend class MCContext; + MCSectionWasm(StringRef Section, unsigned type, unsigned flags, SectionKind K, + const MCSymbolWasm *group, unsigned UniqueID, MCSymbol *Begin) + : MCSection(SV_Wasm, K, Begin), SectionName(Section), Type(type), + Flags(flags), UniqueID(UniqueID), Group(group) { + } + + void setSectionName(StringRef Name) { SectionName = Name; } + +public: + ~MCSectionWasm(); + + /// Decides whether a '.section' directive should be printed before the + /// section name + bool ShouldOmitSectionDirective(StringRef Name, const MCAsmInfo &MAI) const; + + StringRef getSectionName() const { return SectionName; } + unsigned getType() const { return Type; } + unsigned getFlags() const { return Flags; } + void setFlags(unsigned F) { Flags = F; } + const MCSymbolWasm *getGroup() const { return Group; } + + void PrintSwitchToSection(const MCAsmInfo &MAI, raw_ostream &OS, + const MCExpr *Subsection) const override; + bool UseCodeAlign() const override; + bool isVirtualSection() const override; + + bool isUnique() const { return UniqueID != ~0U; } + unsigned getUniqueID() const { return UniqueID; } + + static bool classof(const MCSection *S) { return S->getVariant() == SV_Wasm; } +}; + +} // end namespace llvm + +#endif Index: include/llvm/MC/MCStreamer.h =================================================================== --- include/llvm/MC/MCStreamer.h +++ include/llvm/MC/MCStreamer.h @@ -36,6 +36,7 @@ class MCStreamer; class MCSymbolELF; class MCSymbolRefExpr; +class MCSymbolWasm; class MCSubtargetInfo; class StringRef; class Twine; Index: include/llvm/MC/MCSymbol.h =================================================================== --- include/llvm/MC/MCSymbol.h +++ include/llvm/MC/MCSymbol.h @@ -45,6 +45,7 @@ SymbolKindCOFF, SymbolKindELF, SymbolKindMachO, + SymbolKindWasm, }; /// A symbol can contain an Offset, or Value, or be Common, but never more @@ -97,7 +98,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; @@ -281,6 +282,8 @@ bool isMachO() const { return Kind == SymbolKindMachO; } + bool isWasm() const { return Kind == SymbolKindWasm; } + /// @} /// \name Variable Symbols /// @{ Index: include/llvm/MC/MCSymbolWasm.h =================================================================== --- /dev/null +++ include/llvm/MC/MCSymbolWasm.h @@ -0,0 +1,24 @@ +//===- MCSymbolWasm.h - ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_MC_MCSYMBOLWASM_H +#define LLVM_MC_MCSYMBOLWASM_H + +#include "llvm/MC/MCSymbol.h" + +namespace llvm { +class MCSymbolWasm : public MCSymbol { +public: + MCSymbolWasm(const StringMapEntry *Name, bool isTemporary) + : MCSymbol(SymbolKindWasm, Name, isTemporary) {} + + static bool classof(const MCSymbol *S) { return S->isWasm(); } +}; +} + +#endif Index: include/llvm/MC/MCWasmObjectWriter.h =================================================================== --- /dev/null +++ include/llvm/MC/MCWasmObjectWriter.h @@ -0,0 +1,78 @@ +//===-- llvm/MC/MCWasmObjectWriter.h - Wasm Object Writer -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MC_MCWASMOBJECTWRITER_H +#define LLVM_MC_MCWASMOBJECTWRITER_H + +#include "llvm/ADT/Triple.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/raw_ostream.h" +#include + +namespace llvm { +class MCAssembler; +class MCContext; +class MCFixup; +class MCFragment; +class MCObjectWriter; +class MCSymbol; +class MCSymbolWasm; +class MCValue; +class raw_pwrite_stream; + +struct WasmRelocationEntry { + uint64_t Offset; // Where is the relocation. + const MCSymbolWasm *Symbol; // The symbol to relocate with. + unsigned Type; // The type of the relocation. + + WasmRelocationEntry(uint64_t Offset, const MCSymbolWasm *Symbol, + unsigned Type) + : Offset(Offset), Symbol(Symbol), Type(Type) {} + + void print(raw_ostream &Out) const { + Out << "Off=" << Offset << ", Sym=" << Symbol << ", Type=" << Type; + } + void dump() const { print(errs()); } +}; + +class MCWasmObjectTargetWriter { + const unsigned Is64Bit : 1; + +protected: + explicit MCWasmObjectTargetWriter(bool Is64Bit_); + +public: + virtual ~MCWasmObjectTargetWriter() {} + + virtual unsigned getRelocType(MCContext &Ctx, const MCValue &Target, + const MCFixup &Fixup, bool IsPCRel) const = 0; + + virtual bool needsRelocateWithSymbol(const MCSymbol &Sym, + unsigned Type) const; + + virtual void sortRelocs(const MCAssembler &Asm, + std::vector &Relocs); + + /// \name Accessors + /// @{ + bool is64Bit() const { return Is64Bit; } + /// @} +}; + +/// \brief Construct a new Wasm writer instance. +/// +/// \param MOTW - The target specific Wasm writer subclass. +/// \param OS - The stream to write to. +/// \returns The constructed object writer. +MCObjectWriter *createWasmObjectWriter(MCWasmObjectTargetWriter *MOTW, + raw_pwrite_stream &OS); +} // End llvm namespace + +#endif Index: include/llvm/MC/MCWasmStreamer.h =================================================================== --- /dev/null +++ include/llvm/MC/MCWasmStreamer.h @@ -0,0 +1,87 @@ +//===- MCWasmStreamer.h - MCStreamer Wasm Object File Interface -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MC_MCWASMSTREAMER_H +#define LLVM_MC_MCWASMSTREAMER_H + +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/MC/MCDirectives.h" +#include "llvm/MC/MCObjectStreamer.h" +#include "llvm/MC/SectionKind.h" +#include "llvm/Support/DataTypes.h" + +namespace llvm { +class MCAsmBackend; +class MCAssembler; +class MCCodeEmitter; +class MCExpr; +class MCInst; +class raw_ostream; + +class MCWasmStreamer : public MCObjectStreamer { +public: + MCWasmStreamer(MCContext &Context, MCAsmBackend &TAB, raw_pwrite_stream &OS, + MCCodeEmitter *Emitter) + : MCObjectStreamer(Context, TAB, OS, Emitter), SeenIdent(false) {} + + ~MCWasmStreamer() override; + + /// state management + void reset() override { + SeenIdent = false; + MCObjectStreamer::reset(); + } + + /// \name MCStreamer Interface + /// @{ + + void ChangeSection(MCSection *Section, const MCExpr *Subsection) override; + void EmitAssemblerFlag(MCAssemblerFlag Flag) override; + void EmitThumbFunc(MCSymbol *Func) override; + void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) override; + bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override; + void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) override; + void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) override; + void BeginCOFFSymbolDef(const MCSymbol *Symbol) override; + void EmitCOFFSymbolStorageClass(int StorageClass) override; + void EmitCOFFSymbolType(int Type) override; + void EndCOFFSymbolDef() override; + + void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) override; + + void EmitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr, + uint64_t Size = 0, unsigned ByteAlignment = 0) override; + void EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment = 0) override; + void EmitValueImpl(const MCExpr *Value, unsigned Size, + SMLoc Loc = SMLoc()) override; + + void EmitFileDirective(StringRef Filename) override; + + void EmitIdent(StringRef IdentString) override; + + void EmitValueToAlignment(unsigned, int64_t, unsigned, unsigned) override; + + void FinishImpl() override; + +private: + void EmitInstToFragment(const MCInst &Inst, const MCSubtargetInfo &) override; + void EmitInstToData(const MCInst &Inst, const MCSubtargetInfo &) override; + + /// \brief Merge the content of the fragment \p EF into the fragment \p DF. + void mergeFragment(MCDataFragment *, MCDataFragment *); + + bool SeenIdent; +}; + +} // end namespace llvm + +#endif 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" @@ -1146,3 +1148,53 @@ OS << ",data"; } } + +//===----------------------------------------------------------------------===// +// 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/MCAsmInfoWasm.cpp =================================================================== --- /dev/null +++ lib/MC/MCAsmInfoWasm.cpp @@ -0,0 +1,27 @@ +//===-- MCAsmInfoWasm.cpp - Wasm asm properties -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines target asm properties related what form asm statements +// should take in general on Wasm-based targets +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCAsmInfoWasm.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSectionWasm.h" +using namespace llvm; + +void MCAsmInfoWasm::anchor() { } + +MCAsmInfoWasm::MCAsmInfoWasm() { + HasIdentDirective = true; + WeakRefDirective = "\t.weak\t"; + PrivateGlobalPrefix = ".L"; + PrivateLabelPrefix = ".L"; +} 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" @@ -162,6 +164,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, @@ -332,7 +336,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 new (ELFAllocator.Allocate()) MCSectionELF(I->getKey(), Type, Flags, SectionKind::getReadOnly(), @@ -469,6 +473,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; @@ -799,6 +800,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) { @@ -843,6 +868,10 @@ Env = IsELF; initELFMCObjectFileInfo(TT); break; + case Triple::Wasm: + Env = IsWasm; + initWasmMCObjectFileInfo(TT); + break; case Triple::UnknownObjectFormat: report_fatal_error("Cannot initialize MC for unknown object file format."); break; 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/MC/MCSectionWasm.cpp =================================================================== --- /dev/null +++ lib/MC/MCSectionWasm.cpp @@ -0,0 +1,96 @@ +//===- lib/MC/MCSectionWasm.cpp - Wasm Code Section Representation --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCSectionWasm.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +MCSectionWasm::~MCSectionWasm() {} // anchor. + +// Decides whether a '.section' directive +// should be printed before the section name. +bool MCSectionWasm::ShouldOmitSectionDirective(StringRef Name, + const MCAsmInfo &MAI) const { + return MAI.shouldOmitSectionDirective(Name); +} + +static void printName(raw_ostream &OS, StringRef Name) { + if (Name.find_first_not_of("0123456789_." + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ") == Name.npos) { + OS << Name; + return; + } + OS << '"'; + for (const char *B = Name.begin(), *E = Name.end(); B < E; ++B) { + if (*B == '"') // Unquoted " + OS << "\\\""; + else if (*B != '\\') // Neither " or backslash + OS << *B; + else if (B + 1 == E) // Trailing backslash + OS << "\\\\"; + else { + OS << B[0] << B[1]; // Quoted character + ++B; + } + } + OS << '"'; +} + +void MCSectionWasm::PrintSwitchToSection(const MCAsmInfo &MAI, raw_ostream &OS, + const MCExpr *Subsection) const { + + if (ShouldOmitSectionDirective(SectionName, MAI)) { + OS << '\t' << getSectionName(); + if (Subsection) { + OS << '\t'; + Subsection->print(OS, &MAI); + } + OS << '\n'; + return; + } + + OS << "\t.section\t"; + printName(OS, getSectionName()); + OS << ",\""; + + // TODO: Print section flags. + + OS << '"'; + + OS << ','; + + // If comment string is '@', e.g. as on ARM - use '%' instead + if (MAI.getCommentString()[0] == '@') + OS << '%'; + else + OS << '@'; + + // TODO: Print section type. + + if (isUnique()) + OS << ",unique," << UniqueID; + + OS << '\n'; + + if (Subsection) { + OS << "\t.subsection\t"; + Subsection->print(OS, &MAI); + OS << '\n'; + } +} + +bool MCSectionWasm::UseCodeAlign() const { return false; } + +bool MCSectionWasm::isVirtualSection() const { return false; } Index: lib/MC/MCWasmObjectTargetWriter.cpp =================================================================== --- /dev/null +++ lib/MC/MCWasmObjectTargetWriter.cpp @@ -0,0 +1,27 @@ +//===-- MCWasmObjectTargetWriter.cpp - Wasm Target Writer Subclass --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/STLExtras.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCValue.h" +#include "llvm/MC/MCWasmObjectWriter.h" + +using namespace llvm; + +MCWasmObjectTargetWriter::MCWasmObjectTargetWriter(bool Is64Bit_) + : Is64Bit(Is64Bit_) {} + +bool MCWasmObjectTargetWriter::needsRelocateWithSymbol(const MCSymbol &Sym, + unsigned Type) const { + return false; +} + +void MCWasmObjectTargetWriter::sortRelocs( + const MCAssembler &Asm, std::vector &Relocs) { +} Index: lib/MC/MCWasmStreamer.cpp =================================================================== --- /dev/null +++ lib/MC/MCWasmStreamer.cpp @@ -0,0 +1,211 @@ +//===- lib/MC/MCWasmStreamer.cpp - Wasm Object Output ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file assembles .s files and emits Wasm .o object files. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCWasmStreamer.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCAsmLayout.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCObjectStreamer.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCSectionWasm.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCSymbolWasm.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +MCWasmStreamer::~MCWasmStreamer() {} + +void MCWasmStreamer::mergeFragment(MCDataFragment *DF, MCDataFragment *EF) { + flushPendingLabels(DF, DF->getContents().size()); + + for (unsigned i = 0, e = EF->getFixups().size(); i != e; ++i) { + EF->getFixups()[i].setOffset(EF->getFixups()[i].getOffset() + + DF->getContents().size()); + DF->getFixups().push_back(EF->getFixups()[i]); + } + DF->setHasInstructions(true); + DF->getContents().append(EF->getContents().begin(), EF->getContents().end()); +} + +void MCWasmStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { + // Let the target do whatever target specific stuff it needs to do. + getAssembler().getBackend().handleAssemblerFlag(Flag); + + // Do any generic stuff we need to do. + llvm_unreachable("invalid assembler flag!"); +} + +void MCWasmStreamer::ChangeSection(MCSection *Section, + const MCExpr *Subsection) { + MCAssembler &Asm = getAssembler(); + auto *SectionWasm = static_cast(Section); + const MCSymbol *Grp = SectionWasm->getGroup(); + if (Grp) + Asm.registerSymbol(*Grp); + + this->MCObjectStreamer::ChangeSection(Section, Subsection); +} + +void MCWasmStreamer::EmitWeakReference(MCSymbol *Alias, + const MCSymbol *Symbol) { + getAssembler().registerSymbol(*Symbol); + const MCExpr *Value = MCSymbolRefExpr::create( + Symbol, MCSymbolRefExpr::VK_WEAKREF, getContext()); + Alias->setVariableValue(Value); +} + +bool MCWasmStreamer::EmitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) { + auto *Symbol = cast(S); + // Indirect symbols are handled differently, to match how 'as' handles + // them. This makes writing matching .o files easier. + if (Attribute == MCSA_IndirectSymbol) { + // Note that we intentionally cannot use the symbol data here; this is + // important for matching the string table that 'as' generates. + IndirectSymbolData ISD; + ISD.Symbol = Symbol; + ISD.Section = getCurrentSectionOnly(); + getAssembler().getIndirectSymbols().push_back(ISD); + return true; + } + + // Adding a symbol attribute always introduces the symbol, note that an + // important side effect of calling registerSymbol here is to register + // the symbol with the assembler. + getAssembler().registerSymbol(*Symbol); + + // TODO: Set the symbol binding, type, etc. + + return true; +} + +void MCWasmStreamer::EmitCommonSymbol(MCSymbol *S, uint64_t Size, + unsigned ByteAlignment) { + llvm_unreachable("Common symbols are not yet implemented for Wasm"); +} + +void MCWasmStreamer::EmitLocalCommonSymbol(MCSymbol *S, uint64_t Size, + unsigned ByteAlignment) { + llvm_unreachable("Local common symbols are not yet implemented for Wasm"); +} + +void MCWasmStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size, + SMLoc Loc) { + MCObjectStreamer::EmitValueImpl(Value, Size, Loc); +} + +void MCWasmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, + unsigned ValueSize, + unsigned MaxBytesToEmit) { + MCObjectStreamer::EmitValueToAlignment(ByteAlignment, Value, ValueSize, + MaxBytesToEmit); +} + +// Add a symbol for the file name of this module. They start after the +// null symbol and don't count as normal symbol, i.e. a non-STT_FILE symbol +// with the same name may appear. +void MCWasmStreamer::EmitFileDirective(StringRef Filename) { + getAssembler().addFileName(Filename); +} + +void MCWasmStreamer::EmitIdent(StringRef IdentString) { + llvm_unreachable("Ident sections not yet implemented for wasm"); +} + +void MCWasmStreamer::EmitInstToFragment(const MCInst &Inst, + const MCSubtargetInfo &STI) { + this->MCObjectStreamer::EmitInstToFragment(Inst, STI); +} + +void MCWasmStreamer::EmitInstToData(const MCInst &Inst, + const MCSubtargetInfo &STI) { + MCAssembler &Assembler = getAssembler(); + SmallVector Fixups; + SmallString<256> Code; + raw_svector_ostream VecOS(Code); + Assembler.getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI); + + // Append the encoded instruction to the current data fragment (or create a + // new such fragment if the current fragment is not a data fragment). + MCDataFragment *DF = getOrCreateDataFragment(); + + // Add the fixups and data. + for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { + Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size()); + DF->getFixups().push_back(Fixups[i]); + } + DF->setHasInstructions(true); + DF->getContents().append(Code.begin(), Code.end()); +} + +void MCWasmStreamer::FinishImpl() { + EmitFrames(nullptr); + + this->MCObjectStreamer::FinishImpl(); +} + +MCStreamer *llvm::createWasmStreamer(MCContext &Context, MCAsmBackend &MAB, + raw_pwrite_stream &OS, MCCodeEmitter *CE, + bool RelaxAll) { + MCWasmStreamer *S = new MCWasmStreamer(Context, MAB, OS, CE); + if (RelaxAll) + S->getAssembler().setRelaxAll(true); + return S; +} + +void MCWasmStreamer::EmitThumbFunc(MCSymbol *Func) { + llvm_unreachable("Generic Wasm doesn't support this directive"); +} + +void MCWasmStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { + llvm_unreachable("Wasm doesn't support this directive"); +} + +void MCWasmStreamer::BeginCOFFSymbolDef(const MCSymbol *Symbol) { + llvm_unreachable("Wasm doesn't support this directive"); +} + +void MCWasmStreamer::EmitCOFFSymbolStorageClass(int StorageClass) { + llvm_unreachable("Wasm doesn't support this directive"); +} + +void MCWasmStreamer::EmitCOFFSymbolType(int Type) { + llvm_unreachable("Wasm doesn't support this directive"); +} + +void MCWasmStreamer::EndCOFFSymbolDef() { + llvm_unreachable("Wasm doesn't support this directive"); +} + +void MCWasmStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment) { + llvm_unreachable("Wasm doesn't support this directive"); +} + +void MCWasmStreamer::EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment) { + llvm_unreachable("Wasm doesn't support this directive"); +} Index: lib/MC/WasmObjectWriter.cpp =================================================================== --- /dev/null +++ lib/MC/WasmObjectWriter.cpp @@ -0,0 +1,165 @@ +//===- lib/MC/WasmObjectWriter.cpp - Wasm File Writer ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements Wasm object file writer information. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCAsmLayout.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSectionWasm.h" +#include "llvm/MC/MCSymbolWasm.h" +#include "llvm/MC/MCValue.h" +#include "llvm/MC/MCWasmObjectWriter.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/StringSaver.h" +#include + +using namespace llvm; + +#undef DEBUG_TYPE +#define DEBUG_TYPE "reloc-info" + +namespace { +typedef DenseMap SectionIndexMapTy; + +class WasmObjectWriter : public MCObjectWriter { + /// Helper struct for containing some precomputed information on symbols. + struct WasmSymbolData { + const MCSymbolWasm *Symbol; + StringRef Name; + + // Support lexicographic sorting. + bool operator<(const WasmSymbolData &RHS) const { return Name < RHS.Name; } + }; + + /// The target specific Wasm writer instance. + std::unique_ptr TargetObjectWriter; + + DenseMap Renames; + + /// @} + /// @name Symbol Table Data + /// @{ + + BumpPtrAllocator Alloc; + StringSaver VersionSymSaver{Alloc}; + + /// @} + + // TargetObjectWriter wrappers. + bool is64Bit() const { return TargetObjectWriter->is64Bit(); } + unsigned getRelocType(MCContext &Ctx, const MCValue &Target, + const MCFixup &Fixup, bool IsPCRel) const { + return TargetObjectWriter->getRelocType(Ctx, Target, Fixup, IsPCRel); + } + +public: + WasmObjectWriter(MCWasmObjectTargetWriter *MOTW, raw_pwrite_stream &OS) + : MCObjectWriter(OS, /*IsLittleEndian=*/true), TargetObjectWriter(MOTW) {} + + void reset() override { + Renames.clear(); + MCObjectWriter::reset(); + } + + ~WasmObjectWriter() override; + + void writeHeader(const MCAssembler &Asm); + + // Fixup offset and size of each section + typedef std::map> + SectionSizesTy; + + void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, + const MCFragment *Fragment, const MCFixup &Fixup, + MCValue Target, bool &IsPCRel, + uint64_t &FixedValue) override; + + void executePostLayoutBinding(MCAssembler &Asm, + const MCAsmLayout &Layout) override; + + void writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override; +}; +} // end anonymous namespace + +WasmObjectWriter::~WasmObjectWriter() {} + +// Emit the Wasm header. +void WasmObjectWriter::writeHeader(const MCAssembler &Asm) { + // TODO: write the magic cookie and the version. +} + +void WasmObjectWriter::executePostLayoutBinding(MCAssembler &Asm, + const MCAsmLayout &Layout) { + // The presence of symbol versions causes undefined symbols and + // versions declared with @@@ to be renamed. + for (const MCSymbol &A : Asm.symbols()) { + const auto &Alias = cast(A); + // Not an alias. + if (!Alias.isVariable()) + continue; + auto *Ref = dyn_cast(Alias.getVariableValue()); + if (!Ref) + continue; + const auto &Symbol = cast(Ref->getSymbol()); + + StringRef AliasName = Alias.getName(); + size_t Pos = AliasName.find('@'); + if (Pos == StringRef::npos) + continue; + + // Aliases defined with .symvar copy the binding from the symbol they alias. + // This is the first place we are able to copy this information. + StringRef Rest = AliasName.substr(Pos); + if (!Symbol.isUndefined() && !Rest.startswith("@@@")) + continue; + + // FIXME: produce a better error message. + if (Symbol.isUndefined() && Rest.startswith("@@") && + !Rest.startswith("@@@")) + report_fatal_error("A @@ version cannot be undefined"); + + Renames.insert(std::make_pair(&Symbol, &Alias)); + } +} + +void WasmObjectWriter::recordRelocation(MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, MCValue Target, + bool &IsPCRel, uint64_t &FixedValue) { + // TODO: Implement +} + +void WasmObjectWriter::writeObject(MCAssembler &Asm, + const MCAsmLayout &Layout) { + // Write out the Wasm header. + writeHeader(Asm); + + // TODO: Write the contents. +} + +MCObjectWriter *llvm::createWasmObjectWriter(MCWasmObjectTargetWriter *MOTW, + raw_pwrite_stream &OS) { + return new WasmObjectWriter(MOTW, OS); +} Index: lib/Target/ARM/AsmParser/ARMAsmParser.cpp =================================================================== --- lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -5480,7 +5480,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; @@ -5514,6 +5515,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,44 @@ bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override; }; +bool WebAssemblyAsmBackendELF::writeNopData(uint64_t Count, + MCObjectWriter *OW) const { + if (Count == 0) + return true; + + 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 = (Info.TargetSize + 7) / 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) @@ -96,10 +169,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()) + 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/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp =================================================================== --- /dev/null +++ lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp @@ -0,0 +1,48 @@ +//===-- WebAssemblyWasmObjectWriter.cpp - WebAssembly Wasm Writer ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file handles Wasm-specific object emission, converting LLVM's +/// internal fixups into the appropriate relocations. +/// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCWasmObjectWriter.h" +#include "llvm/Support/ErrorHandling.h" +using namespace llvm; + +namespace { +class WebAssemblyWasmObjectWriter final : public MCWasmObjectTargetWriter { +public: + explicit WebAssemblyWasmObjectWriter(bool Is64Bit); + +protected: + unsigned getRelocType(MCContext &Ctx, const MCValue &Target, + const MCFixup &Fixup, bool IsPCRel) const override; +}; +} // end anonymous namespace + +WebAssemblyWasmObjectWriter::WebAssemblyWasmObjectWriter(bool Is64Bit) + : MCWasmObjectTargetWriter(Is64Bit) {} + +unsigned WebAssemblyWasmObjectWriter::getRelocType(MCContext &Ctx, + const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel) const { + llvm_unreachable("Relocations not yet implemented"); + return 0; +} + +MCObjectWriter *llvm::createWebAssemblyWasmObjectWriter(raw_pwrite_stream &OS, + bool Is64Bit) { + MCWasmObjectTargetWriter *MOTW = new WebAssemblyWasmObjectWriter(Is64Bit); + return createWasmObjectWriter(MOTW, OS); +} 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(); +}