Author: quic-areg Date: 2024-03-19T16:22:30-05:00 New Revision: 31f4b329c8234fab9afa59494d7f8bdaeaefeaad
URL: https://github.com/llvm/llvm-project/commit/31f4b329c8234fab9afa59494d7f8bdaeaefeaad DIFF: https://github.com/llvm/llvm-project/commit/31f4b329c8234fab9afa59494d7f8bdaeaefeaad.diff LOG: [Hexagon] ELF attributes for Hexagon (#85359) Defines a subset of attributes and emits them to a section called .hexagon.attributes. The current attributes recorded are the attributes needed by llvm-objdump to automatically determine target features and eliminate the need to manually pass features. Added: clang/test/Driver/hexagon-default-build-attributes.s llvm/include/llvm/Support/HexagonAttributeParser.h llvm/include/llvm/Support/HexagonAttributes.h llvm/lib/Support/HexagonAttributeParser.cpp llvm/lib/Support/HexagonAttributes.cpp llvm/test/CodeGen/Hexagon/build-attributes.ll llvm/test/MC/Hexagon/directive-attribute-err.s llvm/test/MC/Hexagon/directive-attribute.s llvm/test/MC/Hexagon/hexagon_attributes.s Modified: clang/lib/Driver/ToolChains/Clang.cpp llvm/include/llvm/BinaryFormat/ELF.h llvm/include/llvm/Object/ELFObjectFile.h llvm/lib/Object/ELF.cpp llvm/lib/Object/ELFObjectFile.cpp llvm/lib/ObjectYAML/ELFYAML.cpp llvm/lib/Support/CMakeLists.txt llvm/lib/Target/Hexagon/AsmParser/HexagonAsmParser.cpp llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp llvm/lib/Target/Hexagon/HexagonAsmPrinter.h llvm/lib/Target/Hexagon/HexagonTargetStreamer.h llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.cpp llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h llvm/test/tools/llvm-readobj/ELF/machine-specific-section-types.test llvm/tools/llvm-readobj/ELFDumper.cpp Removed: ################################################################################ diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 055884d275ce1b..bcdf2737bc7ae0 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -8481,6 +8481,14 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::riscv64: AddRISCVTargetArgs(Args, CmdArgs); break; + + case llvm::Triple::hexagon: + if (Args.hasFlag(options::OPT_mdefault_build_attributes, + options::OPT_mno_default_build_attributes, true)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-hexagon-add-build-attributes"); + } + break; } // Consume all the warning flags. Usually this would be handled more diff --git a/clang/test/Driver/hexagon-default-build-attributes.s b/clang/test/Driver/hexagon-default-build-attributes.s new file mode 100644 index 00000000000000..58f246c2f805da --- /dev/null +++ b/clang/test/Driver/hexagon-default-build-attributes.s @@ -0,0 +1,21 @@ +/// Enabled by default for assembly +// RUN: %clang --target=hexagon-unknown-elf -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix CHECK-ENABLED + +/// Can be forced on or off for assembly. +// RUN: %clang --target=hexagon-unknown-elf -### %s 2>&1 -mno-default-build-attributes \ +// RUN: | FileCheck %s -check-prefix CHECK-DISABLED +// RUN: %clang --target=hexagon-unknown-elf -### %s 2>&1 -mdefault-build-attributes \ +// RUN: | FileCheck %s -check-prefix CHECK-ENABLED + +/// Option ignored C/C++ (since we always emit hardware and ABI build attributes +/// during codegen). +// RUN: %clang --target=hexagon-unknown-elf -### -x c %s -mdefault-build-attributes 2>&1 \ +// RUN: | FileCheck %s -check-prefix CHECK-DISABLED-C +// RUN: %clang --target=hexagon-unknown-elf -### -x c++ %s -mdefault-build-attributes 2>&1 \ +// RUN: | FileCheck %s -check-prefix CHECK-DISABLED-C + +// CHECK-DISABLED-NOT: "-hexagon-add-build-attributes" +// CHECK-DISABLED-C-NOT: "-hexagon-add-build-attributes" +// CHECK-ENABLED: "-hexagon-add-build-attributes" +// CHECK-DISABLED-C: argument unused during compilation: '-mdefault-build-attributes' diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h index bace3a92677a82..877f3f7862c8ba 100644 --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -1141,6 +1141,8 @@ enum : unsigned { SHT_CSKY_ATTRIBUTES = 0x70000001U, + SHT_HEXAGON_ATTRIBUTES = 0x70000003U, + SHT_HIPROC = 0x7fffffff, // Highest processor arch-specific type. SHT_LOUSER = 0x80000000, // Lowest type reserved for applications. SHT_HIUSER = 0xffffffff // Highest type reserved for applications. diff --git a/llvm/include/llvm/Object/ELFObjectFile.h b/llvm/include/llvm/Object/ELFObjectFile.h index 1e73de9f08c19d..f57a7ab8882ad2 100644 --- a/llvm/include/llvm/Object/ELFObjectFile.h +++ b/llvm/include/llvm/Object/ELFObjectFile.h @@ -60,6 +60,7 @@ class ELFObjectFileBase : public ObjectFile { SubtargetFeatures getMIPSFeatures() const; SubtargetFeatures getARMFeatures() const; + SubtargetFeatures getHexagonFeatures() const; Expected<SubtargetFeatures> getRISCVFeatures() const; SubtargetFeatures getLoongArchFeatures() const; @@ -397,6 +398,9 @@ template <class ELFT> class ELFObjectFile : public ELFObjectFileBase { case ELF::EM_RISCV: Type = ELF::SHT_RISCV_ATTRIBUTES; break; + case ELF::EM_HEXAGON: + Type = ELF::SHT_HEXAGON_ATTRIBUTES; + break; default: return Error::success(); } diff --git a/llvm/include/llvm/Support/HexagonAttributeParser.h b/llvm/include/llvm/Support/HexagonAttributeParser.h new file mode 100644 index 00000000000000..1116dd42b1ad01 --- /dev/null +++ b/llvm/include/llvm/Support/HexagonAttributeParser.h @@ -0,0 +1,37 @@ +//===-- HexagonAttributeParser.h - Hexagon Attribute Parser -----*- 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_SUPPORT_HEXAGONATTRIBUTEPARSER_H +#define LLVM_SUPPORT_HEXAGONATTRIBUTEPARSER_H + +#include "llvm/Support/ELFAttributeParser.h" +#include "llvm/Support/HexagonAttributes.h" + +namespace llvm { +class HexagonAttributeParser : public ELFAttributeParser { + struct DisplayHandler { + HexagonAttrs::AttrType Attribute; + Error (HexagonAttributeParser::*Routine)(unsigned); + }; + + static const DisplayHandler DisplayRoutines[]; + + Error handler(uint64_t Tag, bool &Handled) override; + +public: + HexagonAttributeParser(ScopedPrinter *SP) + : ELFAttributeParser(SP, HexagonAttrs::getHexagonAttributeTags(), + "hexagon") {} + HexagonAttributeParser() + : ELFAttributeParser(HexagonAttrs::getHexagonAttributeTags(), "hexagon") { + } +}; + +} // namespace llvm + +#endif diff --git a/llvm/include/llvm/Support/HexagonAttributes.h b/llvm/include/llvm/Support/HexagonAttributes.h new file mode 100644 index 00000000000000..8a50d8993e633b --- /dev/null +++ b/llvm/include/llvm/Support/HexagonAttributes.h @@ -0,0 +1,32 @@ +//===-- HexagonAttributes.h - Qualcomm Hexagon Attributes -----------------===// +// +// 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_SUPPORT_HEXAGONATTRIBUTES_H +#define LLVM_SUPPORT_HEXAGONATTRIBUTES_H + +#include "llvm/Support/ELFAttributes.h" + +namespace llvm { +namespace HexagonAttrs { + +const TagNameMap &getHexagonAttributeTags(); + +enum AttrType : unsigned { + ARCH = 4, + HVXARCH = 5, + HVXIEEEFP = 6, + HVXQFLOAT = 7, + ZREG = 8, + AUDIO = 9, + CABAC = 10 +}; + +} // namespace HexagonAttrs +} // namespace llvm + +#endif diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp index 137f606dd2d46b..55dd0c8e06c092 100644 --- a/llvm/lib/Object/ELF.cpp +++ b/llvm/lib/Object/ELF.cpp @@ -251,7 +251,10 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) { } break; case ELF::EM_HEXAGON: - switch (Type) { STRINGIFY_ENUM_CASE(ELF, SHT_HEX_ORDERED); } + switch (Type) { + STRINGIFY_ENUM_CASE(ELF, SHT_HEX_ORDERED); + STRINGIFY_ENUM_CASE(ELF, SHT_HEXAGON_ATTRIBUTES); + } break; case ELF::EM_X86_64: switch (Type) { STRINGIFY_ENUM_CASE(ELF, SHT_X86_64_UNWIND); } diff --git a/llvm/lib/Object/ELFObjectFile.cpp b/llvm/lib/Object/ELFObjectFile.cpp index 33be48196ae7d2..efec612957de33 100644 --- a/llvm/lib/Object/ELFObjectFile.cpp +++ b/llvm/lib/Object/ELFObjectFile.cpp @@ -20,6 +20,7 @@ #include "llvm/Support/ARMAttributeParser.h" #include "llvm/Support/ARMBuildAttributes.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/HexagonAttributeParser.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/RISCVAttributeParser.h" #include "llvm/Support/RISCVAttributes.h" @@ -287,6 +288,81 @@ SubtargetFeatures ELFObjectFileBase::getARMFeatures() const { return Features; } +static std::optional<std::string> hexagonAttrToFeatureString(unsigned Attr) { + switch (Attr) { + case 5: + return "v5"; + case 55: + return "v55"; + case 60: + return "v60"; + case 62: + return "v62"; + case 65: + return "v65"; + case 67: + return "v67"; + case 68: + return "v68"; + case 69: + return "v69"; + case 71: + return "v71"; + case 73: + return "v73"; + default: + return {}; + } +} + +SubtargetFeatures ELFObjectFileBase::getHexagonFeatures() const { + SubtargetFeatures Features; + HexagonAttributeParser Parser; + if (Error E = getBuildAttributes(Parser)) { + // Return no attributes if none can be read. + // This behavior is important for backwards compatibility. + consumeError(std::move(E)); + return Features; + } + std::optional<unsigned> Attr; + + if ((Attr = Parser.getAttributeValue(HexagonAttrs::ARCH))) { + if (std::optional<std::string> FeatureString = + hexagonAttrToFeatureString(*Attr)) + Features.AddFeature(*FeatureString); + } + + if ((Attr = Parser.getAttributeValue(HexagonAttrs::HVXARCH))) { + std::optional<std::string> FeatureString = + hexagonAttrToFeatureString(*Attr); + // There is no corresponding hvx arch for v5 and v55. + if (FeatureString && *Attr >= 60) + Features.AddFeature("hvx" + *FeatureString); + } + + if ((Attr = Parser.getAttributeValue(HexagonAttrs::HVXIEEEFP))) + if (*Attr) + Features.AddFeature("hvx-ieee-fp"); + + if ((Attr = Parser.getAttributeValue(HexagonAttrs::HVXQFLOAT))) + if (*Attr) + Features.AddFeature("hvx-qfloat"); + + if ((Attr = Parser.getAttributeValue(HexagonAttrs::ZREG))) + if (*Attr) + Features.AddFeature("zreg"); + + if ((Attr = Parser.getAttributeValue(HexagonAttrs::AUDIO))) + if (*Attr) + Features.AddFeature("audio"); + + if ((Attr = Parser.getAttributeValue(HexagonAttrs::CABAC))) + if (*Attr) + Features.AddFeature("cabac"); + + return Features; +} + Expected<SubtargetFeatures> ELFObjectFileBase::getRISCVFeatures() const { SubtargetFeatures Features; unsigned PlatformFlags = getPlatformFlags(); @@ -349,6 +425,8 @@ Expected<SubtargetFeatures> ELFObjectFileBase::getFeatures() const { return getRISCVFeatures(); case ELF::EM_LOONGARCH: return getLoongArchFeatures(); + case ELF::EM_HEXAGON: + return getHexagonFeatures(); default: return SubtargetFeatures(); } diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp index 9c1a28db592a1c..045211c44b9079 100644 --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -716,6 +716,7 @@ void ScalarEnumerationTraits<ELFYAML::ELF_SHT>::enumeration( break; case ELF::EM_HEXAGON: ECase(SHT_HEX_ORDERED); + ECase(SHT_HEXAGON_ATTRIBUTES); break; case ELF::EM_X86_64: ECase(SHT_X86_64_UNWIND); diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt index b9c13c43e9a7c5..da2a4b4cdec568 100644 --- a/llvm/lib/Support/CMakeLists.txt +++ b/llvm/lib/Support/CMakeLists.txt @@ -188,6 +188,8 @@ add_llvm_component_library(LLVMSupport GlobPattern.cpp GraphWriter.cpp Hashing.cpp + HexagonAttributeParser.cpp + HexagonAttributes.cpp InitLLVM.cpp InstructionCost.cpp IntEqClasses.cpp diff --git a/llvm/lib/Support/HexagonAttributeParser.cpp b/llvm/lib/Support/HexagonAttributeParser.cpp new file mode 100644 index 00000000000000..2143162d11c79c --- /dev/null +++ b/llvm/lib/Support/HexagonAttributeParser.cpp @@ -0,0 +1,55 @@ +//===-- HexagonAttributeParser.cpp - Hexagon Attribute Parser -------------===// +// +// 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/Support/HexagonAttributeParser.h" + +using namespace llvm; + +const HexagonAttributeParser::DisplayHandler + HexagonAttributeParser::DisplayRoutines[] = { + { + HexagonAttrs::ARCH, + &ELFAttributeParser::integerAttribute, + }, + { + HexagonAttrs::HVXARCH, + &ELFAttributeParser::integerAttribute, + }, + { + HexagonAttrs::HVXIEEEFP, + &ELFAttributeParser::integerAttribute, + }, + { + HexagonAttrs::HVXQFLOAT, + &ELFAttributeParser::integerAttribute, + }, + { + HexagonAttrs::ZREG, + &ELFAttributeParser::integerAttribute, + }, + { + HexagonAttrs::AUDIO, + &ELFAttributeParser::integerAttribute, + }, + { + HexagonAttrs::CABAC, + &ELFAttributeParser::integerAttribute, + }}; + +Error HexagonAttributeParser::handler(uint64_t Tag, bool &Handled) { + Handled = false; + for (const auto &R : DisplayRoutines) { + if (uint64_t(R.Attribute) == Tag) { + if (Error E = (this->*R.Routine)(Tag)) + return E; + Handled = true; + break; + } + } + return Error::success(); +} diff --git a/llvm/lib/Support/HexagonAttributes.cpp b/llvm/lib/Support/HexagonAttributes.cpp new file mode 100644 index 00000000000000..165215c8fb676a --- /dev/null +++ b/llvm/lib/Support/HexagonAttributes.cpp @@ -0,0 +1,27 @@ +//===-- HexagonAttributes.cpp - Qualcomm Hexagon Attributes ---------------===// +// +// 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/Support/HexagonAttributes.h" + +using namespace llvm; +using namespace llvm::HexagonAttrs; + +static constexpr TagNameItem TagData[] = { + {ARCH, "Tag_arch"}, + {HVXARCH, "Tag_hvx_arch"}, + {HVXIEEEFP, "Tag_hvx_ieeefp"}, + {HVXQFLOAT, "Tag_hvx_qfloat"}, + {ZREG, "Tag_zreg"}, + {AUDIO, "Tag_audio"}, + {CABAC, "Tag_cabac"}, +}; + +constexpr TagNameMap HexagonAttributeTags{TagData}; +const TagNameMap &llvm::HexagonAttrs::getHexagonAttributeTags() { + return HexagonAttributeTags; +} diff --git a/llvm/lib/Target/Hexagon/AsmParser/HexagonAsmParser.cpp b/llvm/lib/Target/Hexagon/AsmParser/HexagonAsmParser.cpp index fd7d25fa16d1da..864591d4eb9552 100644 --- a/llvm/lib/Target/Hexagon/AsmParser/HexagonAsmParser.cpp +++ b/llvm/lib/Target/Hexagon/AsmParser/HexagonAsmParser.cpp @@ -43,6 +43,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" +#include "llvm/Support/HexagonAttributes.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/SourceMgr.h" @@ -79,7 +80,7 @@ static cl::opt<bool> ErrorNoncontigiousRegister( "merror-noncontigious-register", cl::desc("Error for register names that aren't contigious"), cl::init(false)); - +static cl::opt<bool> AddBuildAttributes("hexagon-add-build-attributes"); namespace { struct HexagonOperand; @@ -120,6 +121,9 @@ class HexagonAsmParser : public MCTargetAsmParser { SMLoc &EndLoc) override; bool ParseDirectiveSubsection(SMLoc L); bool ParseDirectiveComm(bool IsLocal, SMLoc L); + + bool parseDirectiveAttribute(SMLoc L); + bool RegisterMatchesArch(unsigned MatchNum) const; bool matchBundleOptions(); @@ -164,6 +168,9 @@ class HexagonAsmParser : public MCTargetAsmParser { Parser.addAliasForDirective(".word", ".4byte"); MCAsmParserExtension::Initialize(_Parser); + + if (AddBuildAttributes) + getTargetStreamer().emitTargetAttributes(*STI); } bool splitIdentifier(OperandVector &Operands); @@ -652,6 +659,56 @@ bool HexagonAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, return finishBundle(IDLoc, Out); return false; } +/// parseDirectiveAttribute +/// ::= .attribute int, int +/// ::= .attribute Tag_name, int +bool HexagonAsmParser::parseDirectiveAttribute(SMLoc L) { + MCAsmParser &Parser = getParser(); + int64_t Tag; + SMLoc TagLoc = Parser.getTok().getLoc(); + if (Parser.getTok().is(AsmToken::Identifier)) { + StringRef Name = Parser.getTok().getIdentifier(); + std::optional<unsigned> Ret = ELFAttrs::attrTypeFromString( + Name, HexagonAttrs::getHexagonAttributeTags()); + if (!Ret) + return Error(TagLoc, "attribute name not recognized: " + Name); + Tag = *Ret; + Parser.Lex(); + } else { + const MCExpr *AttrExpr; + + TagLoc = Parser.getTok().getLoc(); + if (Parser.parseExpression(AttrExpr)) + return true; + + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(AttrExpr); + if (check(!CE, TagLoc, "expected numeric constant")) + return true; + + Tag = CE->getValue(); + } + + if (Parser.parseComma()) + return true; + + // We currently only have integer values. + int64_t IntegerValue = 0; + SMLoc ValueExprLoc = Parser.getTok().getLoc(); + const MCExpr *ValueExpr; + if (Parser.parseExpression(ValueExpr)) + return true; + + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(ValueExpr); + if (!CE) + return Error(ValueExprLoc, "expected numeric constant"); + IntegerValue = CE->getValue(); + + if (Parser.parseEOL()) + return true; + + getTargetStreamer().emitAttribute(Tag, IntegerValue); + return false; +} /// ParseDirective parses the Hexagon specific directives bool HexagonAsmParser::ParseDirective(AsmToken DirectiveID) { @@ -664,6 +721,8 @@ bool HexagonAsmParser::ParseDirective(AsmToken DirectiveID) { return ParseDirectiveComm(false, DirectiveID.getLoc()); if (IDVal.lower() == ".subsection") return ParseDirectiveSubsection(DirectiveID.getLoc()); + if (IDVal == ".attribute") + return parseDirectiveAttribute(DirectiveID.getLoc()); return true; } diff --git a/llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp b/llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp index 4ee67cb05d4953..d2f64ac9e90b0b 100644 --- a/llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp +++ b/llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp @@ -17,6 +17,7 @@ #include "HexagonInstrInfo.h" #include "HexagonRegisterInfo.h" #include "HexagonSubtarget.h" +#include "HexagonTargetStreamer.h" #include "MCTargetDesc/HexagonInstPrinter.h" #include "MCTargetDesc/HexagonMCExpr.h" #include "MCTargetDesc/HexagonMCInstrInfo.h" @@ -46,6 +47,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" #include <algorithm> #include <cassert> #include <cstdint> @@ -775,6 +777,24 @@ void HexagonAsmPrinter::emitInstruction(const MachineInstr *MI) { OutStreamer->emitInstruction(MCB, getSubtargetInfo()); } +void HexagonAsmPrinter::emitStartOfAsmFile(Module &M) { + if (TM.getTargetTriple().isOSBinFormatELF()) + emitAttributes(); +} + +void HexagonAsmPrinter::emitEndOfAsmFile(Module &M) { + HexagonTargetStreamer &HTS = + static_cast<HexagonTargetStreamer &>(*OutStreamer->getTargetStreamer()); + if (TM.getTargetTriple().isOSBinFormatELF()) + HTS.finishAttributeSection(); +} + +void HexagonAsmPrinter::emitAttributes() { + HexagonTargetStreamer &HTS = + static_cast<HexagonTargetStreamer &>(*OutStreamer->getTargetStreamer()); + HTS.emitTargetAttributes(*TM.getMCSubtargetInfo()); +} + void HexagonAsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind) { static const int8_t NoopsInSledCount = 4; // We want to emit the following pattern: diff --git a/llvm/lib/Target/Hexagon/HexagonAsmPrinter.h b/llvm/lib/Target/Hexagon/HexagonAsmPrinter.h index 5cb1edf54d1a76..b555c885965036 100644 --- a/llvm/lib/Target/Hexagon/HexagonAsmPrinter.h +++ b/llvm/lib/Target/Hexagon/HexagonAsmPrinter.h @@ -29,6 +29,8 @@ class TargetMachine; class HexagonAsmPrinter : public AsmPrinter { const HexagonSubtarget *Subtarget = nullptr; + void emitAttributes(); + public: explicit HexagonAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer) @@ -68,6 +70,8 @@ class TargetMachine; const char *ExtraCode, raw_ostream &OS) override; bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &OS) override; + void emitStartOfAsmFile(Module &M) override; + void emitEndOfAsmFile(Module &M) override; }; } // end namespace llvm diff --git a/llvm/lib/Target/Hexagon/HexagonTargetStreamer.h b/llvm/lib/Target/Hexagon/HexagonTargetStreamer.h index ff84363106629f..a2f93d476bfe1b 100644 --- a/llvm/lib/Target/Hexagon/HexagonTargetStreamer.h +++ b/llvm/lib/Target/Hexagon/HexagonTargetStreamer.h @@ -24,6 +24,15 @@ class HexagonTargetStreamer : public MCTargetStreamer { virtual void emitLocalCommonSymbolSorted(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlign, unsigned AccessGranularity){}; + void finish() override {} + + virtual void finishAttributeSection() {} + + virtual void emitAttribute(unsigned Attribute, unsigned Value) {} + + void emitTargetAttributes(const MCSubtargetInfo &STI); + + virtual void reset() {} }; } diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.cpp index d1678fa0241ca8..22c82bf5ac1b40 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.cpp +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.cpp @@ -12,6 +12,8 @@ //===----------------------------------------------------------------------===// #include "MCTargetDesc/HexagonMCELFStreamer.h" +#include "HexagonTargetStreamer.h" +#include "MCTargetDesc/HexagonMCChecker.h" #include "MCTargetDesc/HexagonMCInstrInfo.h" #include "MCTargetDesc/HexagonMCShuffler.h" #include "llvm/ADT/StringRef.h" @@ -27,11 +29,13 @@ #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCSymbolELF.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/HexagonAttributes.h" #include "llvm/Support/MathExtras.h" #include <cassert> #include <cstdint> @@ -147,6 +151,63 @@ void HexagonMCELFStreamer::HexagonMCEmitLocalCommonSymbol(MCSymbol *Symbol, HexagonMCEmitCommonSymbol(Symbol, Size, ByteAlignment, AccessSize); } +static unsigned featureToArchVersion(unsigned Feature) { + switch (Feature) { + case Hexagon::ArchV5: + return 5; + case Hexagon::ArchV55: + return 55; + case Hexagon::ArchV60: + case Hexagon::ExtensionHVXV60: + return 60; + case Hexagon::ArchV62: + case Hexagon::ExtensionHVXV62: + return 62; + case Hexagon::ArchV65: + case Hexagon::ExtensionHVXV65: + return 65; + case Hexagon::ArchV66: + case Hexagon::ExtensionHVXV66: + return 66; + case Hexagon::ArchV67: + case Hexagon::ExtensionHVXV67: + return 67; + case Hexagon::ArchV68: + case Hexagon::ExtensionHVXV68: + return 68; + case Hexagon::ArchV69: + case Hexagon::ExtensionHVXV69: + return 69; + case Hexagon::ArchV71: + case Hexagon::ExtensionHVXV71: + return 71; + case Hexagon::ArchV73: + case Hexagon::ExtensionHVXV73: + return 73; + } + llvm_unreachable("Expected valid arch feature"); + return 0; +} + +void HexagonTargetStreamer::emitTargetAttributes(const MCSubtargetInfo &STI) { + auto Features = STI.getFeatureBits(); + unsigned Arch = featureToArchVersion(Hexagon_MC::getArchVersion(Features)); + std::optional<unsigned> HVXArch = Hexagon_MC::getHVXVersion(Features); + emitAttribute(HexagonAttrs::ARCH, Arch); + if (HVXArch) + emitAttribute(HexagonAttrs::HVXARCH, featureToArchVersion(*HVXArch)); + if (Features.test(Hexagon::ExtensionHVXIEEEFP)) + emitAttribute(HexagonAttrs::HVXIEEEFP, 1); + if (Features.test(Hexagon::ExtensionHVXQFloat)) + emitAttribute(HexagonAttrs::HVXQFLOAT, 1); + if (Features.test(Hexagon::ExtensionZReg)) + emitAttribute(HexagonAttrs::ZREG, 1); + if (Features.test(Hexagon::ExtensionAudio)) + emitAttribute(HexagonAttrs::AUDIO, 1); + if (Features.test(Hexagon::FeatureCabac)) + emitAttribute(HexagonAttrs::CABAC, 1); +} + namespace llvm { MCStreamer *createHexagonELFStreamer(Triple const &TT, MCContext &Context, std::unique_ptr<MCAsmBackend> MAB, diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp index 0740ac58a33813..dc8328a6705da8 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp @@ -35,6 +35,7 @@ #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/HexagonAttributes.h" #include "llvm/Support/raw_ostream.h" #include <cassert> #include <cstdint> @@ -224,12 +225,13 @@ bool isSlot0Only(unsigned units) { namespace { class HexagonTargetAsmStreamer : public HexagonTargetStreamer { + formatted_raw_ostream &OS; + bool IsVerboseAsm; + public: - HexagonTargetAsmStreamer(MCStreamer &S, - formatted_raw_ostream &OS, - bool isVerboseAsm, - MCInstPrinter &IP) - : HexagonTargetStreamer(S) {} + HexagonTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS, + bool IsVerboseAsm, MCInstPrinter &IP) + : HexagonTargetStreamer(S), OS(OS), IsVerboseAsm(IsVerboseAsm) {} void prettyPrintAsm(MCInstPrinter &InstPrinter, uint64_t Address, const MCInst &Inst, const MCSubtargetInfo &STI, @@ -266,6 +268,21 @@ class HexagonTargetAsmStreamer : public HexagonTargetStreamer { else OS << "\t}" << PacketBundle.second; } + + void finish() override { finishAttributeSection(); } + + void finishAttributeSection() override {} + + void emitAttribute(unsigned Attribute, unsigned Value) override { + OS << "\t.attribute\t" << Attribute << ", " << Twine(Value); + if (IsVerboseAsm) { + StringRef Name = ELFAttrs::attrTypeAsString( + Attribute, HexagonAttrs::getHexagonAttributeTags()); + if (!Name.empty()) + OS << "\t// " << Name; + } + OS << "\n"; + } }; class HexagonTargetELFStreamer : public HexagonTargetStreamer { @@ -279,7 +296,6 @@ class HexagonTargetELFStreamer : public HexagonTargetStreamer { MCA.setELFHeaderEFlags(Hexagon_MC::GetELFFlags(STI)); } - void emitCommonSymbolSorted(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment, unsigned AccessSize) override { @@ -297,6 +313,27 @@ class HexagonTargetELFStreamer : public HexagonTargetStreamer { HexagonELFStreamer.HexagonMCEmitLocalCommonSymbol( Symbol, Size, Align(ByteAlignment), AccessSize); } + + void finish() override { finishAttributeSection(); } + + void reset() override { AttributeSection = nullptr; } + +private: + MCSection *AttributeSection = nullptr; + + void finishAttributeSection() override { + MCELFStreamer &S = getStreamer(); + if (S.Contents.empty()) + return; + + S.emitAttributesSection("hexagon", ".hexagon.attributes", + ELF::SHT_HEXAGON_ATTRIBUTES, AttributeSection); + } + + void emitAttribute(uint32_t Attribute, uint32_t Value) override { + getStreamer().setAttributeItem(Attribute, Value, + /*OverwriteExisting=*/true); + } }; } // end anonymous namespace @@ -591,6 +628,29 @@ void Hexagon_MC::addArchSubtarget(MCSubtargetInfo const *STI, StringRef FS) { } } +std::optional<unsigned> +Hexagon_MC::getHVXVersion(const FeatureBitset &Features) { + for (auto Arch : {Hexagon::ExtensionHVXV73, Hexagon::ExtensionHVXV71, + Hexagon::ExtensionHVXV69, Hexagon::ExtensionHVXV68, + Hexagon::ExtensionHVXV67, Hexagon::ExtensionHVXV66, + Hexagon::ExtensionHVXV65, Hexagon::ExtensionHVXV62, + Hexagon::ExtensionHVXV60}) + if (Features.test(Arch)) + return Arch; + return {}; +} + +unsigned Hexagon_MC::getArchVersion(const FeatureBitset &Features) { + for (auto Arch : + {Hexagon::ArchV73, Hexagon::ArchV71, Hexagon::ArchV69, Hexagon::ArchV68, + Hexagon::ArchV67, Hexagon::ArchV66, Hexagon::ArchV65, Hexagon::ArchV62, + Hexagon::ArchV60, Hexagon::ArchV55, Hexagon::ArchV5}) + if (Features.test(Arch)) + return Arch; + llvm_unreachable("Expected arch v5-v73"); + return 0; +} + unsigned Hexagon_MC::GetELFFlags(const MCSubtargetInfo &STI) { return StringSwitch<unsigned>(STI.getCPU()) .Case("generic", llvm::ELF::EF_HEXAGON_MACH_V5) diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h index ffb81bca208df1..6110c7a93982ca 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h @@ -81,7 +81,11 @@ namespace Hexagon_MC { unsigned GetELFFlags(const MCSubtargetInfo &STI); llvm::ArrayRef<MCPhysReg> GetVectRegRev(); -} + + std::optional<unsigned> getHVXVersion(const FeatureBitset &Features); + + unsigned getArchVersion(const FeatureBitset &Features); + } // namespace Hexagon_MC MCCodeEmitter *createHexagonMCCodeEmitter(const MCInstrInfo &MCII, MCContext &MCT); diff --git a/llvm/test/CodeGen/Hexagon/build-attributes.ll b/llvm/test/CodeGen/Hexagon/build-attributes.ll new file mode 100644 index 00000000000000..48ee31a4d19bd6 --- /dev/null +++ b/llvm/test/CodeGen/Hexagon/build-attributes.ll @@ -0,0 +1,16 @@ +;; Generate build attributes from llc. + +; RUN: llc -mtriple=hexagon-unknown-elf \ +; RUN: -mattr=+hvxv73,+cabac,+v71,+hvx-ieee-fp,+hvx-length128b %s -o - | FileCheck %s + +; CHECK: .attribute 4, 71 // Tag_arch +; CHECK-NEXT: .attribute 5, 73 // Tag_hvx_arch +; CHECK-NEXT: .attribute 6, 1 // Tag_hvx_ieeefp +; CHECK-NEXT: .attribute 7, 1 // Tag_hvx_qfloat +; CHECK-NEXT: .attribute 8, 1 // Tag_zreg +; CHECK-NEXT: .attribute 10, 1 // Tag_cabac + +define i32 @addi(i32 %a) { + %1 = add i32 %a, 1 + ret i32 %1 +} \ No newline at end of file diff --git a/llvm/test/MC/Hexagon/directive-attribute-err.s b/llvm/test/MC/Hexagon/directive-attribute-err.s new file mode 100644 index 00000000000000..52b145b1ff28a1 --- /dev/null +++ b/llvm/test/MC/Hexagon/directive-attribute-err.s @@ -0,0 +1,24 @@ +/// attribute parsing error cases. + +// RUN: not llvm-mc -triple=hexagon -filetype=asm %s 2>&1 \ +// RUN: | FileCheck %s + + .attribute Tag_unknown_name, 0 +// CHECK: [[#@LINE-1]]:14: error: attribute name not recognized: Tag_unknown_name +// CHECK-NEXT: .attribute Tag_unknown_name + + .attribute [non_constant_expression], 0 +// CHECK: [[#@LINE-1]]:14: error: expected numeric constant +// CHECK-NEXT: .attribute [non_constant_expression], 0 + + .attribute 42, "forty two" +// CHECK: [[#@LINE-1]]:18: error: expected numeric constant +// CHECK-NEXT: .attribute 42, "forty two" + + .attribute Tag_arch, "v75" +// CHECK: [[#@LINE-1]]:24: error: expected numeric constant +// CHECK-NEXT: .attribute Tag_arch, "v75" + + .attribute 0 +// CHECK: :[[#@LINE-1]]:15: error: expected comma +// CHECK-NEXT: .attribute 0 diff --git a/llvm/test/MC/Hexagon/directive-attribute.s b/llvm/test/MC/Hexagon/directive-attribute.s new file mode 100644 index 00000000000000..d7c893061e18ab --- /dev/null +++ b/llvm/test/MC/Hexagon/directive-attribute.s @@ -0,0 +1,41 @@ +/// Check .attribute parsing. + +// RUN: llvm-mc -triple=hexagon -filetype=obj %s | llvm-readelf -A - | \ +// RUN: FileCheck %s --match-full-lines --implicit-check-not={{.}} + +.attribute 4, 71 // Tag_arch +.attribute Tag_cabac, 1 +.attribute Tag_hvx_arch, 68 +.attribute 7, 1 // Tag_hvx_qfloat + +// CHECK: BuildAttributes { +// CHECK-NEXT: FormatVersion: 0x41 +// CHECK-NEXT: Section 1 { +// CHECK-NEXT: SectionLength: 25 +// CHECK-NEXT: Vendor: hexagon +// CHECK-NEXT: Tag: Tag_File (0x1) +// CHECK-NEXT: Size: 13 +// CHECK-NEXT: FileAttributes { +// CHECK-NEXT: Attribute { +// CHECK-NEXT: Tag: 4 +// CHECK-NEXT: TagName: arch +// CHECK-NEXT: Value: 71 +// CHECK-NEXT: } +// CHECK-NEXT: Attribute { +// CHECK-NEXT: Tag: 10 +// CHECK-NEXT: TagName: cabac +// CHECK-NEXT: Value: 1 +// CHECK-NEXT: } +// CHECK-NEXT: Attribute { +// CHECK-NEXT: Tag: 5 +// CHECK-NEXT: TagName: hvx_arch +// CHECK-NEXT: Value: 68 +// CHECK-NEXT: } +// CHECK-NEXT: Attribute { +// CHECK-NEXT: Tag: 7 +// CHECK-NEXT: TagName: hvx_qfloat +// CHECK-NEXT: Value: 1 +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: } diff --git a/llvm/test/MC/Hexagon/hexagon_attributes.s b/llvm/test/MC/Hexagon/hexagon_attributes.s new file mode 100644 index 00000000000000..e90536030d977f --- /dev/null +++ b/llvm/test/MC/Hexagon/hexagon_attributes.s @@ -0,0 +1,94 @@ +/// Check that file attributes are recorded in a .hexagon.attributes section. + +q0&=vcmp.gt(v0.bf,v0.bf) // hvxv73, hvx-qfloat +r3:2=cround(r1:0,#0x0) // v67, audio +v3:0.w=vrmpyz(v0.b,r0.b) // hvxv73, zreg +v1:0.sf=vadd(v0.bf,v0.bf) // hvxv73, hvx-ieee-fp + +// RUN: llvm-mc --mattr=+v67,+hvxv73,+hvx-qfloat,+hvx-ieee-fp,+zreg,+audio %s \ +// RUN: -triple=hexagon -filetype=obj --hexagon-add-build-attributes -o %t.o + +// RUN: llvm-readelf -A %t.o | \ +// RUN: FileCheck %s --match-full-lines --implicit-check-not={{.}} --check-prefix=READELF + +/// llvm-objudmp should be able to determine subtarget features +/// without manually passing in features when an attribute section is present. +// RUN: llvm-objdump -d %t.o | FileCheck %s --check-prefix=OBJDUMP + +// RUN: llvm-mc --mattr=+v67,+hvxv73,+hvx-qfloat,+hvx-ieee-fp,+zreg,+audio %s \ +// RUN: -triple=hexagon -filetype=asm --hexagon-add-build-attributes | \ +// RUN: FileCheck %s --match-full-lines --implicit-check-not={{.}} --check-prefix=ASM + +// READELF: BuildAttributes { +// READELF-NEXT: FormatVersion: 0x41 +// READELF-NEXT: Section 1 { +// READELF-NEXT: SectionLength: 31 +// READELF-NEXT: Vendor: hexagon +// READELF-NEXT: Tag: Tag_File (0x1) +// READELF-NEXT: Size: 19 +// READELF-NEXT: FileAttributes { +// READELF-NEXT: Attribute { +// READELF-NEXT: Tag: 4 +// READELF-NEXT: TagName: arch +// READELF-NEXT: Value: 67 +// READELF-NEXT: } +// READELF-NEXT: Attribute { +// READELF-NEXT: Tag: 5 +// READELF-NEXT: TagName: hvx_arch +// READELF-NEXT: Value: 73 +// READELF-NEXT: } +// READELF-NEXT: Attribute { +// READELF-NEXT: Tag: 6 +// READELF-NEXT: TagName: hvx_ieeefp +// READELF-NEXT: Value: 1 +// READELF-NEXT: } +// READELF-NEXT: Attribute { +// READELF-NEXT: Tag: 7 +// READELF-NEXT: TagName: hvx_qfloat +// READELF-NEXT: Value: 1 +// READELF-NEXT: } +// READELF-NEXT: Attribute { +// READELF-NEXT: Tag: 8 +// READELF-NEXT: TagName: zreg +// READELF-NEXT: Value: 1 +// READELF-NEXT: } +// READELF-NEXT: Attribute { +// READELF-NEXT: Tag: 9 +// READELF-NEXT: TagName: audio +// READELF-NEXT: Value: 1 +// READELF-NEXT: } +// READELF-NEXT: Attribute { +// READELF-NEXT: Tag: 10 +// READELF-NEXT: TagName: cabac +// READELF-NEXT: Value: 1 +// READELF-NEXT: } +// READELF-NEXT: } +// READELF-NEXT: } +// READELF-NEXT: } + +// OBJDUMP: 1c80e0d0 { q0 &= vcmp.gt(v0.bf,v0.bf) } +// OBJDUMP-NEXT: 8ce0c042 { r3:2 = cround(r1:0,#0x0) } +// OBJDUMP-NEXT: 19e8c000 { v3:0.w = vrmpyz(v0.b,r0.b) } +// OBJDUMP-NEXT: 1d40e0c0 { v1:0.sf = vadd(v0.bf,v0.bf) } + +// ASM: .attribute 4, 67 // Tag_arch +// ASM-NEXT: .attribute 5, 73 // Tag_hvx_arch +// ASM-NEXT: .attribute 6, 1 // Tag_hvx_ieeefp +// ASM-NEXT: .attribute 7, 1 // Tag_hvx_qfloat +// ASM-NEXT: .attribute 8, 1 // Tag_zreg +// ASM-NEXT: .attribute 9, 1 // Tag_audio +// ASM-NEXT: .attribute 10, 1 // Tag_cabac +// ASM-NEXT: .text +// ASM-EMPTY: +// ASM-NEXT: { +// ASM-NEXT: q0 &= vcmp.gt(v0.bf,v0.bf) +// ASM-NEXT: } +// ASM-NEXT: { +// ASM-NEXT: r3:2 = cround(r1:0,#0) +// ASM-NEXT: } +// ASM-NEXT: { +// ASM-NEXT: v3:0.w = vrmpyz(v0.b,r0.b) +// ASM-NEXT: } +// ASM-NEXT: { +// ASM-NEXT: v1:0.sf = vadd(v0.bf,v0.bf) +// ASM-NEXT: } diff --git a/llvm/test/tools/llvm-readobj/ELF/machine-specific-section-types.test b/llvm/test/tools/llvm-readobj/ELF/machine-specific-section-types.test index 8ad50c5158dbc3..f65793c5bdc62d 100644 --- a/llvm/test/tools/llvm-readobj/ELF/machine-specific-section-types.test +++ b/llvm/test/tools/llvm-readobj/ELF/machine-specific-section-types.test @@ -70,6 +70,8 @@ # HEXAGON-LLVM: Name: hexagon_ordered # HEXAGON-LLVM: Type: SHT_HEX_ORDERED +# HEXAGON-LLVM: Name: .hexagon.attributes +# HEXAGON-LLVM: Type: SHT_HEXAGON_ATTRIBUTES # HEXAGON-GNU: hexagon_ordered HEX_ORDERED @@ -141,3 +143,5 @@ FileHeader: Sections: - Name: hexagon_ordered Type: SHT_HEX_ORDERED + - Name: .hexagon.attributes + Type: SHT_HEXAGON_ATTRIBUTES diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index e78732353cc877..d1c05f437042de 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -49,6 +49,7 @@ #include "llvm/Support/Format.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Support/HexagonAttributeParser.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/MSP430AttributeParser.h" #include "llvm/Support/MSP430Attributes.h" @@ -2824,6 +2825,11 @@ template <typename ELFT> void ELFDumper<ELFT>::printLoadName() { template <class ELFT> void ELFDumper<ELFT>::printArchSpecificInfo() { switch (Obj.getHeader().e_machine) { + case EM_HEXAGON: + printAttributes(ELF::SHT_HEXAGON_ATTRIBUTES, + std::make_unique<HexagonAttributeParser>(&W), + llvm::endianness::little); + break; case EM_ARM: if (Obj.isLE()) printAttributes(ELF::SHT_ARM_ATTRIBUTES, _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits