diff --git a/llvm/include/llvm/BinaryFormat/XCOFF.h b/llvm/include/llvm/BinaryFormat/XCOFF.h --- a/llvm/include/llvm/BinaryFormat/XCOFF.h +++ b/llvm/include/llvm/BinaryFormat/XCOFF.h @@ -22,6 +22,36 @@ enum { SectionNameSize = 8, SymbolNameSize = 8 }; enum ReservedSectionNum { N_DEBUG = -2, N_ABS = -1, N_UNDEF = 0 }; +// x_smclas field of x_csect from system header: /usr/include/syms.h +/// Storage Mapping Class definitions. +enum StorageMappingClass { + // READ ONLY CLASSES + XMC_PR = 0, ///< Program Code + XMC_RO = 1, ///< Read Only Constant + XMC_DB = 2, ///< Debug Dictionary Table + XMC_GL = 6, ///< Global Linkage (Interfile Interface Code) + XMC_XO = 7, ///< Extended Operation (Pseudo Machine Instruction + XMC_SV = 8, ///< Supervisor Call (32-bit process only) + XMC_SV64 = 17, ///< Supervisor Call for 64-bit process + XMC_SV3264 = 18, ///< Supervisor Call for both 32- and 64-bit processes. + XMC_TI = 12, ///< Traceback Index csect + XMC_TB = 13, ///< Traceback table csect + + // READ WRITE CLASSES + XMC_RW = 5, ///< Read Write Data + XMC_TC0 = 15, ///< TOC Anchor for TOC Addressability + XMC_TC = 3, ///< General TOC item + XMC_TD = 16, ///< Scalar data item in the TOC + XMC_DS = 10, ///< Descriptor csect + XMC_UA = 4, ///< Unclassified - Treated as Read Write + XMC_BS = 9, ///< BSS class (uninitialized static internal) + XMC_UC = 11, ///< Un-named Fortran Common + + XMC_TL = 20, ///< Initialized thread-local variable + XMC_UL = 21, ///< Uninitialized thread-local variable + XMC_TE = 22 ///< Symbol mapped at the end of TOC +}; + // Flags for defining the section type. Used for the s_flags field of // the section header structure. Defined in the system header `scnhdr.h`. enum SectionTypeFlags { diff --git a/llvm/include/llvm/MC/MCAsmInfoXCOFF.h b/llvm/include/llvm/MC/MCAsmInfoXCOFF.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/MC/MCAsmInfoXCOFF.h @@ -0,0 +1,25 @@ +//===- MCAsmInfoXCOFF.h - XCOFF asm properties ----------------- *- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MC_MCASMINFOXCOFF_H +#define LLVM_MC_MCASMINFOXCOFF_H + +#include "llvm/MC/MCAsmInfo.h" + +namespace llvm { + +class MCAsmInfoXCOFF : public MCAsmInfo { + virtual void anchor(); + +protected: + MCAsmInfoXCOFF(); +}; + +} // end namespace llvm + +#endif // LLVM_MC_MCASMINFOXCOFF_H diff --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h --- a/llvm/include/llvm/MC/MCContext.h +++ b/llvm/include/llvm/MC/MCContext.h @@ -18,6 +18,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/BinaryFormat/XCOFF.h" #include "llvm/MC/MCAsmMacro.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCSubtargetInfo.h" @@ -49,6 +50,7 @@ class MCSectionELF; class MCSectionMachO; class MCSectionWasm; + class MCSectionXCOFF; class MCStreamer; class MCSymbol; class MCSymbolELF; @@ -91,6 +93,7 @@ SpecificBumpPtrAllocator ELFAllocator; SpecificBumpPtrAllocator MachOAllocator; SpecificBumpPtrAllocator WasmAllocator; + SpecificBumpPtrAllocator XCOFFAllocator; /// Bindings of names to symbols. SymbolTable Symbols; @@ -246,10 +249,25 @@ } }; + struct XCOFFSectionKey { + std::string SectionName; + unsigned MappingClass; + + XCOFFSectionKey(StringRef SectionName, unsigned MappingClass) + : SectionName(SectionName), MappingClass(MappingClass) {} + + bool operator<(const XCOFFSectionKey &Other) const { + if (SectionName != Other.SectionName) + return SectionName < Other.SectionName; + return MappingClass < Other.MappingClass; + } + }; + StringMap MachOUniquingMap; std::map ELFUniquingMap; std::map COFFUniquingMap; std::map WasmUniquingMap; + std::map XCOFFUniquingMap; StringMap RelSecNames; SpecificBumpPtrAllocator MCSubtargetAllocator; @@ -470,6 +488,11 @@ const MCSymbolWasm *Group, unsigned UniqueID, const char *BeginSymName); + MCSectionXCOFF *getXCOFFSection(StringRef Section, + XCOFF::StorageMappingClass MappingClass, + SectionKind K, + const char *BeginSymName = nullptr); + // Create and save a copy of STI and return a reference to the copy. MCSubtargetInfo &getSubtargetCopy(const MCSubtargetInfo &STI); diff --git a/llvm/include/llvm/MC/MCObjectFileInfo.h b/llvm/include/llvm/MC/MCObjectFileInfo.h --- a/llvm/include/llvm/MC/MCObjectFileInfo.h +++ b/llvm/include/llvm/MC/MCObjectFileInfo.h @@ -400,6 +400,7 @@ void initELFMCObjectFileInfo(const Triple &T, bool Large); void initCOFFMCObjectFileInfo(const Triple &T); void initWasmMCObjectFileInfo(const Triple &T); + void initXCOFFMCObjectFileInfo(const Triple &T); MCSection *getDwarfComdatSection(const char *Name, uint64_t Hash) const; public: diff --git a/llvm/include/llvm/MC/MCSection.h b/llvm/include/llvm/MC/MCSection.h --- a/llvm/include/llvm/MC/MCSection.h +++ b/llvm/include/llvm/MC/MCSection.h @@ -37,7 +37,7 @@ /// current translation unit. The MCContext class uniques and creates these. class MCSection { public: - enum SectionVariant { SV_COFF = 0, SV_ELF, SV_MachO, SV_Wasm }; + enum SectionVariant { SV_COFF = 0, SV_ELF, SV_MachO, SV_Wasm, SV_XCOFF }; /// Express the state of bundle locked groups while emitting code. enum BundleLockStateType { diff --git a/llvm/include/llvm/MC/MCSectionXCOFF.h b/llvm/include/llvm/MC/MCSectionXCOFF.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/MC/MCSectionXCOFF.h @@ -0,0 +1,56 @@ +//===- MCSectionXCOFF.h - XCOFF Machine Code Sections -----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares the MCSectionXCOFF class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MC_MCSECTIONXCOFF_H +#define LLVM_MC_MCSECTIONXCOFF_H + +#include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/MC/MCSection.h" + +namespace llvm { + +class MCSymbol; + +// This class represents an XCOFF `Control Section`, more commonly referred to +// as a csect. A csect represents the smallest possible unit of data/code which +// will be relocated as a single block. +class MCSectionXCOFF final : public MCSection { + friend class MCContext; + + StringRef Name; + XCOFF::StorageMappingClass MappingClass; + + MCSectionXCOFF(StringRef Section, XCOFF::StorageMappingClass SMC, + SectionKind K, MCSymbol *Begin) + : MCSection(SV_XCOFF, K, Begin), Name(Section), MappingClass(SMC) {} + +public: + ~MCSectionXCOFF(); + + static bool classof(const MCSection *S) { + return S->getVariant() == SV_XCOFF; + } + + StringRef getSectionName() const { return Name; } + XCOFF::StorageMappingClass getMappingClass() const { return MappingClass; } + + void PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T, + raw_ostream &OS, + const MCExpr *Subsection) const override; + bool UseCodeAlign() const override; + bool isVirtualSection() const override; +}; + +} // end namespace llvm + +#endif diff --git a/llvm/include/llvm/MC/MCXCOFFObjectWriter.h b/llvm/include/llvm/MC/MCXCOFFObjectWriter.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/MC/MCXCOFFObjectWriter.h @@ -0,0 +1,36 @@ +//===-- llvm/MC/MCXCOFFObjectWriter.h - XCOFF Object Writer ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MC_MCXCOFFOBJECTWRITER_H +#define LLVM_MC_MCXCOFFOBJECTWRITER_H + +#include "llvm/MC/MCObjectWriter.h" + +namespace llvm { + +class raw_pwrite_stream; + +class MCXCOFFObjectTargetWriter : public MCObjectTargetWriter { +protected: + MCXCOFFObjectTargetWriter(); + +public: + virtual ~MCXCOFFObjectTargetWriter(); + + virtual Triple::ObjectFormatType getFormat() const { return Triple::XCOFF; } + static bool classof(const MCObjectTargetWriter *W) { + return W->getFormat() == Triple::XCOFF; + } +}; + +std::unique_ptr +createXCOFFObjectWriter(std::unique_ptr MOTW, + raw_pwrite_stream &OS); +} // namespace llvm + +#endif // LLVM_MC_MCXCOFFOBJECTWRITER_H diff --git a/llvm/include/llvm/MC/MCXCOFFStreamer.h b/llvm/include/llvm/MC/MCXCOFFStreamer.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/MC/MCXCOFFStreamer.h @@ -0,0 +1,33 @@ +//===- MCXCOFFObjectStreamer.h - MCStreamer XCOFF Object File Interface ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MC_MCXCOFFSTREAMER_H +#define LLVM_MC_MCXCOFFSTREAMER_H + +#include "llvm/MC/MCObjectStreamer.h" + +namespace llvm { + +class MCXCOFFStreamer : public MCObjectStreamer { +public: + MCXCOFFStreamer(MCContext &Context, std::unique_ptr MAB, + std::unique_ptr OW, + std::unique_ptr Emitter); + + bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override; + void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) override; + void EmitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr, + uint64_t Size = 0, unsigned ByteAlignment = 0, + SMLoc Loc = SMLoc()) override; + void EmitInstToData(const MCInst &Inst, const MCSubtargetInfo &) override; +}; + +} // end namespace llvm + +#endif // LLVM_MC_MCXCOFFSTREAMER_H diff --git a/llvm/include/llvm/Support/TargetRegistry.h b/llvm/include/llvm/Support/TargetRegistry.h --- a/llvm/include/llvm/Support/TargetRegistry.h +++ b/llvm/include/llvm/Support/TargetRegistry.h @@ -100,6 +100,11 @@ std::unique_ptr &&OW, std::unique_ptr &&CE, bool RelaxAll); +MCStreamer *createXCOFFStreamer(MCContext &Ctx, + std::unique_ptr &&TAB, + std::unique_ptr &&OW, + std::unique_ptr &&CE, + bool RelaxAll); MCRelocationInfo *createMCRelocationInfo(const Triple &TT, MCContext &Ctx); @@ -177,6 +182,7 @@ std::unique_ptr &&TAB, std::unique_ptr &&OW, std::unique_ptr &&Emitter, bool RelaxAll); + using NullTargetStreamerCtorTy = MCTargetStreamer *(*)(MCStreamer &S); using AsmTargetStreamerCtorTy = MCTargetStreamer *(*)( MCStreamer &S, formatted_raw_ostream &OS, MCInstPrinter *InstPrint, @@ -504,6 +510,10 @@ S = createWasmStreamer(Ctx, std::move(TAB), std::move(OW), std::move(Emitter), RelaxAll); break; + case Triple::XCOFF: + S = createXCOFFStreamer(Ctx, std::move(TAB), std::move(OW), + std::move(Emitter), RelaxAll); + break; } if (ObjectTargetStreamerCtorFn) ObjectTargetStreamerCtorFn(*S, STI); diff --git a/llvm/lib/MC/CMakeLists.txt b/llvm/lib/MC/CMakeLists.txt --- a/llvm/lib/MC/CMakeLists.txt +++ b/llvm/lib/MC/CMakeLists.txt @@ -7,6 +7,7 @@ MCAsmInfoDarwin.cpp MCAsmInfoELF.cpp MCAsmInfoWasm.cpp + MCAsmInfoXCOFF.cpp MCAsmMacro.cpp MCAsmStreamer.cpp MCAssembler.cpp @@ -38,6 +39,7 @@ MCSectionELF.cpp MCSectionMachO.cpp MCSectionWasm.cpp + MCSectionXCOFF.cpp MCStreamer.cpp MCSubtargetInfo.cpp MCSymbol.cpp @@ -49,11 +51,14 @@ MCWin64EH.cpp MCWinCOFFStreamer.cpp MCWinEH.cpp + MCXCOFFObjectTargetWriter.cpp + MCXCOFFStreamer.cpp MachObjectWriter.cpp StringTableBuilder.cpp SubtargetFeature.cpp WasmObjectWriter.cpp WinCOFFObjectWriter.cpp + XCOFFObjectWriter.cpp ADDITIONAL_HEADER_DIRS ${LLVM_MAIN_INCLUDE_DIR}/llvm/MC diff --git a/llvm/lib/MC/MCAsmBackend.cpp b/llvm/lib/MC/MCAsmBackend.cpp --- a/llvm/lib/MC/MCAsmBackend.cpp +++ b/llvm/lib/MC/MCAsmBackend.cpp @@ -16,6 +16,7 @@ #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCWasmObjectWriter.h" #include "llvm/MC/MCWinCOFFObjectWriter.h" +#include "llvm/MC/MCXCOFFObjectWriter.h" #include #include #include @@ -43,6 +44,9 @@ case Triple::Wasm: return createWasmObjectWriter(cast(std::move(TW)), OS); + case Triple::XCOFF: + return createXCOFFObjectWriter( + cast(std::move(TW)), OS); default: llvm_unreachable("unexpected object format"); } diff --git a/llvm/lib/MC/MCAsmInfoXCOFF.cpp b/llvm/lib/MC/MCAsmInfoXCOFF.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/MC/MCAsmInfoXCOFF.cpp @@ -0,0 +1,18 @@ +//===- MC/MCAsmInfoXCOFF.cpp - XCOFF asm properties ------------ *- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCAsmInfoXCOFF.h" + +using namespace llvm; + +void MCAsmInfoXCOFF::anchor() {} + +MCAsmInfoXCOFF::MCAsmInfoXCOFF() { + IsLittleEndian = false; + HasDotTypeDotSizeDirective = false; +} diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp --- a/llvm/lib/MC/MCContext.cpp +++ b/llvm/lib/MC/MCContext.cpp @@ -26,6 +26,7 @@ #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCSectionWasm.h" +#include "llvm/MC/MCSectionXCOFF.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCSymbolCOFF.h" @@ -86,6 +87,7 @@ COFFAllocator.DestroyAll(); ELFAllocator.DestroyAll(); MachOAllocator.DestroyAll(); + XCOFFAllocator.DestroyAll(); MCSubtargetAllocator.DestroyAll(); UsedNames.clear(); @@ -107,6 +109,7 @@ ELFUniquingMap.clear(); COFFUniquingMap.clear(); WasmUniquingMap.clear(); + XCOFFUniquingMap.clear(); NextID.clear(); AllowTemporaryLabels = true; @@ -526,6 +529,38 @@ return Result; } +MCSectionXCOFF *MCContext::getXCOFFSection(StringRef Section, + XCOFF::StorageMappingClass SMC, + SectionKind Kind, + const char *BeginSymName) { + // Do the lookup. If we have a hit, return it. + auto IterBool = XCOFFUniquingMap.insert( + std::make_pair(XCOFFSectionKey{Section.str(), SMC}, nullptr)); + auto &Entry = *IterBool.first; + if (!IterBool.second) + return Entry.second; + + // Otherwise, return a new section. + StringRef CachedName = Entry.first.SectionName; + + MCSymbol *Begin = nullptr; + if (BeginSymName) + Begin = createTempSymbol(BeginSymName, false); + + MCSectionXCOFF *Result = new (XCOFFAllocator.Allocate()) + MCSectionXCOFF(CachedName, SMC, Kind, Begin); + Entry.second = Result; + + auto *F = new MCDataFragment(); + Result->getFragmentList().insert(Result->begin(), F); + F->setParent(Result); + + if (Begin) + Begin->setFragment(F); + + return Result; +} + MCSubtargetInfo &MCContext::getSubtargetCopy(const MCSubtargetInfo &STI) { return *new (MCSubtargetAllocator.Allocate()) MCSubtargetInfo(STI); } diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp --- a/llvm/lib/MC/MCObjectFileInfo.cpp +++ b/llvm/lib/MC/MCObjectFileInfo.cpp @@ -18,6 +18,7 @@ #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCSectionWasm.h" +#include "llvm/MC/MCSectionXCOFF.h" using namespace llvm; @@ -761,6 +762,13 @@ // TODO: Define more sections. } +void MCObjectFileInfo::initXCOFFMCObjectFileInfo(const Triple &T) { + // The default csect for program code. Functions without a specified section + // get placed into this csect. + TextSection = Ctx->getXCOFFSection( + ".text", XCOFF::StorageMappingClass::XMC_PR, SectionKind::getText()); +} + void MCObjectFileInfo::InitMCObjectFileInfo(const Triple &TheTriple, bool PIC, MCContext &ctx, bool LargeCodeModel) { @@ -809,8 +817,7 @@ break; case Triple::XCOFF: Env = IsXCOFF; - // TODO: Initialize MCObjectFileInfo for XCOFF format when - // MCSectionXCOFF is ready. + initXCOFFMCObjectFileInfo(TT); break; case Triple::UnknownObjectFormat: report_fatal_error("Cannot initialize MC for unknown object file format."); diff --git a/llvm/lib/MC/MCSectionXCOFF.cpp b/llvm/lib/MC/MCSectionXCOFF.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/MC/MCSectionXCOFF.cpp @@ -0,0 +1,33 @@ +//===- lib/MC/MCSectionXCOFF.cpp - XCOFF Code Section Representation ------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCSectionXCOFF.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +MCSectionXCOFF::~MCSectionXCOFF() = default; + +void MCSectionXCOFF::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T, + raw_ostream &OS, + const MCExpr *Subsection) const { + if (getKind().isText()) { + OS << "\t.csect " << getSectionName() << "[" + << "PR" + << "]" << '\n'; + return; + } + + report_fatal_error("Printing for this SectionKind is unimplemented."); +} + +bool MCSectionXCOFF::UseCodeAlign() const { return getKind().isText(); } + +bool MCSectionXCOFF::isVirtualSection() const { return !getKind().isCommon(); } diff --git a/llvm/lib/MC/MCXCOFFObjectTargetWriter.cpp b/llvm/lib/MC/MCXCOFFObjectTargetWriter.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/MC/MCXCOFFObjectTargetWriter.cpp @@ -0,0 +1,14 @@ +//===- MCXCOFFObjectTargetWriter.cpp - XCOFF Target Writer Subclass -------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCXCOFFObjectWriter.h" + +using namespace llvm; + +MCXCOFFObjectTargetWriter::MCXCOFFObjectTargetWriter() = default; +MCXCOFFObjectTargetWriter::~MCXCOFFObjectTargetWriter() = default; diff --git a/llvm/lib/MC/MCXCOFFStreamer.cpp b/llvm/lib/MC/MCXCOFFStreamer.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/MC/MCXCOFFStreamer.cpp @@ -0,0 +1,60 @@ +//===- lib/MC/MCXCOFFStreamer.cpp - XCOFF Object Output -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file assembles .s files and emits XCOFF .o object files. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCXCOFFStreamer.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +MCXCOFFStreamer::MCXCOFFStreamer(MCContext &Context, + std::unique_ptr MAB, + std::unique_ptr OW, + std::unique_ptr Emitter) + : MCObjectStreamer(Context, std::move(MAB), std::move(OW), + std::move(Emitter)) {} + +bool MCXCOFFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, + MCSymbolAttr Attribute) { + report_fatal_error("Symbol attributes not implemented for XCOFF."); + return false; +} + +void MCXCOFFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) { + report_fatal_error("Emiting common symbols not implemented for XCOFF."); +} + +void MCXCOFFStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment, + SMLoc Loc) { + report_fatal_error("Zero fill not implemented for XCOFF."); +} + +void MCXCOFFStreamer::EmitInstToData(const MCInst &Inst, + const MCSubtargetInfo &) { + report_fatal_error("Instruction emission not implemented for XCOFF."); +} + +MCStreamer *llvm::createXCOFFStreamer(MCContext &Context, + std::unique_ptr &&MAB, + std::unique_ptr &&OW, + std::unique_ptr &&CE, + bool RelaxAll) { + MCXCOFFStreamer *S = new MCXCOFFStreamer(Context, std::move(MAB), + std::move(OW), std::move(CE)); + if (RelaxAll) + S->getAssembler().setRelaxAll(true); + return S; +} diff --git a/llvm/lib/MC/XCOFFObjectWriter.cpp b/llvm/lib/MC/XCOFFObjectWriter.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/MC/XCOFFObjectWriter.cpp @@ -0,0 +1,92 @@ +//===-- lib/MC/XCOFFObjectWriter.cpp - XCOFF file writer ------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements XCOFF object file writer information. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCValue.h" +#include "llvm/MC/MCXCOFFObjectWriter.h" + +using namespace llvm; + +namespace { + +class XCOFFObjectWriter : public MCObjectWriter { + support::endian::Writer W; + std::unique_ptr TargetObjectWriter; + + virtual void executePostLayoutBinding(MCAssembler &, + const MCAsmLayout &) override; + + virtual void recordRelocation(MCAssembler &, const MCAsmLayout &, + const MCFragment *, const MCFixup &, MCValue, + uint64_t &) override; + + virtual uint64_t writeObject(MCAssembler &, const MCAsmLayout &) override; + +public: + XCOFFObjectWriter(std::unique_ptr MOTW, + raw_pwrite_stream &OS); +}; + +XCOFFObjectWriter::XCOFFObjectWriter( + std::unique_ptr MOTW, raw_pwrite_stream &OS) + : W(OS, support::big), TargetObjectWriter(std::move(MOTW)) {} + +void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &, + const MCAsmLayout &) { + // TODO Implement once we have sections and symbols to handle. +} + +void XCOFFObjectWriter::recordRelocation(MCAssembler &, const MCAsmLayout &, + const MCFragment *, const MCFixup &, + MCValue, uint64_t &) { + report_fatal_error("XCOFF relocations not supported."); +} + +uint64_t XCOFFObjectWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &) { + // We always emit a timestamp of 0 for reporducibility, so ensure incremental + // linking is not enabled. + if (Asm.isIncrementalLinkerCompatible()) + report_fatal_error("Incremental linking not supported for XCOFF."); + + uint64_t StartOffset = W.OS.tell(); + + // TODO FIXME Assign section numbers/finalize sections. + + // TODO FIXME Finialize symbols. + + // Magic. + W.write(0x01df); + // Number of sections. + W.write(0); + // Timestamp field. For reproducible output we write a 0, which represents no + // timestamp. + W.write(0); + // Byte Offset to the start of the symbol table. + W.write(0); + // Number of entries in the symbol table. + W.write(0); + // Size of the optional header. + W.write(0); + // Flags. + W.write(0); + + return W.OS.tell() - StartOffset; +} + +} // end anonymous namespace. + +std::unique_ptr +llvm::createXCOFFObjectWriter(std::unique_ptr MOTW, + raw_pwrite_stream &OS) { + return make_unique(std::move(MOTW), OS); +} diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/PowerPC/MCTargetDesc/CMakeLists.txt --- a/llvm/lib/Target/PowerPC/MCTargetDesc/CMakeLists.txt +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/CMakeLists.txt @@ -8,4 +8,5 @@ PPCPredicates.cpp PPCMachObjectWriter.cpp PPCELFObjectWriter.cpp + PPCXCOFFObjectWriter.cpp ) diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp @@ -229,6 +229,20 @@ Optional getFixupKind(StringRef Name) const override; }; + class XCOFFPPCAsmBackend : public PPCAsmBackend { + public: + XCOFFPPCAsmBackend(const Target &T, const Triple &TT) + : PPCAsmBackend(T, TT) {} + + std::unique_ptr + createObjectTargetWriter() const override { + if (TT.isArch64Bit()) + report_fatal_error("64-bit XCOFF object files are not supported yet."); + + return createPPCXCOFFObjectWriter(TT.isArch64Bit()); + } + }; + } // end anonymous namespace Optional ELFPPCAsmBackend::getFixupKind(StringRef Name) const { @@ -250,5 +264,8 @@ if (TT.isOSDarwin()) return new DarwinPPCAsmBackend(T, TT); + if (TT.isOSBinFormatXCOFF()) + return new XCOFFPPCAsmBackend(T, TT); + return new ELFPPCAsmBackend(T, TT); } diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.h b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.h --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.h +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.h @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// // -// This file contains the declaration of the MCAsmInfoDarwin class. +// This file contains the declarations of the PowerPC MCAsmInfo classes. // //===----------------------------------------------------------------------===// @@ -15,6 +15,7 @@ #include "llvm/MC/MCAsmInfoDarwin.h" #include "llvm/MC/MCAsmInfoELF.h" +#include "llvm/MC/MCAsmInfoXCOFF.h" namespace llvm { class Triple; @@ -33,6 +34,13 @@ explicit PPCELFMCAsmInfo(bool is64Bit, const Triple &); }; +class PPCXCOFFMCAsmInfo : public MCAsmInfoXCOFF { + virtual void anchor(); + +public: + explicit PPCXCOFFMCAsmInfo(bool is64Bit, const Triple &); +}; + } // namespace llvm #endif diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp @@ -81,3 +81,9 @@ UseIntegratedAssembler = true; } +void PPCXCOFFMCAsmInfo::anchor() {} + +PPCXCOFFMCAsmInfo::PPCXCOFFMCAsmInfo(bool is64Bit, const Triple &T) { + assert(!IsLittleEndian && "Little endian XCOFF not supported."); + CodePointerSize = CalleeSaveStackSlotSize = is64Bit ? 8 : 4; +} diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h @@ -51,6 +51,9 @@ std::unique_ptr createPPCMachObjectWriter(bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype); +/// Construct a PPC XCOFF object writer. +std::unique_ptr createPPCXCOFFObjectWriter(bool Is64Bit); + /// Returns true iff Val consists of one contiguous run of 1s with any number of /// 0s on either side. The 1s are allowed to wrap from LSB to MSB, so /// 0x000FFF0, 0x0000FFFF, and 0xFF0000FF are all runs. 0x0F0F0000 is not, diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp @@ -83,6 +83,8 @@ MCAsmInfo *MAI; if (TheTriple.isOSDarwin()) MAI = new PPCMCAsmInfoDarwin(isPPC64, TheTriple); + else if (TheTriple.isOSBinFormatXCOFF()) + MAI = new PPCXCOFFMCAsmInfo(isPPC64, TheTriple); else MAI = new PPCELFMCAsmInfo(isPPC64, TheTriple); @@ -235,6 +237,27 @@ } }; +class PPCTargetXCOFFStreamer : public PPCTargetStreamer { +public: + PPCTargetXCOFFStreamer(MCStreamer &S) : PPCTargetStreamer(S) {} + + void emitTCEntry(const MCSymbol &S) override { + report_fatal_error("TOC entry not supported yet."); + } + + void emitMachine(StringRef CPU) override { + llvm_unreachable("emit machine pseduo-op no tsupported on XCOFF."); + } + + void emitAbiVersion(int AbiVersion) override { + llvm_unreachable("Unknown pseudo-op: .abiversion"); + } + + void emitLocalEntry(MCSymbolELF *S, const MCExpr *LocalOffset) override { + llvm_unreachable("Unknown pseudo-op: .localentry"); + } +}; + } // end anonymous namespace static MCTargetStreamer *createAsmTargetStreamer(MCStreamer &S, @@ -249,6 +272,8 @@ const Triple &TT = STI.getTargetTriple(); if (TT.isOSBinFormatELF()) return new PPCTargetELFStreamer(S); + if (TT.isOSBinFormatXCOFF()) + return new PPCTargetXCOFFStreamer(S); return new PPCTargetMachOStreamer(S); } diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp @@ -0,0 +1,30 @@ +//===-- PPCXCOFFObjectWriter.cpp - PowerPC XCOFF Writer -------------------===// +// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "PPCMCTargetDesc.h" +#include "llvm/MC/MCXCOFFObjectWriter.h" + +using namespace llvm; + +namespace { +class PPCXCOFFObjectWriter : public MCXCOFFObjectTargetWriter { +public: + PPCXCOFFObjectWriter(); +}; +} // end anonymous namespace. + +PPCXCOFFObjectWriter::PPCXCOFFObjectWriter() = default; + +std::unique_ptr +llvm::createPPCXCOFFObjectWriter(bool Is64Bit) { + if (Is64Bit) + report_fatal_error("64-bit XCOFF object support not implemented yet."); + + return llvm::make_unique(); +} diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp --- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -158,6 +158,16 @@ void EmitStartOfAsmFile(Module &M) override; }; + class PPCAIXAsmPrinter : public PPCAsmPrinter { + public: + PPCAIXAsmPrinter(TargetMachine &TM, std::unique_ptr Streamer) + : PPCAsmPrinter(TM, std::move(Streamer)) {} + + StringRef getPassName() const override { + return "AIX PPC Assembly Printer"; + } + }; + } // end anonymous namespace void PPCAsmPrinter::PrintSymbolOperand(const MachineOperand &MO, @@ -1647,6 +1657,9 @@ std::unique_ptr &&Streamer) { if (tm.getTargetTriple().isMacOSX()) return new PPCDarwinAsmPrinter(tm, std::move(Streamer)); + if (tm.getTargetTriple().isOSAIX()) + return new PPCAIXAsmPrinter(tm, std::move(Streamer)); + return new PPCLinuxAsmPrinter(tm, std::move(Streamer)); } diff --git a/llvm/test/CodeGen/PowerPC/aix-xcoff-basic.ll b/llvm/test/CodeGen/PowerPC/aix-xcoff-basic.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/aix-xcoff-basic.ll @@ -0,0 +1,23 @@ +; RUN: llc -mtriple powerpc-ibm-aix-xcoff -filetype=obj -o %t.o < %s +; RUN: llvm-readobj --file-headers %t.o | FileCheck %s + +; RUN: not llc -mtriple powerpc64-ibm-aix-xcoff -filetype=obj < %s 2>&1 | \ +; RUN: FileCheck --check-prefix=64BIT %s + +target datalayout = "E-m:e-p:32:32-i64:64-n32" +target triple = "powerpc-unknown-aix" + +; CHECK: Format: aixcoff-rs6000 +; CHECK-NEXT: Arch: powerpc +; CHECK-NEXT: AddressSize: 32bit +; CHECK-NEXT: FileHeader { +; CHECK-NEXT: Magic: 0x1DF +; CHECK-NEXT: NumberOfSections: 0 +; CHECK-NEXT: TimeStamp: None (0x0) +; CHECK-NEXT: SymbolTableOffset: 0x0 +; CHECK-NEXT: SymbolTableEntries: 0 +; CHECK-NEXT: OptionalHeaderSize: 0x0 +; CHECK-NEXT: Flags: 0x0 +; CHECK-NEXT: } + +; 64BIT: LLVM ERROR: 64-bit XCOFF object files are not supported yet.