Index: llvm/include/llvm/MC/MCStreamer.h =================================================================== --- llvm/include/llvm/MC/MCStreamer.h +++ llvm/include/llvm/MC/MCStreamer.h @@ -19,6 +19,7 @@ #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCLinkerOptimizationHint.h" #include "llvm/MC/MCPseudoProbe.h" @@ -184,6 +185,47 @@ std::unique_ptr ConstantPools; }; +class MCTargetELFAttributesStreamer { +protected: + // This structure holds all attributes, accounting for their string/numeric + // value, so we can later emit them in declaration order, keeping all in + // the same vector. + struct AttributeItem { + enum { + HiddenAttribute = 0, + NumericAttribute, + TextAttribute, + NumericAndTextAttributes + } Type; + unsigned Tag; + unsigned IntValue; + std::string StringValue; + }; + + SmallVector Contents; + +private: + AttributeItem *getAttributeItem(unsigned Attribute); + +protected: + void setAttributeItem(unsigned Attribute, unsigned Value, + bool OverwriteExisting); + void setAttributeItem(unsigned Attribute, StringRef Value, + bool OverwriteExisting); + void setAttributeItems(unsigned Attribute, unsigned IntValue, + StringRef StringValue, bool OverwriteExisting); + size_t calculateContentSize(); + void emitAttributesSection(StringRef &Vendor, MCStreamer &Streamer, + const Twine &Section, unsigned Type, + MCSection *&AttributeSection); + void emitGNUAttributesSection(MCStreamer &Streamer, + MCSection *&AttributeSection) { + StringRef Vendor("gnu"); + emitAttributesSection(Vendor, Streamer, ".gnu.attributes", + ELF::SHT_GNU_ATTRIBUTES, AttributeSection); + } +}; + /// Streaming machine code generation interface. /// /// This interface is intended to provide a programmatic interface that is very Index: llvm/lib/MC/MCStreamer.cpp =================================================================== --- llvm/lib/MC/MCStreamer.cpp +++ llvm/lib/MC/MCStreamer.cpp @@ -27,9 +27,11 @@ #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSectionCOFF.h" +#include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCWin64EH.h" #include "llvm/MC/MCWinEH.h" +#include "llvm/Support/ARMBuildAttributes.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/LEB128.h" @@ -88,6 +90,156 @@ void MCTargetStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) {} +MCTargetELFAttributesStreamer::AttributeItem* MCTargetELFAttributesStreamer:: +getAttributeItem(unsigned Attribute) { + for (size_t i = 0; i < Contents.size(); ++i) + if (Contents[i].Tag == Attribute) + return &Contents[i]; + return nullptr; +} + +void MCTargetELFAttributesStreamer:: +setAttributeItem(unsigned Attribute, unsigned Value, bool OverwriteExisting) { + // Look for existing attribute item + if (AttributeItem *Item = getAttributeItem(Attribute)) { + if (!OverwriteExisting) + return; + Item->Type = AttributeItem::NumericAttribute; + Item->IntValue = Value; + return; + } + + // Create new attribute item + AttributeItem Item = {AttributeItem::NumericAttribute, Attribute, Value, + std::string(StringRef(""))}; + Contents.push_back(Item); +} + +void MCTargetELFAttributesStreamer:: +setAttributeItem(unsigned Attribute, StringRef Value, bool OverwriteExisting) { + // Look for existing attribute item + if (AttributeItem *Item = getAttributeItem(Attribute)) { + if (!OverwriteExisting) + return; + Item->Type = AttributeItem::TextAttribute; + Item->StringValue = std::string(Value); + return; + } + + // Create new attribute item + AttributeItem Item = {AttributeItem::TextAttribute, Attribute, 0, + std::string(Value)}; + Contents.push_back(Item); +} + +void MCTargetELFAttributesStreamer:: +setAttributeItems(unsigned Attribute, unsigned IntValue, + StringRef StringValue, bool OverwriteExisting) { + // Look for existing attribute item + if (AttributeItem *Item = getAttributeItem(Attribute)) { + if (!OverwriteExisting) + return; + Item->Type = AttributeItem::NumericAndTextAttributes; + Item->IntValue = IntValue; + Item->StringValue = std::string(StringValue); + return; + } + + // Create new attribute item + AttributeItem Item = {AttributeItem::NumericAndTextAttributes, Attribute, + IntValue, std::string(StringValue)}; + Contents.push_back(Item); +} + +size_t MCTargetELFAttributesStreamer::calculateContentSize() { + size_t Result = 0; + for (size_t i = 0; i < Contents.size(); ++i) { + AttributeItem item = Contents[i]; + switch (item.Type) { + case AttributeItem::HiddenAttribute: + break; + case AttributeItem::NumericAttribute: + Result += getULEB128Size(item.Tag); + Result += getULEB128Size(item.IntValue); + break; + case AttributeItem::TextAttribute: + Result += getULEB128Size(item.Tag); + Result += item.StringValue.size() + 1; // string + '\0' + break; + case AttributeItem::NumericAndTextAttributes: + Result += getULEB128Size(item.Tag); + Result += getULEB128Size(item.IntValue); + Result += item.StringValue.size() + 1; // string + '\0'; + break; + } + } + return Result; +} + +void MCTargetELFAttributesStreamer:: +emitAttributesSection(StringRef &Vendor, MCStreamer &Streamer, + const Twine &Section, unsigned Type, + MCSection *&AttributeSection) { + // + // [ "vendor-name" + // [ * + // | * 0 * + // | * 0 * + // ]+ + // ]* + + // Switch section to AttributeSection or get/create the section. + if (AttributeSection) { + Streamer.SwitchSection(AttributeSection); + } else { + AttributeSection = Streamer.getContext().getELFSection( + Section, Type, 0); + Streamer.SwitchSection(AttributeSection); + + // Format version + Streamer.emitInt8(0x41); + } + + // Vendor size + Vendor name + '\0' + const size_t VendorHeaderSize = 4 + Vendor.size() + 1; + + // Tag + Tag Size + const size_t TagHeaderSize = 1 + 4; + + const size_t ContentsSize = calculateContentSize(); + + Streamer.emitInt32(VendorHeaderSize + TagHeaderSize + ContentsSize); + Streamer.emitBytes(Vendor); + Streamer.emitInt8(0); // '\0' + + Streamer.emitInt8(ARMBuildAttrs::File); + Streamer.emitInt32(TagHeaderSize + ContentsSize); + + // Size should have been accounted for already, now + // emit each field as its type (ULEB or String) + for (size_t i = 0; i < Contents.size(); ++i) { + AttributeItem item = Contents[i]; + Streamer.emitULEB128IntValue(item.Tag); + switch (item.Type) { + default: llvm_unreachable("Invalid attribute type"); + case AttributeItem::NumericAttribute: + Streamer.emitULEB128IntValue(item.IntValue); + break; + case AttributeItem::TextAttribute: + Streamer.emitBytes(item.StringValue); + Streamer.emitInt8(0); // '\0' + break; + case AttributeItem::NumericAndTextAttributes: + Streamer.emitULEB128IntValue(item.IntValue); + Streamer.emitBytes(item.StringValue); + Streamer.emitInt8(0); // '\0' + break; + } + } + + Contents.clear(); +} + MCStreamer::MCStreamer(MCContext &Ctx) : Context(Ctx), CurrentWinFrameInfo(nullptr), CurrentProcWinFrameInfoStartIndex(0), UseAssemblerInfoForParsing(false) { Index: llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp =================================================================== --- llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp +++ llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp @@ -272,106 +272,16 @@ OS << '\n'; } -class ARMTargetELFStreamer : public ARMTargetStreamer { +class ARMTargetELFStreamer : public ARMTargetStreamer, + private MCTargetELFAttributesStreamer { private: - // This structure holds all attributes, accounting for - // their string/numeric value, so we can later emit them - // in declaration order, keeping all in the same vector - struct AttributeItem { - enum { - HiddenAttribute = 0, - NumericAttribute, - TextAttribute, - NumericAndTextAttributes - } Type; - unsigned Tag; - unsigned IntValue; - std::string StringValue; - - static bool LessTag(const AttributeItem &LHS, const AttributeItem &RHS) { - // The conformance tag must be emitted first when serialised - // into an object file. Specifically, the addenda to the ARM ABI - // states that (2.3.7.4): - // - // "To simplify recognition by consumers in the common case of - // claiming conformity for the whole file, this tag should be - // emitted first in a file-scope sub-subsection of the first - // public subsection of the attributes section." - // - // So it is special-cased in this comparison predicate when the - // attributes are sorted in finishAttributeSection(). - return (RHS.Tag != ARMBuildAttrs::conformance) && - ((LHS.Tag == ARMBuildAttrs::conformance) || (LHS.Tag < RHS.Tag)); - } - }; - StringRef CurrentVendor; unsigned FPU = ARM::FK_INVALID; ARM::ArchKind Arch = ARM::ArchKind::INVALID; ARM::ArchKind EmittedArch = ARM::ArchKind::INVALID; - SmallVector Contents; MCSection *AttributeSection = nullptr; - AttributeItem *getAttributeItem(unsigned Attribute) { - for (size_t i = 0; i < Contents.size(); ++i) - if (Contents[i].Tag == Attribute) - return &Contents[i]; - return nullptr; - } - - void setAttributeItem(unsigned Attribute, unsigned Value, - bool OverwriteExisting) { - // Look for existing attribute item - if (AttributeItem *Item = getAttributeItem(Attribute)) { - if (!OverwriteExisting) - return; - Item->Type = AttributeItem::NumericAttribute; - Item->IntValue = Value; - return; - } - - // Create new attribute item - AttributeItem Item = {AttributeItem::NumericAttribute, Attribute, Value, - std::string(StringRef(""))}; - Contents.push_back(Item); - } - - void setAttributeItem(unsigned Attribute, StringRef Value, - bool OverwriteExisting) { - // Look for existing attribute item - if (AttributeItem *Item = getAttributeItem(Attribute)) { - if (!OverwriteExisting) - return; - Item->Type = AttributeItem::TextAttribute; - Item->StringValue = std::string(Value); - return; - } - - // Create new attribute item - AttributeItem Item = {AttributeItem::TextAttribute, Attribute, 0, - std::string(Value)}; - Contents.push_back(Item); - } - - void setAttributeItems(unsigned Attribute, unsigned IntValue, - StringRef StringValue, bool OverwriteExisting) { - // Look for existing attribute item - if (AttributeItem *Item = getAttributeItem(Attribute)) { - if (!OverwriteExisting) - return; - Item->Type = AttributeItem::NumericAndTextAttributes; - Item->IntValue = IntValue; - Item->StringValue = std::string(StringValue); - return; - } - - // Create new attribute item - AttributeItem Item = {AttributeItem::NumericAndTextAttributes, Attribute, - IntValue, std::string(StringValue)}; - Contents.push_back(Item); - } - void emitArchDefaultAttributes(); void emitFPUDefaultAttributes(); @@ -1048,40 +958,7 @@ } } -size_t ARMTargetELFStreamer::calculateContentSize() const { - size_t Result = 0; - for (size_t i = 0; i < Contents.size(); ++i) { - AttributeItem item = Contents[i]; - switch (item.Type) { - case AttributeItem::HiddenAttribute: - break; - case AttributeItem::NumericAttribute: - Result += getULEB128Size(item.Tag); - Result += getULEB128Size(item.IntValue); - break; - case AttributeItem::TextAttribute: - Result += getULEB128Size(item.Tag); - Result += item.StringValue.size() + 1; // string + '\0' - break; - case AttributeItem::NumericAndTextAttributes: - Result += getULEB128Size(item.Tag); - Result += getULEB128Size(item.IntValue); - Result += item.StringValue.size() + 1; // string + '\0'; - break; - } - } - return Result; -} - void ARMTargetELFStreamer::finishAttributeSection() { - // - // [ "vendor-name" - // [ * - // | * 0 * - // | * 0 * - // ]+ - // ]* - if (FPU != ARM::FK_INVALID) emitFPUDefaultAttributes(); @@ -1091,60 +968,27 @@ if (Contents.empty()) return; - llvm::sort(Contents, AttributeItem::LessTag); - - ARMELFStreamer &Streamer = getStreamer(); - - // Switch to .ARM.attributes section - if (AttributeSection) { - Streamer.SwitchSection(AttributeSection); - } else { - AttributeSection = Streamer.getContext().getELFSection( - ".ARM.attributes", ELF::SHT_ARM_ATTRIBUTES, 0); - Streamer.SwitchSection(AttributeSection); - - // Format version - Streamer.emitInt8(0x41); - } - - // Vendor size + Vendor name + '\0' - const size_t VendorHeaderSize = 4 + CurrentVendor.size() + 1; - - // Tag + Tag Size - const size_t TagHeaderSize = 1 + 4; - - const size_t ContentsSize = calculateContentSize(); - - Streamer.emitInt32(VendorHeaderSize + TagHeaderSize + ContentsSize); - Streamer.emitBytes(CurrentVendor); - Streamer.emitInt8(0); // '\0' - - Streamer.emitInt8(ARMBuildAttrs::File); - Streamer.emitInt32(TagHeaderSize + ContentsSize); + auto LessTag = [](const AttributeItem &LHS, const AttributeItem &RHS) -> bool { + // The conformance tag must be emitted first when serialised into an + // object file. Specifically, the addenda to the ARM ABI states that + // (2.3.7.4): + // + // "To simplify recognition by consumers in the common case of claiming + // conformity for the whole file, this tag should be emitted first in a + // file-scope sub-subsection of the first public subsection of the + // attributes section." + // + // So it is special-cased in this comparison predicate when the + // attributes are sorted in finishAttributeSection(). + return (RHS.Tag != ARMBuildAttrs::conformance) && + ((LHS.Tag == ARMBuildAttrs::conformance) || (LHS.Tag < RHS.Tag)); + }; + llvm::sort(Contents, LessTag); - // Size should have been accounted for already, now - // emit each field as its type (ULEB or String) - for (size_t i = 0; i < Contents.size(); ++i) { - AttributeItem item = Contents[i]; - Streamer.emitULEB128IntValue(item.Tag); - switch (item.Type) { - default: llvm_unreachable("Invalid attribute type"); - case AttributeItem::NumericAttribute: - Streamer.emitULEB128IntValue(item.IntValue); - break; - case AttributeItem::TextAttribute: - Streamer.emitBytes(item.StringValue); - Streamer.emitInt8(0); // '\0' - break; - case AttributeItem::NumericAndTextAttributes: - Streamer.emitULEB128IntValue(item.IntValue); - Streamer.emitBytes(item.StringValue); - Streamer.emitInt8(0); // '\0' - break; - } - } + emitAttributesSection(CurrentVendor, getStreamer(), + ".ARM.attributes", ELF::SHT_ARM_ATTRIBUTES, + AttributeSection); - Contents.clear(); FPU = ARM::FK_INVALID; } Index: llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp =================================================================== --- llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp +++ llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "SystemZTargetStreamer.h" #include "MCTargetDesc/SystemZInstPrinter.h" #include "MCTargetDesc/SystemZMCAsmInfo.h" #include "MCTargetDesc/SystemZMCTargetDesc.h" @@ -405,6 +406,13 @@ SMLoc StartLoc, EndLoc; }; + SystemZTargetStreamer &getTargetStreamer() { + assert(getParser().getStreamer().getTargetStreamer() && + "do not have a target streamer"); + MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer(); + return static_cast(TS); + } + bool parseRegister(Register &Reg, bool RestoreOnFailure = false); bool parseIntegerRegister(Register &Reg, RegisterGroup Group); @@ -420,6 +428,7 @@ bool parseAddressRegister(Register &Reg); bool ParseDirectiveInsn(SMLoc L); + bool ParseGNUAttribute(SMLoc L); OperandMatchResultTy parseAddress(OperandVector &Operands, MemoryKind MemKind, @@ -1210,6 +1219,8 @@ if (IDVal == ".insn") return ParseDirectiveInsn(DirectiveID.getLoc()); + if (IDVal.startswith(".gnu_attribute")) + return ParseGNUAttribute(DirectiveID.getLoc()); return true; } @@ -1322,6 +1333,31 @@ return false; } +bool SystemZAsmParser::ParseGNUAttribute(SMLoc L) { + StringRef S(L.getPointer()); + MCAsmParser &Parser = getParser(); + SMLoc TagLoc; + TagLoc = Parser.getTok().getLoc(); + const AsmToken &Tok = Parser.getTok(); + if (Tok.isNot(AsmToken::Integer)) + return false; + int64_t Tag = Tok.getIntVal(); + Parser.Lex(); // Eat the Tag + Parser.Lex(); // Eat the comma + if (Tok.isNot(AsmToken::Integer)) + return false; + int64_t IntegerValue = Tok.getIntVal(); + Parser.Lex(); // Eat the IntegerValue + + // Tag_GNU_S390_ABI_Vector tag is '8' and can be 0, 1, or 2. + if (Tag != 8 || (IntegerValue < 0 || IntegerValue > 2)) + return false; + getTargetStreamer().emitGNUAttribute(Tag, IntegerValue); + + return true; +} + + bool SystemZAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc, bool RestoreOnFailure) { Register Reg; Index: llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp =================================================================== --- llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp +++ llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp @@ -9,6 +9,7 @@ #include "SystemZMCTargetDesc.h" #include "SystemZInstPrinter.h" #include "SystemZMCAsmInfo.h" +#include "SystemZTargetStreamer.h" #include "TargetInfo/SystemZTargetInfo.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCInstrInfo.h" @@ -182,6 +183,42 @@ return new SystemZInstPrinter(MAI, MII, MRI); } +class SystemZTargetAsmStreamer : public SystemZTargetStreamer { +formatted_raw_ostream &OS; +public: + SystemZTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS) + : SystemZTargetStreamer(S), OS(OS) {} + void emitGNUAttribute(unsigned Tag, unsigned Value) override { + OS << "\t.gnu_attribute " << Tag << ", " << Value << "\n"; + } + void finishAttributeSection() override {} +}; + +class SystemZTargetELFStreamer : public SystemZTargetStreamer, + private MCTargetELFAttributesStreamer { +public: + SystemZTargetELFStreamer(MCStreamer &S) : SystemZTargetStreamer(S) {} + void emitGNUAttribute(unsigned Tag, unsigned Value) override { + setAttributeItem(Tag, Value, /* OverwriteExisting= */ false); + } + void finishAttributeSection() override { + MCSection *AttributeSection = nullptr; + emitGNUAttributesSection(getStreamer(), AttributeSection); + } + void finish() override { finishAttributeSection(); } +}; + +static MCTargetStreamer * +createAsmTargetStreamer(MCStreamer &S, formatted_raw_ostream &OS, + MCInstPrinter *InstPrint, bool isVerboseAsm) { + return new SystemZTargetAsmStreamer(S, OS); +} + +static MCTargetStreamer * +createObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) { + return new SystemZTargetELFStreamer(S); +} + extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSystemZTargetMC() { // Register the MCAsmInfo. TargetRegistry::RegisterMCAsmInfo(getTheSystemZTarget(), @@ -210,4 +247,12 @@ // Register the MCInstPrinter. TargetRegistry::RegisterMCInstPrinter(getTheSystemZTarget(), createSystemZMCInstPrinter); + + // Register the asm streamer. + TargetRegistry::RegisterAsmTargetStreamer(getTheSystemZTarget(), + createAsmTargetStreamer); + + // Register the obj streamer + TargetRegistry::RegisterObjectTargetStreamer(getTheSystemZTarget(), + createObjectTargetStreamer); } Index: llvm/lib/Target/SystemZ/SystemZAsmPrinter.h =================================================================== --- llvm/lib/Target/SystemZ/SystemZAsmPrinter.h +++ llvm/lib/Target/SystemZ/SystemZAsmPrinter.h @@ -49,6 +49,7 @@ void LowerFENTRY_CALL(const MachineInstr &MI, SystemZMCInstLower &MCIL); void LowerSTACKMAP(const MachineInstr &MI); void LowerPATCHPOINT(const MachineInstr &MI, SystemZMCInstLower &Lower); + void emitAttributes(Module &M); }; } // end namespace llvm Index: llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp =================================================================== --- llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp +++ llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp @@ -15,6 +15,7 @@ #include "MCTargetDesc/SystemZInstPrinter.h" #include "SystemZConstantPoolValue.h" #include "SystemZMCInstLower.h" +#include "SystemZTargetStreamer.h" #include "TargetInfo/SystemZTargetInfo.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/CodeGen/MachineModuleInfoImpls.h" @@ -698,6 +699,63 @@ getSubtargetInfo()); } +// The *alignment* of 128-bit vector types is different between the +// software/hardware vector ABIs. +bool static isVectorOrVectorPtrType(Type *Ty) { + if (Ty->isVectorTy()) + return true; + if (auto *PTy = dyn_cast(Ty)) + return isVectorOrVectorPtrType(PTy->getElementType()); + return false; +} + +void SystemZAsmPrinter::emitAttributes(Module &M) { + bool HasVectorABI = false; + for (const GlobalValue &GV : M.global_values()) { + if (!GV.hasLocalLinkage() && (!GV.isDeclaration() || !GV.use_empty())) { + if (const Function *F = dyn_cast(&GV)) { + FunctionType *FTy = F->getFunctionType(); + if (isVectorOrVectorPtrType(FTy->getReturnType())) + HasVectorABI = true; + else { + for (auto ParamTy : FTy->params()) + if (isVectorOrVectorPtrType(ParamTy)) { + HasVectorABI = true; + break; + } + } + if (!HasVectorABI && FTy->isVarArg()) { + for (auto U : F->users()) { + if (auto *CI = dyn_cast(&*U)) { + for (const Use &Arg : CI->args()) + if (isVectorOrVectorPtrType(Arg->getType())) { + HasVectorABI = true; + break; + } + } + if (HasVectorABI) + break; + } + } + } + else if (const GlobalVariable *GVar = dyn_cast(&GV)) + if (isVectorOrVectorPtrType(GVar->getValueType())) + HasVectorABI = true; + + if (HasVectorABI) + break; + } + } + + if (HasVectorABI) { + bool HasVectorFeature = + TM.getMCSubtargetInfo()->getFeatureBits()[SystemZ::FeatureVector]; + SystemZTargetStreamer *SZTS = + static_cast(OutStreamer->getTargetStreamer()); + SZTS->emitGNUAttribute(8, HasVectorFeature ? 2 : 1); + } +} + // Convert a SystemZ-specific constant pool modifier into the associated // MCSymbolRefExpr variant kind. static MCSymbolRefExpr::VariantKind @@ -746,6 +804,7 @@ } void SystemZAsmPrinter::emitEndOfAsmFile(Module &M) { + emitAttributes(M); emitStackMaps(SM); } Index: llvm/lib/Target/SystemZ/SystemZTargetStreamer.h =================================================================== --- /dev/null +++ llvm/lib/Target/SystemZ/SystemZTargetStreamer.h @@ -0,0 +1,27 @@ +//=- SystemZTargetStreamer.h - SystemZ Target Streamer ----------*- 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_LIB_TARGET_SYSTEMZ_SYSTEMZTARGETSTREAMER_H +#define LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZTARGETSTREAMER_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/MC/MCStreamer.h" + +namespace llvm { + +class SystemZTargetStreamer : public MCTargetStreamer { +public: + SystemZTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {} + + virtual void emitGNUAttribute(unsigned Tag, unsigned Value) = 0; + virtual void finishAttributeSection() = 0; +}; + +} // end namespace llvm + +#endif // LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZTARGETSTREAMER_H Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-00.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-00.ll @@ -0,0 +1,14 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch13 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Call to external function with vector argument. +define internal void @fun() { +entry: + tail call void @foo(<4 x i32> zeroinitializer) + ret void +} + +declare void @foo(<4 x i32>) + +; CHECK: .gnu_attribute 8, 2 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-01.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-01.ll @@ -0,0 +1,16 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch13 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Call to external function with vector return value. +define internal void @fun() { +entry: + %indirect-arg-temp = alloca <4 x i32>, align 16 + %C = call <4 x i32> @foo() + store <4 x i32> %C, <4 x i32>* %indirect-arg-temp + ret void +} + +declare <4 x i32> @foo() + +; CHECK: .gnu_attribute 8, 2 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-02.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-02.ll @@ -0,0 +1,14 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch13 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Call to external function *without* vector arguments. +define internal void @fun() { +entry: + tail call void @foo(i64 0) + ret void +} + +declare void @foo(i64) + +; CHECK-NOT: .gnu_attribute 8 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-03.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-03.ll @@ -0,0 +1,11 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch13 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Defining globally visible function with vector arguments. +define <4 x i32> @fun(<4 x i32> %Arg) { +entry: + ret <4 x i32> %Arg +} + +; CHECK: .gnu_attribute 8, 2 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-04.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-04.ll @@ -0,0 +1,14 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch13 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Calling globally visible function with vector parameter. +define void @fun() { +entry: + tail call void @foo(<4 x i32> zeroinitializer) + ret void +} + +declare void @foo(<4 x i32>) + +; CHECK: .gnu_attribute 8, 2 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-05.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-05.ll @@ -0,0 +1,8 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch10 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Globally visible vector variable. +@VisibleVector = global <4 x i32> zeroinitializer + +; CHECK: .gnu_attribute 8, 1 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-06.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-06.ll @@ -0,0 +1,14 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch13 < %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Using external vector variable. +@ExtVector = external global <4 x i32> + +define void @fun() { +entry: + store <4 x i32> zeroinitializer, <4 x i32>* @ExtVector + ret void +} + +; CHECK: .gnu_attribute 8, 2 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-07.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-07.ll @@ -0,0 +1,14 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch13 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Using local vector variable. +@LocVector = internal global <4 x i32> zeroinitializer + +define void @fun() { +entry: + store volatile <4 x i32> zeroinitializer, <4 x i32>* @LocVector + ret void +} + +; CHECK-NOT: .gnu_attribute 8 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-08.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-08.ll @@ -0,0 +1,17 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch10 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Calling local function with vector return value. +define void @fun() { +entry: + %indirect-arg-temp = alloca <4 x i32>, align 16 + store <4 x i32> zeroinitializer, <4 x i32>* %indirect-arg-temp + call void @foo(<4 x i32>* nonnull %indirect-arg-temp) + ret void +} + +define internal void @foo(<4 x i32>*) { ret void } + +; CHECK-LABEL: fun: +; CHECK-NOT: .gnu_attribute 8 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-09.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-09.ll @@ -0,0 +1,14 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch10 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Call to vararg function *without* any vector argument. +define internal void @fun() { +entry: + call void (...) @foo() + ret void +} + +declare void @foo(...) + +; CHECK-NOT: .gnu_attribute 8 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-10.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-10.ll @@ -0,0 +1,14 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch13 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Call to vararg function with a vector argument. +define internal void @fun() { +entry: + call void (...) @foo(<2 x i64> zeroinitializer) + ret void +} + +declare void @foo(...) + +; CHECK: .gnu_attribute 8, 2 Index: llvm/test/MC/SystemZ/gnu-attributes.s =================================================================== --- /dev/null +++ llvm/test/MC/SystemZ/gnu-attributes.s @@ -0,0 +1,17 @@ +# RUN: llvm-mc -triple s390x-linux-gnu -filetype=asm %s | \ +# RUN: FileCheck %s --check-prefix=ASM +# RUN: llvm-mc -triple s390x-linux-gnu -filetype=obj %s | \ +# RUN: llvm-objdump --mcpu=z14 -D - | FileCheck %s --check-prefix=OBJ + +#ASM: .text +#ASM: .gnu_attribute 8, 2 + +#OBJ: 0000000000000000 <.gnu.attributes>: +#OBJ: 0: 41 00 00 00 +#OBJ: 4: 0f 67 +#OBJ: 6: 6e 75 00 01 +#OBJ: a: 00 00 +#OBJ: c: 00 07 +#OBJ: e: 08 02 + + .gnu_attribute 8, 2