diff --git a/llvm/include/llvm/MC/MCDirectives.h b/llvm/include/llvm/MC/MCDirectives.h index f8b7e05b3719b..3b9c4670399c9 100644 --- a/llvm/include/llvm/MC/MCDirectives.h +++ b/llvm/include/llvm/MC/MCDirectives.h @@ -48,6 +48,8 @@ enum MCSymbolAttr { MCSA_WeakDefAutoPrivate, ///< .weak_def_can_be_hidden (MachO) MCSA_WeakAntiDep, ///< .weak_anti_dep (COFF) MCSA_Memtag, ///< .memtag (ELF) + MCSA_OSLinkage, ///< symbol uses OS linkage (GOFF) + MCSA_XPLinkage, ///< symbol uses XP linkage (GOFF) }; enum MCDataRegionType { diff --git a/llvm/include/llvm/MC/MCGOFFAttributes.h b/llvm/include/llvm/MC/MCGOFFAttributes.h index c996f0cae2c69..e771f36f35346 100644 --- a/llvm/include/llvm/MC/MCGOFFAttributes.h +++ b/llvm/include/llvm/MC/MCGOFFAttributes.h @@ -80,6 +80,15 @@ struct PRAttr { uint32_t SortKey = 0; }; +// Attributes for ER symbols. +struct ERAttr { + GOFF::ESDExecutable Executable = GOFF::ESD_EXE_Unspecified; + GOFF::ESDBindingStrength BindingStrength = GOFF::ESD_BST_Strong; + GOFF::ESDLinkageType Linkage = GOFF::ESD_LT_XPLink; + GOFF::ESDAmode Amode; + GOFF::ESDBindingScope BindingScope = GOFF::ESD_BSC_Unspecified; +}; + // Predefined GOFF class names. constexpr StringLiteral CLASS_CODE = "C_CODE64"; constexpr StringLiteral CLASS_WSA = "C_WSA64"; diff --git a/llvm/include/llvm/MC/MCGOFFObjectWriter.h b/llvm/include/llvm/MC/MCGOFFObjectWriter.h index ec07637dd2847..90887b296d46f 100644 --- a/llvm/include/llvm/MC/MCGOFFObjectWriter.h +++ b/llvm/include/llvm/MC/MCGOFFObjectWriter.h @@ -14,6 +14,7 @@ namespace llvm { class MCObjectWriter; +class MCSectionGOFF; class raw_pwrite_stream; class MCGOFFObjectTargetWriter : public MCObjectTargetWriter { @@ -37,11 +38,16 @@ class GOFFObjectWriter : public MCObjectWriter { // The stream used to write the GOFF records. raw_pwrite_stream &OS; + // The RootSD section. + MCSectionGOFF *RootSD = nullptr; + public: GOFFObjectWriter(std::unique_ptr MOTW, raw_pwrite_stream &OS); ~GOFFObjectWriter() override; + void setRootSD(MCSectionGOFF *RootSD) { this->RootSD = RootSD; } + // Implementation of the MCObjectWriter interface. void recordRelocation(const MCFragment &F, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) override {} diff --git a/llvm/include/llvm/MC/MCGOFFStreamer.h b/llvm/include/llvm/MC/MCGOFFStreamer.h index 8888d9e7bdbb3..886efe10d45df 100644 --- a/llvm/include/llvm/MC/MCGOFFStreamer.h +++ b/llvm/include/llvm/MC/MCGOFFStreamer.h @@ -14,6 +14,7 @@ namespace llvm { class GOFFObjectWriter; +class MCSymbolGOFF; class MCGOFFStreamer : public MCObjectStreamer { @@ -24,13 +25,14 @@ class MCGOFFStreamer : public MCObjectStreamer { ~MCGOFFStreamer() override; + void finishImpl() override; + void changeSection(MCSection *Section, uint32_t Subsection = 0) override; GOFFObjectWriter &getWriter(); - bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override { - return false; - } + bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override; + void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, Align ByteAlignment) override {} }; diff --git a/llvm/include/llvm/MC/MCSymbolGOFF.h b/llvm/include/llvm/MC/MCSymbolGOFF.h index 11d4df4aea634..fb73a72975331 100644 --- a/llvm/include/llvm/MC/MCSymbolGOFF.h +++ b/llvm/include/llvm/MC/MCSymbolGOFF.h @@ -14,6 +14,7 @@ #define LLVM_MC_MCSYMBOLGOFF_H #include "llvm/BinaryFormat/GOFF.h" +#include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCGOFFAttributes.h" #include "llvm/MC/MCSectionGOFF.h" #include "llvm/MC/MCSymbol.h" @@ -23,30 +24,57 @@ namespace llvm { class MCSymbolGOFF : public MCSymbol { // Associated data area of the section. Needs to be emitted first. - MCSectionGOFF *ADA; + MCSectionGOFF *ADA = nullptr; - GOFF::LDAttr LDAttributes; + GOFF::ESDExecutable CodeData = GOFF::ESDExecutable::ESD_EXE_Unspecified; + GOFF::ESDLinkageType Linkage = GOFF::ESDLinkageType::ESD_LT_XPLink; enum SymbolFlags : uint16_t { - SF_LD = 0x01, // LD attributes are set. + SF_Hidden = 0x01, // Symbol is hidden, aka not exported. + SF_Weak = 0x02, // Symbol is weak. }; public: MCSymbolGOFF(const MCSymbolTableEntry *Name, bool IsTemporary) : MCSymbol(Name, IsTemporary) {} - void setLDAttributes(GOFF::LDAttr Attr) { - modifyFlags(SF_LD, SF_LD); - LDAttributes = Attr; - } - GOFF::LDAttr getLDAttributes() const { return LDAttributes; } - bool hasLDAttributes() const { return getFlags() & SF_LD; } - void setADA(MCSectionGOFF *AssociatedDataArea) { ADA = AssociatedDataArea; AssociatedDataArea->RequiresNonZeroLength = true; } MCSectionGOFF *getADA() const { return ADA; } + + bool isExternal() const { return IsExternal; } + void setExternal(bool Value) const { IsExternal = Value; } + + void setHidden(bool Value = true) { + modifyFlags(Value ? SF_Hidden : 0, SF_Hidden); + } + bool isHidden() const { return getFlags() & SF_Hidden; } + bool isExported() const { return !isHidden(); } + + void setWeak(bool Value = true) { modifyFlags(Value ? SF_Weak : 0, SF_Weak); } + bool isWeak() const { return getFlags() & SF_Weak; } + + void setCodeData(GOFF::ESDExecutable Value) { CodeData = Value; } + GOFF::ESDExecutable getCodeData() const { return CodeData; } + + void setLinkage(GOFF::ESDLinkageType Value) { Linkage = Value; } + GOFF::ESDLinkageType getLinkage() const { return Linkage; } + + GOFF::ESDBindingScope getBindingScope() const { + return (isExternal() || !isDefined()) ? isExported() + ? GOFF::ESD_BSC_ImportExport + : GOFF::ESD_BSC_Library + : GOFF::ESD_BSC_Section; + } + + GOFF::ESDBindingStrength getBindingStrength() const { + return isWeak() ? GOFF::ESDBindingStrength::ESD_BST_Weak + : GOFF::ESDBindingStrength::ESD_BST_Strong; + } + + bool setSymbolAttribute(MCSymbolAttr Attribute); }; } // end namespace llvm diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index ae681b9aebdfb..5edbc4caf3fae 100644 --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -2788,9 +2788,10 @@ void TargetLoweringObjectFileGOFF::getModuleMetadata(Module &M) { // Initialize the label for the text section. MCSymbolGOFF *TextLD = static_cast( getContext().getOrCreateSymbol(RootSD->getName())); - TextLD->setLDAttributes(GOFF::LDAttr{ - false, GOFF::ESD_EXE_CODE, GOFF::ESD_BST_Strong, GOFF::ESD_LT_XPLink, - GOFF::ESD_AMODE_64, GOFF::ESD_BSC_Section}); + TextLD->setCodeData(GOFF::ESD_EXE_CODE); + TextLD->setLinkage(GOFF::ESD_LT_XPLink); + TextLD->setExternal(false); + TextLD->setWeak(false); TextLD->setADA(ADAPR); TextSection->setBeginSymbol(TextLD); } diff --git a/llvm/lib/MC/CMakeLists.txt b/llvm/lib/MC/CMakeLists.txt index 70c4577aeec0a..1388f130bb806 100644 --- a/llvm/lib/MC/CMakeLists.txt +++ b/llvm/lib/MC/CMakeLists.txt @@ -50,6 +50,7 @@ add_llvm_component_library(LLVMMC MCSubtargetInfo.cpp MCSymbol.cpp MCSymbolELF.cpp + MCSymbolGOFF.cpp MCSymbolXCOFF.cpp MCTargetOptions.cpp MCTargetOptionsCommandFlags.cpp diff --git a/llvm/lib/MC/GOFFObjectWriter.cpp b/llvm/lib/MC/GOFFObjectWriter.cpp index a3eaaa743039d..fa4ca5465cece 100644 --- a/llvm/lib/MC/GOFFObjectWriter.cpp +++ b/llvm/lib/MC/GOFFObjectWriter.cpp @@ -266,11 +266,24 @@ class GOFFSymbol { BehavAttrs.setBindingScope(Attr.BindingScope); BehavAttrs.setAlignment(EDAttr.Alignment); } + + GOFFSymbol(StringRef Name, uint32_t EsdID, uint32_t ParentEsdID, + const GOFF::ERAttr &Attr) + : Name(Name.data(), Name.size()), EsdId(EsdID), ParentEsdId(ParentEsdID), + SymbolType(GOFF::ESD_ST_ExternalReference), + NameSpace(GOFF::ESD_NS_NormalName) { + BehavAttrs.setExecutable(Attr.Executable); + BehavAttrs.setBindingStrength(Attr.BindingStrength); + BehavAttrs.setLinkageType(Attr.Linkage); + BehavAttrs.setAmode(Attr.Amode); + BehavAttrs.setBindingScope(Attr.BindingScope); + } }; class GOFFWriter { GOFFOstream OS; MCAssembler &Asm; + MCSectionGOFF *RootSD; void writeHeader(); void writeSymbol(const GOFFSymbol &Symbol); @@ -279,16 +292,18 @@ class GOFFWriter { void defineSectionSymbols(const MCSectionGOFF &Section); void defineLabel(const MCSymbolGOFF &Symbol); + void defineExtern(const MCSymbolGOFF &Symbol); void defineSymbols(); public: - GOFFWriter(raw_pwrite_stream &OS, MCAssembler &Asm); + GOFFWriter(raw_pwrite_stream &OS, MCAssembler &Asm, MCSectionGOFF *RootSD); uint64_t writeObject(); }; } // namespace -GOFFWriter::GOFFWriter(raw_pwrite_stream &OS, MCAssembler &Asm) - : OS(OS), Asm(Asm) {} +GOFFWriter::GOFFWriter(raw_pwrite_stream &OS, MCAssembler &Asm, + MCSectionGOFF *RootSD) + : OS(OS), Asm(Asm), RootSD(RootSD) {} void GOFFWriter::defineSectionSymbols(const MCSectionGOFF &Section) { if (Section.isSD()) { @@ -325,12 +340,24 @@ void GOFFWriter::defineSectionSymbols(const MCSectionGOFF &Section) { void GOFFWriter::defineLabel(const MCSymbolGOFF &Symbol) { MCSectionGOFF &Section = static_cast(Symbol.getSection()); GOFFSymbol LD(Symbol.getName(), Symbol.getIndex(), Section.getOrdinal(), - Section.getEDAttributes().NameSpace, Symbol.getLDAttributes()); + Section.getEDAttributes().NameSpace, + GOFF::LDAttr{false, Symbol.getCodeData(), + Symbol.getBindingStrength(), Symbol.getLinkage(), + GOFF::ESD_AMODE_64, Symbol.getBindingScope()}); if (Symbol.getADA()) LD.ADAEsdId = Symbol.getADA()->getOrdinal(); + LD.Offset = Asm.getSymbolOffset(Symbol); writeSymbol(LD); } +void GOFFWriter::defineExtern(const MCSymbolGOFF &Symbol) { + GOFFSymbol ER(Symbol.getName(), Symbol.getIndex(), RootSD->getOrdinal(), + GOFF::ERAttr{Symbol.getCodeData(), Symbol.getBindingStrength(), + Symbol.getLinkage(), GOFF::ESD_AMODE_64, + Symbol.getBindingScope()}); + writeSymbol(ER); +} + void GOFFWriter::defineSymbols() { unsigned Ordinal = 0; // Process all sections. @@ -345,9 +372,13 @@ void GOFFWriter::defineSymbols() { if (Sym.isTemporary()) continue; auto &Symbol = static_cast(Sym); - if (Symbol.hasLDAttributes()) { + bool IsDefined = Symbol.isDefined(); + if (IsDefined && static_cast(Symbol.getSection()).isED()) { Symbol.setIndex(++Ordinal); defineLabel(Symbol); + } else if (!IsDefined) { + Symbol.setIndex(++Ordinal); + defineExtern(Symbol); } } } @@ -523,7 +554,7 @@ GOFFObjectWriter::GOFFObjectWriter( GOFFObjectWriter::~GOFFObjectWriter() = default; uint64_t GOFFObjectWriter::writeObject() { - uint64_t Size = GOFFWriter(OS, *Asm).writeObject(); + uint64_t Size = GOFFWriter(OS, *Asm, RootSD).writeObject(); return Size; } diff --git a/llvm/lib/MC/MCAsmInfoGOFF.cpp b/llvm/lib/MC/MCAsmInfoGOFF.cpp index 092736b991f93..4dc33943609db 100644 --- a/llvm/lib/MC/MCAsmInfoGOFF.cpp +++ b/llvm/lib/MC/MCAsmInfoGOFF.cpp @@ -21,7 +21,7 @@ using namespace llvm; MCAsmInfoGOFF::MCAsmInfoGOFF() { Data64bitsDirective = "\t.quad\t"; - HasDotTypeDotSizeDirective = false; + WeakRefDirective = "WXTRN"; PrivateGlobalPrefix = "L#"; PrivateLabelPrefix = "L#"; ZeroDirective = "\t.space\t"; diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp index 885fa55b65d50..7ff570c7df402 100644 --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -774,6 +774,9 @@ bool MCAsmStreamer::emitSymbolAttribute(MCSymbol *Symbol, // Assemblers currently do not support a .cold directive. case MCSA_Exported: // Non-AIX assemblers currently do not support exported visibility. + case MCSA_OSLinkage: + case MCSA_XPLinkage: + // Only for HLASM. return false; case MCSA_Memtag: OS << "\t.memtag\t"; diff --git a/llvm/lib/MC/MCELFStreamer.cpp b/llvm/lib/MC/MCELFStreamer.cpp index 1bc1b92610871..13a7f6d999e61 100644 --- a/llvm/lib/MC/MCELFStreamer.cpp +++ b/llvm/lib/MC/MCELFStreamer.cpp @@ -18,6 +18,7 @@ #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCELFObjectWriter.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCFixup.h" @@ -151,6 +152,8 @@ bool MCELFStreamer::emitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) { case MCSA_IndirectSymbol: case MCSA_Exported: case MCSA_WeakAntiDep: + case MCSA_OSLinkage: + case MCSA_XPLinkage: return false; case MCSA_NoDeadStrip: diff --git a/llvm/lib/MC/MCGOFFStreamer.cpp b/llvm/lib/MC/MCGOFFStreamer.cpp index ad6397bce70f0..51580e0063207 100644 --- a/llvm/lib/MC/MCGOFFStreamer.cpp +++ b/llvm/lib/MC/MCGOFFStreamer.cpp @@ -11,17 +11,35 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCGOFFStreamer.h" +#include "llvm/BinaryFormat/GOFF.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCGOFFObjectWriter.h" +#include "llvm/MC/MCObjectStreamer.h" +#include "llvm/MC/MCSymbolGOFF.h" #include "llvm/MC/TargetRegistry.h" using namespace llvm; +MCGOFFStreamer::MCGOFFStreamer(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)) {} + MCGOFFStreamer::~MCGOFFStreamer() = default; +void MCGOFFStreamer::finishImpl() { + getWriter().setRootSD(static_cast( + getContext().getObjectFileInfo()->getTextSection()) + ->getParent()); + MCObjectStreamer::finishImpl(); +} + GOFFObjectWriter &MCGOFFStreamer::getWriter() { return static_cast(getAssembler().getWriter()); } @@ -37,6 +55,11 @@ void MCGOFFStreamer::changeSection(MCSection *Section, uint32_t Subsection) { } } +bool MCGOFFStreamer::emitSymbolAttribute(MCSymbol *Sym, + MCSymbolAttr Attribute) { + return static_cast(Sym)->setSymbolAttribute(Attribute); +} + MCStreamer *llvm::createGOFFStreamer(MCContext &Context, std::unique_ptr &&MAB, std::unique_ptr &&OW, @@ -45,9 +68,3 @@ MCStreamer *llvm::createGOFFStreamer(MCContext &Context, new MCGOFFStreamer(Context, std::move(MAB), std::move(OW), std::move(CE)); return S; } -llvm::MCGOFFStreamer::MCGOFFStreamer(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)) {} diff --git a/llvm/lib/MC/MCMachOStreamer.cpp b/llvm/lib/MC/MCMachOStreamer.cpp index 2b7a248e6d109..b8e7772f4e16f 100644 --- a/llvm/lib/MC/MCMachOStreamer.cpp +++ b/llvm/lib/MC/MCMachOStreamer.cpp @@ -299,6 +299,8 @@ bool MCMachOStreamer::emitSymbolAttribute(MCSymbol *Sym, case MCSA_Exported: case MCSA_Memtag: case MCSA_WeakAntiDep: + case MCSA_OSLinkage: + case MCSA_XPLinkage: return false; case MCSA_Global: diff --git a/llvm/lib/MC/MCSymbolGOFF.cpp b/llvm/lib/MC/MCSymbolGOFF.cpp new file mode 100644 index 0000000000000..00479d22232ff --- /dev/null +++ b/llvm/lib/MC/MCSymbolGOFF.cpp @@ -0,0 +1,69 @@ +//===- MCSymbolGOFF.cpp - GOFF Symbol 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/MCSymbolGOFF.h" +#include "llvm/BinaryFormat/GOFF.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +bool MCSymbolGOFF::setSymbolAttribute(MCSymbolAttr Attribute) { + switch (Attribute) { + case MCSA_Invalid: + case MCSA_Cold: + case MCSA_ELF_TypeIndFunction: + case MCSA_ELF_TypeTLS: + case MCSA_ELF_TypeCommon: + case MCSA_ELF_TypeNoType: + case MCSA_ELF_TypeGnuUniqueObject: + case MCSA_LGlobal: + case MCSA_Extern: + case MCSA_Exported: + case MCSA_IndirectSymbol: + case MCSA_Internal: + case MCSA_LazyReference: + case MCSA_Local: + case MCSA_NoDeadStrip: + case MCSA_SymbolResolver: + case MCSA_AltEntry: + case MCSA_PrivateExtern: + case MCSA_Protected: + case MCSA_Reference: + case MCSA_WeakDefinition: + case MCSA_WeakDefAutoPrivate: + case MCSA_WeakAntiDep: + case MCSA_Memtag: + return false; + + case MCSA_ELF_TypeFunction: + setCodeData(GOFF::ESDExecutable::ESD_EXE_CODE); + break; + case MCSA_ELF_TypeObject: + setCodeData(GOFF::ESDExecutable::ESD_EXE_DATA); + break; + case MCSA_OSLinkage: + setLinkage(GOFF::ESDLinkageType::ESD_LT_OS); + break; + case MCSA_XPLinkage: + setLinkage(GOFF::ESDLinkageType::ESD_LT_XPLink); + break; + case MCSA_Global: + setExternal(true); + break; + case MCSA_Weak: + case MCSA_WeakReference: + setExternal(true); + setWeak(); + break; + case MCSA_Hidden: + setHidden(true); + break; + } + + return true; +} diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.cpp index 72bb37265259e..ddc897b0e8393 100644 --- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.cpp +++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.cpp @@ -8,12 +8,20 @@ #include "SystemZHLASMAsmStreamer.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/BinaryFormat/GOFF.h" +#include "llvm/MC/MCGOFFAttributes.h" +#include "llvm/MC/MCGOFFStreamer.h" +#include "llvm/MC/MCSymbolGOFF.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Signals.h" #include using namespace llvm; +void SystemZHLASMAsmStreamer::visitUsedSymbol(const MCSymbol &Sym) { + Assembler->registerSymbol(Sym); +} + void SystemZHLASMAsmStreamer::EmitEOL() { // Comments are emitted on a new line before the instruction. if (IsVerboseAsm) @@ -183,17 +191,81 @@ void SystemZHLASMAsmStreamer::emitInstruction(const MCInst &Inst, EmitEOL(); } +static void emitXATTR(raw_ostream &OS, StringRef Name, + GOFF::ESDLinkageType Linkage, + GOFF::ESDExecutable Executable, + GOFF::ESDBindingScope BindingScope) { + llvm::ListSeparator Sep(","); + OS << Name << " XATTR "; + OS << Sep << "LINKAGE(" << (Linkage == GOFF::ESD_LT_OS ? "OS" : "XPLINK") + << ")"; + if (Executable != GOFF::ESD_EXE_Unspecified) + OS << Sep << "REFERENCE(" + << (Executable == GOFF::ESD_EXE_CODE ? "CODE" : "DATA") << ")"; + if (BindingScope != GOFF::ESD_BSC_Unspecified) { + OS << Sep << "SCOPE("; + switch (BindingScope) { + case GOFF::ESD_BSC_Section: + OS << "SECTION"; + break; + case GOFF::ESD_BSC_Module: + OS << "MODULE"; + break; + case GOFF::ESD_BSC_Library: + OS << "LIBRARY"; + break; + case GOFF::ESD_BSC_ImportExport: + OS << "EXPORT"; + break; + default: + break; + } + OS << ')'; + } + OS << '\n'; +} + +static bool sameNameAsCSECT(MCSymbolGOFF *Sym) { + if (!Sym->isTemporary() && Sym->isDefined() && Sym->isInSection()) { + MCSectionGOFF &ED = static_cast(Sym->getSection()); + return ED.isED() && Sym->getName() == ED.getParent()->getName(); + } + return false; +} + void SystemZHLASMAsmStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) { + MCSymbolGOFF *Sym = static_cast(Symbol); + + MCStreamer::emitLabel(Sym, Loc); - MCStreamer::emitLabel(Symbol, Loc); + // Emit ENTRY statement only if not implied by CSECT. + bool EmitEntry = !sameNameAsCSECT(Sym); + + if (!Sym->isTemporary() && Sym->isDefined() && + static_cast(Sym->getSection()).isED()) { + if (EmitEntry) { + OS << " ENTRY " << Sym->getName(); + EmitEOL(); + } + + emitXATTR(OS, Sym->getName(), Sym->getLinkage(), Sym->getCodeData(), + Sym->getBindingScope()); + EmitEOL(); + } - Symbol->print(OS, MAI); // TODO Need to adjust this based on Label type - OS << " DS 0H"; - // TODO Update LabelSuffix in SystemZMCAsmInfoGOFF once tests have been - // moved to HLASM syntax. - // OS << MAI->getLabelSuffix(); - EmitEOL(); + if (EmitEntry) { + OS << Sym->getName() << " DS 0H"; + // TODO Update LabelSuffix in SystemZMCAsmInfoGOFF once tests have been + // moved to HLASM syntax. + // OS << MAI->getLabelSuffix(); + EmitEOL(); + } +} + +bool SystemZHLASMAsmStreamer::emitSymbolAttribute(MCSymbol *Sym, + MCSymbolAttr Attribute) { + return static_cast(Sym)->setSymbolAttribute(Attribute); } void SystemZHLASMAsmStreamer::emitRawTextImpl(StringRef String) { @@ -276,12 +348,29 @@ void SystemZHLASMAsmStreamer::emitValueImpl(const MCExpr *Value, unsigned Size, assert(getCurrentSectionOnly() && "Cannot emit contents before setting section!"); + MCStreamer::emitValueImpl(Value, Size, Loc); OS << " DC "; emitHLASMValueImpl(Value, Size, true); EmitEOL(); } -void SystemZHLASMAsmStreamer::emitEnd() { +void SystemZHLASMAsmStreamer::finishImpl() { + for (auto &Symbol : getAssembler().symbols()) { + if (Symbol.isTemporary()) + continue; + if (Symbol.isRegistered()) { + if (Symbol.isDefined()) + continue; + auto &Sym = static_cast(const_cast(Symbol)); + OS << " " << (Sym.isWeak() ? "WXTRN" : "EXTRN") << " " << Sym.getName(); + EmitEOL(); + emitXATTR(OS, Sym.getName(), Sym.getLinkage(), Sym.getCodeData(), + Sym.getBindingScope()); + EmitEOL(); + } + } + + // Finish the assembly output. OS << " END"; EmitEOL(); } diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h index 93b1ac4d901aa..1eb358d45e0f4 100644 --- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h +++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h @@ -28,6 +28,7 @@ #include "llvm/Support/FormattedStream.h" namespace llvm { +class MCSymbolGOFF; class SystemZHLASMAsmStreamer final : public MCStreamer { constexpr static size_t InstLimit = 80; @@ -100,14 +101,13 @@ class SystemZHLASMAsmStreamer final : public MCStreamer { /// @name MCStreamer Interface /// @{ + void visitUsedSymbol(const MCSymbol &Sym) override; void changeSection(MCSection *Section, uint32_t Subsection) override; void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override; void emitLabel(MCSymbol *Symbol, SMLoc Loc) override; - bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override { - return false; - } + bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override; void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, Align ByteAlignment) override {} @@ -122,7 +122,7 @@ class SystemZHLASMAsmStreamer final : public MCStreamer { bool Parens = false); /// @} - void emitEnd(); + void finishImpl() override; }; } // namespace llvm diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZTargetStreamer.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZTargetStreamer.cpp index 1a3e373f25374..eeaa7382ad761 100644 --- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZTargetStreamer.cpp +++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZTargetStreamer.cpp @@ -15,6 +15,7 @@ #include "SystemZTargetStreamer.h" #include "SystemZHLASMAsmStreamer.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCGOFFStreamer.h" #include "llvm/MC/MCObjectFileInfo.h" using namespace llvm; @@ -38,12 +39,6 @@ SystemZHLASMAsmStreamer &SystemZTargetHLASMStreamer::getHLASMStreamer() { return static_cast(getStreamer()); } -void SystemZTargetHLASMStreamer::emitExtern(StringRef Sym) { - getStreamer().emitRawText(Twine(" EXTRN ") + Twine(Sym)); -} - -void SystemZTargetHLASMStreamer::emitEnd() { getHLASMStreamer().emitEnd(); } - // HLASM statements can only perform a single operation at a time const MCExpr *SystemZTargetHLASMStreamer::createWordDiffExpr( MCContext &Ctx, const MCSymbol *Hi, const MCSymbol *Lo) { diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZTargetStreamer.h b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZTargetStreamer.h index 3fc09bc8c683a..4f9a4a0a97ed8 100644 --- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZTargetStreamer.h +++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZTargetStreamer.h @@ -20,6 +20,7 @@ #include namespace llvm { +class MCGOFFStreamer; class SystemZHLASMAsmStreamer; class SystemZTargetStreamer : public MCTargetStreamer { @@ -57,9 +58,6 @@ class SystemZTargetStreamer : public MCTargetStreamer { virtual void emitMachine(StringRef CPUOrCommand) {}; - virtual void emitExtern(StringRef Str) {}; - virtual void emitEnd() {}; - virtual const MCExpr *createWordDiffExpr(MCContext &Ctx, const MCSymbol *Hi, const MCSymbol *Lo) { return nullptr; @@ -80,8 +78,6 @@ class SystemZTargetHLASMStreamer : public SystemZTargetStreamer { SystemZTargetHLASMStreamer(MCStreamer &S, formatted_raw_ostream &OS) : SystemZTargetStreamer(S), OS(OS) {} SystemZHLASMAsmStreamer &getHLASMStreamer(); - void emitExtern(StringRef Sym) override; - void emitEnd() override; const MCExpr *createWordDiffExpr(MCContext &Ctx, const MCSymbol *Hi, const MCSymbol *Lo) override; }; diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp index e31d7c6a86476..8c41961c8b022 100644 --- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp +++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp @@ -26,6 +26,7 @@ #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/IR/Mangler.h" #include "llvm/IR/Module.h" +#include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInstBuilder.h" #include "llvm/MC/MCSectionELF.h" @@ -1114,9 +1115,6 @@ void SystemZAsmPrinter::emitEndOfAsmFile(Module &M) { emitIDRLSection(M); } emitAttributes(M); - // Emit the END instruction in case of HLASM output. This must be the last - // instruction in the source file. - getTargetStreamer()->emitEnd(); } void SystemZAsmPrinter::emitADASection() { @@ -1570,6 +1568,8 @@ void SystemZAsmPrinter::emitPPA2(Module &M) { // Make CELQSTRT symbol. const char *StartSymbolName = "CELQSTRT"; MCSymbol *CELQSTRT = OutContext.getOrCreateSymbol(StartSymbolName); + OutStreamer->emitSymbolAttribute(CELQSTRT, MCSA_OSLinkage); + OutStreamer->emitSymbolAttribute(CELQSTRT, MCSA_Global); // Create symbol and assign to class field for use in PPA1. PPA2Sym = OutContext.createTempSymbol("PPA2", false); diff --git a/llvm/test/CodeGen/SystemZ/zos-no-eh-label.ll b/llvm/test/CodeGen/SystemZ/zos-no-eh-label.ll index b28f0dd17599a..43ac737b29778 100644 --- a/llvm/test/CodeGen/SystemZ/zos-no-eh-label.ll +++ b/llvm/test/CodeGen/SystemZ/zos-no-eh-label.ll @@ -1,4 +1,4 @@ -; RUN: llc -mtriple s390x-ibm-zos < %s | FileCheck %s +; RUN: llc -mtriple s390x-ibm-zos -emit-gnuas-syntax-on-zos=false < %s | FileCheck %s define signext i32 @_Z9computeitv() personality ptr @__zos_cxx_personality_v2 { ret i32 0 diff --git a/llvm/test/CodeGen/SystemZ/zos-section-1.ll b/llvm/test/CodeGen/SystemZ/zos-section-1.ll index b98584df54d5a..3f2dfffabf0fa 100644 --- a/llvm/test/CodeGen/SystemZ/zos-section-1.ll +++ b/llvm/test/CodeGen/SystemZ/zos-section-1.ll @@ -104,26 +104,50 @@ entry: ; CHECK-NEXT: 000300 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 02 ; CHECK-NEXT: 000310 00 01 20 00 00 00 00 06 a3 85 a2 a3 7b c3 00 00 +; ESD record, type ER. +; The name is CELQSTRT. +; CHECK-NEXT: 000320 03 00 00 04 [[CELQSTRT:00 00 00 09]] [[ROOTSD]] 00 00 00 00 +; CHECK-NEXT: 000330 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000340 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 +; CHECK-NEXT: 000350 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 +; CHECK-NEXT: 000360 00 04 00 00 00 00 00 08 c3 c5 d3 d8 e2 e3 d9 e3 + +; ESD record, type LD. +; The name is me. +; CHECK-NEXT: 000370 03 00 00 02 [[ME:00 00 00 0a]] [[C_CODE64]] 00 00 00 00 +; CHECK-NEXT: 000380 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000390 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 +; CHECK-NEXT: 0003a0 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 02 +; CHECK-NEXT: 0003b0 00 04 20 00 00 00 00 02 94 85 00 00 00 00 00 00 + +; ESD record, type ER. +; The name is other. +; CHECK-NEXT: 0003c0 03 00 00 04 [[OTHER:00 00 00 0b]] [[ROOTSD]] 00 00 00 00 +; CHECK-NEXT: 0003d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 0003e0 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 +; CHECK-NEXT: 0003f0 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 +; CHECK-NEXT: 000400 00 04 20 00 00 00 00 05 96 a3 88 85 99 00 00 00 + ; Text record for the code section C_CODE64. ; The regular expression matches the lower byte of the length. -; CHECK-NEXT: 000320 03 11 00 00 [[C_CODE64]] 00 00 00 00 00 00 00 00 -; CHECK-NEXT: 000330 00 00 00 00 00 00 00 {{..}} 00 c3 00 c5 00 c5 00 f1 +; CHECK-NEXT: 000410 03 11 00 00 [[C_CODE64]] 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000420 00 00 00 00 00 00 00 {{..}} 00 c3 00 c5 00 c5 00 f1 ; Text record for the section .&ppa2. -; CHECK: 0003c0 03 10 00 00 [[PPA2]] 00 00 00 00 00 00 00 00 -; CHECK-NEXT: 0003d0 00 00 00 00 00 00 00 {{..}} {{.*}} +; CHECK: 0004b0 03 10 00 00 [[PPA2]] 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 0004c0 00 00 00 00 00 00 00 {{..}} {{.*}} ; Text record for the ADA section test#S. -; CHECK: 000410 03 10 00 00 [[TESTS]] 00 00 00 00 00 00 00 00 -; CHECK-NEXT: 000420 00 00 00 00 00 00 00 {{..}} {{.*}} +; CHECK: 000500 03 10 00 00 [[TESTS]] 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000510 00 00 00 00 00 00 00 {{..}} {{.*}} ; Text record for the section B_IDRL. -; CHECK: 000460 03 10 00 01 [[BIDRL]] 00 00 00 00 00 00 00 00 -; CHECK-NEXT: 000470 00 00 00 00 00 00 00 {{..}} {{.*}} +; CHECK: 000550 03 10 00 01 [[BIDRL]] 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000560 00 00 00 00 00 00 00 {{..}} {{.*}} ; End record. -; CHECK: 0004b0 03 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -; CHECK-NEXT: 0004c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -; CHECK-NEXT: 0004d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -; CHECK-NEXT: 0004e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -; CHECK-NEXT: 0004f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 0005a0 03 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 0005b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 0005c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 0005d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 0005e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 diff --git a/llvm/test/CodeGen/SystemZ/zos-section-2.ll b/llvm/test/CodeGen/SystemZ/zos-section-2.ll index 0f608c1206b96..d4d541fcc22dd 100644 --- a/llvm/test/CodeGen/SystemZ/zos-section-2.ll +++ b/llvm/test/CodeGen/SystemZ/zos-section-2.ll @@ -147,29 +147,37 @@ source_filename = "test.ll" ; CHECK-NEXT: 0004e0 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 02 ; CHECK-NEXT: 0004f0 00 01 20 00 00 00 00 06 a3 85 a2 a3 7b c3 00 00 +; ESD record, type ER. +; The name is CELQSTRT. +; CHECK-NEXT: 000500 03 00 00 04 [[CELQSTRT:00 00 00 0f]] [[ROOTSD]] 00 00 00 00 +; CHECK-NEXT: 000510 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000520 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 +; CHECK-NEXT: 000530 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 +; CHECK-NEXT: 000540 00 04 00 00 00 00 00 08 c3 c5 d3 d8 e2 e3 d9 e3 + ; Text record for the code section C_CODE64. ; The regular expression matches the lower byte of the length. -; CHECK-NEXT: 000500 03 10 00 00 [[C_CODE64]] 00 00 00 00 00 00 00 00 -; CHECK-NEXT: 000510 00 00 00 00 00 00 00 {{..}} {{.*}} +; CHECK-NEXT: 000550 03 10 00 00 [[C_CODE64]] 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000560 00 00 00 00 00 00 00 {{..}} {{.*}} ; Text record for the section .&ppa2. -; CHECK: 000550 03 10 00 00 [[PPA2]] 00 00 00 00 00 00 00 00 -; CHECK-NEXT: 000560 00 00 00 00 00 00 00 {{..}} {{.*}} +; CHECK: 0005a0 03 10 00 00 [[PPA2]] 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 0005b0 00 00 00 00 00 00 00 {{..}} {{.*}} ; Text record for the section data. ; Length is 4, and the content is 0x2a = 42. -; CHECK: 0005a0 03 10 00 00 [[DATA_PR]] 00 00 00 00 00 00 00 00 -; CHECK-NEXT: 0005b0 00 00 00 00 00 00 00 04 00 00 00 2a 00 00 00 00 +; CHECK: 0005f0 03 10 00 00 [[DATA_PR]] 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000600 00 00 00 00 00 00 00 04 00 00 00 2a 00 00 00 00 ; There is no text record for section bss! ; Text record for the section B_IDRL. -; CHECK: 0005f0 03 10 00 01 [[BIDRL]] 00 00 00 00 00 00 00 00 -; CHECK-NEXT: 000600 00 00 00 00 00 00 00 {{..}} {{.*}} +; CHECK: 000640 03 10 00 01 [[BIDRL]] 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000650 00 00 00 00 00 00 00 {{..}} {{.*}} ; End record. -; CHECK: 000640 03 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -; CHECK-NEXT: 000650 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -; CHECK-NEXT: 000660 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -; CHECK-NEXT: 000670 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -; CHECK-NEXT: 000680 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 000690 03 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 0006a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 0006b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 0006c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 0006d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 diff --git a/llvm/test/CodeGen/SystemZ/zos-symbol-1.ll b/llvm/test/CodeGen/SystemZ/zos-symbol-1.ll new file mode 100644 index 0000000000000..92cb6371a7c50 --- /dev/null +++ b/llvm/test/CodeGen/SystemZ/zos-symbol-1.ll @@ -0,0 +1,38 @@ +; RUN: llc <%s --mtriple s390x-ibm-zos -emit-gnuas-syntax-on-zos=false | FileCheck %s + +declare extern_weak void @other1(...) +declare void @other2(...) + +define internal void @me1() { +entry: + ret void +} + +define hidden void @me2() { +entry: + tail call void @other1() + ret void +} + +define default void @me3() { +entry: + tail call void @other2() + ret void +} + +; CHECK: ENTRY me1 +; CHECK-NEXT: me1 XATTR LINKAGE(XPLINK),REFERENCE(CODE),SCOPE(SECTION) + +; CHECK: ENTRY me2 +; CHECK-NEXT: me2 XATTR LINKAGE(XPLINK),REFERENCE(CODE),SCOPE(LIBRARY) + +; CHECK: ENTRY me3 +; CHECK-NEXT: me3 XATTR LINKAGE(XPLINK),REFERENCE(CODE),SCOPE(EXPORT) + +; CHECK: EXTRN CELQSTRT +; CHECK-NEXT: CELQSTRT XATTR LINKAGE(OS),SCOPE(EXPORT) +; CHECK-NEXT: WXTRN other1 +; CHECK-NEXT: other1 XATTR LINKAGE(XPLINK),SCOPE(EXPORT) +; CHECK-NEXT: EXTRN other2 +; CHECK-NEXT: other2 XATTR LINKAGE(XPLINK),SCOPE(EXPORT) +; CHECK-NEXT: END