diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -880,6 +880,8 @@ SHT_MSP430_ATTRIBUTES = 0x70000003U, + SHT_RISCV_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 --- a/llvm/include/llvm/Object/ELFObjectFile.h +++ b/llvm/include/llvm/Object/ELFObjectFile.h @@ -371,7 +371,8 @@ return SectionsOrErr.takeError(); for (const Elf_Shdr &Sec : *SectionsOrErr) { - if (Sec.sh_type == ELF::SHT_ARM_ATTRIBUTES) { + if (Sec.sh_type == ELF::SHT_ARM_ATTRIBUTES || + Sec.sh_type == ELF::SHT_RISCV_ATTRIBUTES) { auto ErrorOrContents = EF.getSectionContents(&Sec); if (!ErrorOrContents) return ErrorOrContents.takeError(); diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp --- a/llvm/lib/Object/ELF.cpp +++ b/llvm/lib/Object/ELF.cpp @@ -223,6 +223,9 @@ STRINGIFY_ENUM_CASE(ELF, SHT_MIPS_ABIFLAGS); } break; + case ELF::EM_RISCV: + switch (Type) { STRINGIFY_ENUM_CASE(ELF, SHT_RISCV_ATTRIBUTES); } + break; default: break; } diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -500,6 +500,8 @@ ECase(SHT_MIPS_DWARF); ECase(SHT_MIPS_ABIFLAGS); break; + case ELF::EM_RISCV: + ECase(SHT_RISCV_ATTRIBUTES); default: // Nothing to do. break; diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -11,6 +11,7 @@ #include "MCTargetDesc/RISCVMCTargetDesc.h" #include "MCTargetDesc/RISCVTargetStreamer.h" #include "TargetInfo/RISCVTargetInfo.h" +#include "Utils/RISCVAttributes.h" #include "Utils/RISCVBaseInfo.h" #include "Utils/RISCVMatInt.h" #include "llvm/ADT/STLExtras.h" @@ -144,6 +145,7 @@ bool parseOperand(OperandVector &Operands, StringRef Mnemonic); bool parseDirectiveOption(); + bool parseDirectiveAttribute(); void setFeatureBits(uint64_t Feature, StringRef FeatureString) { if (!(getSTI().getFeatureBits()[Feature])) { @@ -1569,6 +1571,8 @@ if (IDVal == ".option") return parseDirectiveOption(); + else if (IDVal == ".attribute") + return parseDirectiveAttribute(); return true; } @@ -1667,6 +1671,81 @@ return false; } +/// parseDirectiveAttribute +/// ::= .attribute int, int [, "str"] +/// ::= .attribute Tag_name, int [, "str"] +bool RISCVAsmParser::parseDirectiveAttribute() { + MCAsmParser &Parser = getParser(); + int64_t Tag; + SMLoc TagLoc; + TagLoc = Parser.getTok().getLoc(); + if (Parser.getTok().is(AsmToken::Identifier)) { + StringRef Name = Parser.getTok().getIdentifier(); + Tag = RISCVAttrs::AttrTypeFromString(Name); + if (Tag == -1) { + Error(TagLoc, "attribute name not recognised: " + Name); + return false; + } + Parser.Lex(); + } else { + const MCExpr *AttrExpr; + + TagLoc = Parser.getTok().getLoc(); + if (Parser.parseExpression(AttrExpr)) + return true; + + const MCConstantExpr *CE = dyn_cast(AttrExpr); + if (check(!CE, TagLoc, "expected numeric constant")) + return true; + + Tag = CE->getValue(); + } + + if (Parser.parseToken(AsmToken::Comma, "comma expected")) + return true; + + StringRef StringValue = ""; + bool IsStringValue = false; + + int64_t IntegerValue = 0; + bool IsIntegerValue = false; + + if (Tag == RISCVAttrs::Arch) + IsStringValue = true; + else + IsIntegerValue = true; + + if (IsIntegerValue) { + const MCExpr *ValueExpr; + SMLoc ValueExprLoc = Parser.getTok().getLoc(); + if (Parser.parseExpression(ValueExpr)) + return true; + + const MCConstantExpr *CE = dyn_cast(ValueExpr); + if (!CE) + return Error(ValueExprLoc, "expected numeric constant"); + IntegerValue = CE->getValue(); + } + + if (IsStringValue) { + if (Parser.getTok().isNot(AsmToken::String)) + return Error(Parser.getTok().getLoc(), "bad string constant"); + + StringValue = Parser.getTok().getStringContents(); + Parser.Lex(); + } + + if (Parser.parseToken(AsmToken::EndOfStatement, + "unexpected token in '.attribute' directive")) + return true; + + if (IsIntegerValue) + getTargetStreamer().emitAttribute(Tag, IntegerValue); + else if (IsStringValue) + getTargetStreamer().emitTextAttribute(Tag, StringValue); + return false; +} + void RISCVAsmParser::emitToStreamer(MCStreamer &S, const MCInst &Inst) { MCInst CInst; bool Res = compressInst(CInst, Inst, getSTI(), S.getContext()); diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h @@ -15,6 +15,90 @@ namespace llvm { class RISCVTargetELFStreamer : public RISCVTargetStreamer { +private: + struct AttributeItem { + enum { + HiddenAttribute = 0, + NumericAttribute, + TextAttribute, + NumericAndTextAttributes + } Type; + unsigned Tag; + unsigned IntValue; + std::string StringValue; + }; + + StringRef CurrentVendor; + 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 emitAttribute(unsigned Attribute, unsigned Value) override; + void emitTextAttribute(unsigned Attribute, StringRef String) override; + void emitIntTextAttribute(unsigned Attribute, unsigned IntValue, + StringRef StringValue) override; + void finishAttributeSection() override; + size_t calculateContentSize() const; + public: MCELFStreamer &getStreamer(); RISCVTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI); diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp @@ -15,14 +15,17 @@ #include "RISCVMCTargetDesc.h" #include "Utils/RISCVBaseInfo.h" #include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/LEB128.h" using namespace llvm; // This part is for ELF object output. RISCVTargetELFStreamer::RISCVTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI) - : RISCVTargetStreamer(S) { + : RISCVTargetStreamer(S), CurrentVendor("riscv") { MCAssembler &MCA = getStreamer().getAssembler(); const FeatureBitset &Features = STI.getFeatureBits(); auto &MAB = static_cast(MCA.getBackend()); @@ -66,3 +69,101 @@ void RISCVTargetELFStreamer::emitDirectiveOptionNoRVC() {} void RISCVTargetELFStreamer::emitDirectiveOptionRelax() {} void RISCVTargetELFStreamer::emitDirectiveOptionNoRelax() {} + +void RISCVTargetELFStreamer::emitAttribute(unsigned Attribute, unsigned Value) { + setAttributeItem(Attribute, Value, /*OverwriteExisting=*/true); +} + +void RISCVTargetELFStreamer::emitTextAttribute(unsigned Attribute, + StringRef String) { + setAttributeItem(Attribute, String, /* OverwriteExisting= */ true); +} + +void RISCVTargetELFStreamer::emitIntTextAttribute(unsigned Attribute, + unsigned IntValue, + StringRef StringValue) { + setAttributeItems(Attribute, IntValue, StringValue, + /* OverwriteExisting= */ true); +} + +void RISCVTargetELFStreamer::finishAttributeSection() { + if (Contents.empty()) + return; + + if (AttributeSection) { + Streamer.SwitchSection(AttributeSection); + } else { + MCAssembler &MCA = getStreamer().getAssembler(); + AttributeSection = MCA.getContext().getELFSection( + ".riscv.attributes", ELF::SHT_RISCV_ATTRIBUTES, 0); + Streamer.SwitchSection(AttributeSection); + + /// FIXME: check this. + Streamer.EmitIntValue(0x41, 1); + } + + // 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.EmitIntValue(VendorHeaderSize + TagHeaderSize + ContentsSize, 4); + Streamer.EmitBytes(CurrentVendor); + Streamer.EmitIntValue(0, 1); // '\0' + + Streamer.EmitIntValue(ARMBuildAttrs::File, 1); + Streamer.EmitIntValue(TagHeaderSize + ContentsSize, 4); + + // 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.EmitIntValue(0, 1); // '\0' + break; + case AttributeItem::NumericAndTextAttributes: + Streamer.EmitULEB128IntValue(item.IntValue); + Streamer.EmitBytes(item.StringValue); + Streamer.EmitIntValue(0, 1); // '\0' + break; + } + } + + Contents.clear(); +} + +size_t RISCVTargetELFStreamer::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; +} diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h @@ -10,12 +10,14 @@ #define LLVM_LIB_TARGET_RISCV_RISCVTARGETSTREAMER_H #include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" namespace llvm { class RISCVTargetStreamer : public MCTargetStreamer { public: RISCVTargetStreamer(MCStreamer &S); + void finish() override; virtual void emitDirectiveOptionPush() = 0; virtual void emitDirectiveOptionPop() = 0; @@ -23,12 +25,25 @@ virtual void emitDirectiveOptionNoRVC() = 0; virtual void emitDirectiveOptionRelax() = 0; virtual void emitDirectiveOptionNoRelax() = 0; + virtual void emitAttribute(unsigned Attribute, unsigned Value) = 0; + virtual void finishAttributeSection() = 0; + virtual void emitTextAttribute(unsigned Attribute, StringRef String) = 0; + virtual void emitIntTextAttribute(unsigned Attribute, unsigned IntValue, + StringRef StringValue = "") = 0; + + void emitTargetAttributes(const MCSubtargetInfo &STI); }; // This part is for ascii assembly output class RISCVTargetAsmStreamer : public RISCVTargetStreamer { formatted_raw_ostream &OS; + void finishAttributeSection() override; + void emitAttribute(unsigned Attribute, unsigned Value) override; + void emitTextAttribute(unsigned Attribute, StringRef String) override; + void emitIntTextAttribute(unsigned Attribute, unsigned IntValue, + StringRef StringValue) override; + public: RISCVTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS); diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp @@ -11,12 +11,50 @@ //===----------------------------------------------------------------------===// #include "RISCVTargetStreamer.h" +#include "RISCVSubtarget.h" +#include "Utils/RISCVAttributes.h" #include "llvm/Support/FormattedStream.h" using namespace llvm; RISCVTargetStreamer::RISCVTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {} +void RISCVTargetStreamer::finish() { finishAttributeSection(); } + +void RISCVTargetStreamer::emitTargetAttributes(const MCSubtargetInfo &STI) { + if (STI.hasFeature(RISCV::FeatureRV32E)) + emitAttribute(RISCVAttrs::Stack_align, 4); + else + emitAttribute(RISCVAttrs::Stack_align, 16); + + std::string Arch = Twine("rv32").str(); + + if (STI.hasFeature(RISCV::Feature64Bit)) + Arch = Twine("rv64").str(); + + if (STI.hasFeature(RISCV::FeatureRV32E)) + Arch = (Twine(Arch) + "e1p9").str(); + else + Arch = (Twine(Arch) + "i2p0").str(); + + if (STI.hasFeature(RISCV::FeatureStdExtM)) + Arch = (Twine(Arch) + "_m2p0").str(); + + if (STI.hasFeature(RISCV::FeatureStdExtA)) + Arch = (Twine(Arch) + "_a2p0").str(); + + if (STI.hasFeature(RISCV::FeatureStdExtF)) + Arch = (Twine(Arch) + "_f2p0").str(); + + if (STI.hasFeature(RISCV::FeatureStdExtD)) + Arch = (Twine(Arch) + "_d2p0").str(); + + if (STI.hasFeature(RISCV::FeatureStdExtC)) + Arch = (Twine(Arch) + "_c2p0").str(); + + emitTextAttribute(RISCVAttrs::Arch, Arch); +} + // This part is for ascii assembly output RISCVTargetAsmStreamer::RISCVTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS) @@ -45,3 +83,19 @@ void RISCVTargetAsmStreamer::emitDirectiveOptionNoRelax() { OS << "\t.option\tnorelax\n"; } + +void RISCVTargetAsmStreamer::emitAttribute(unsigned Attribute, unsigned Value) { + OS << "\t.attribute\t" << Attribute << ", " << Twine(Value) << "\n"; +} + +void RISCVTargetAsmStreamer::emitTextAttribute(unsigned Attribute, + StringRef String) { + OS << "\t.attribute\t" << Attribute << ", \"" << String << "\"" + << "\n"; +} + +void RISCVTargetAsmStreamer::emitIntTextAttribute(unsigned Attribute, + unsigned IntValue, + StringRef StringValue) {} + +void RISCVTargetAsmStreamer::finishAttributeSection() {} diff --git a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp --- a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp +++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp @@ -11,9 +11,10 @@ // //===----------------------------------------------------------------------===// -#include "RISCV.h" #include "MCTargetDesc/RISCVInstPrinter.h" #include "MCTargetDesc/RISCVMCExpr.h" +#include "MCTargetDesc/RISCVTargetStreamer.h" +#include "RISCV.h" #include "RISCVTargetMachine.h" #include "TargetInfo/RISCVTargetInfo.h" #include "llvm/ADT/Statistic.h" @@ -59,6 +60,12 @@ bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const { return LowerRISCVMachineOperandToMCOperand(MO, MCOp, *this); } + + void EmitStartOfAsmFile(Module &M) override; + void EmitEndOfAsmFile(Module &M) override; + +private: + void emitAttributes(); }; } @@ -154,6 +161,36 @@ return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS); } +void RISCVAsmPrinter::EmitStartOfAsmFile(Module &M) { + const Triple &TT = TM.getTargetTriple(); + + if (TT.isOSBinFormatELF()) + emitAttributes(); +} + +void RISCVAsmPrinter::EmitEndOfAsmFile(Module &M) { + const Triple &TT = TM.getTargetTriple(); + MCTargetStreamer &TS = *OutStreamer->getTargetStreamer(); + RISCVTargetStreamer &RTS = static_cast(TS); + + if (TT.isOSBinFormatELF()) { + RTS.finishAttributeSection(); + } +} + +void RISCVAsmPrinter::emitAttributes() { + MCTargetStreamer &TS = *OutStreamer->getTargetStreamer(); + RISCVTargetStreamer &RTS = static_cast(TS); + + const Triple &TT = TM.getTargetTriple(); + StringRef CPU = TM.getTargetCPU(); + StringRef FS = TM.getTargetFeatureString(); + const RISCVTargetMachine &RTM = static_cast(TM); + const RISCVSubtarget STI(TT, CPU, FS, /*ABIName=*/"", RTM); + + RTS.emitTargetAttributes(STI); +} + // Force static initialization. extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVAsmPrinter() { RegisterAsmPrinter X(getTheRISCV32Target()); diff --git a/llvm/lib/Target/RISCV/Utils/CMakeLists.txt b/llvm/lib/Target/RISCV/Utils/CMakeLists.txt --- a/llvm/lib/Target/RISCV/Utils/CMakeLists.txt +++ b/llvm/lib/Target/RISCV/Utils/CMakeLists.txt @@ -1,4 +1,5 @@ add_llvm_component_library(LLVMRISCVUtils + RISCVAttributes.cpp RISCVBaseInfo.cpp RISCVMatInt.cpp ) diff --git a/llvm/lib/Target/RISCV/Utils/RISCVAttributes.h b/llvm/lib/Target/RISCV/Utils/RISCVAttributes.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/RISCV/Utils/RISCVAttributes.h @@ -0,0 +1,45 @@ +//===-- RISCVAttributes.h - RISCV Attributes --------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains enumerations and support routines for RISCV attributes +// as defined in RISC-V ELF psABI specification. +// +// RISC-V ELF psABI specification +// +// https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_LIB_TARGET_RISCV_RISCVATTRIBUTES_H +#define LLVM_LIB_TARGET_RISCV_RISCVATTRIBUTES_H + +namespace llvm { +class StringRef; + +namespace RISCVAttrs { + +enum AttrType { + // Rest correspond to ELF/.riscv.attributes + Stack_align = 4, + Arch = 5, + Unaligned_access = 6, + Priv_spec = 8, + Priv_spec_minor = 10, + Priv_spec_revision = 12, +}; + +StringRef AttrTypeAsString(unsigned Attr, bool HasTagPrefix = true); +StringRef AttrTypeAsString(AttrType Attr, bool HasTagPrefix = true); +int AttrTypeFromString(StringRef Tag); + +// Magic numbers for .riscv.attributes +enum AttrMagic { Format_Version = 0x41 }; + +} // namespace RISCVAttrs +} // namespace llvm + +#endif diff --git a/llvm/lib/Target/RISCV/Utils/RISCVAttributes.cpp b/llvm/lib/Target/RISCV/Utils/RISCVAttributes.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/RISCV/Utils/RISCVAttributes.cpp @@ -0,0 +1,60 @@ +//===-- RISCVAttributes.cpp - RISCV 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 "RISCVAttributes.h" +#include "llvm/ADT/StringRef.h" + +using namespace llvm; + +namespace { +const struct { + RISCVAttrs::AttrType Attr; + StringRef TagName; +} RISCVAttributeTags[] = { + {RISCVAttrs::Stack_align, "Tag_RISCV_stack_align"}, + {RISCVAttrs::Arch, "Tag_RISCV_arch"}, + {RISCVAttrs::Unaligned_access, "Tag_RISCV_unaligned_access"}, + {RISCVAttrs::Priv_spec, "Tag_RISCV_priv_spec"}, + {RISCVAttrs::Priv_spec_minor, "Tag_RISCV_priv_spec_minor"}, + {RISCVAttrs::Priv_spec_revision, "Tag_RISCV_priv_spec_revision"}, +}; +} // namespace + +namespace llvm { +namespace RISCVAttrs { +StringRef AttrTypeAsString(unsigned Attr, bool HasTagPrefix) { + return AttrTypeAsString(static_cast(Attr), HasTagPrefix); +} + +StringRef AttrTypeAsString(AttrType Attr, bool HasTagPrefix) { + for (unsigned TI = 0, + TE = sizeof(RISCVAttributeTags) / sizeof(*RISCVAttributeTags); + TI != TE; ++TI) + if (RISCVAttributeTags[TI].Attr == Attr) { + auto TagName = RISCVAttributeTags[TI].TagName; + return HasTagPrefix ? TagName : TagName.drop_front(4); + } + return ""; +} + +int AttrTypeFromString(StringRef Tag) { + const char *TagPrefix = "Tag_RISCV_"; + bool HasTagPrefix = Tag.startswith(TagPrefix); + for (unsigned TI = 0, + TE = sizeof(RISCVAttributeTags) / sizeof(*RISCVAttributeTags); + TI != TE; ++TI) { + auto TagName = RISCVAttributeTags[TI].TagName; + if (TagName.drop_front(HasTagPrefix ? 0 : StringRef(TagPrefix).size()) == + Tag) { + return RISCVAttributeTags[TI].Attr; + } + } + return -1; +} +} // namespace RISCVAttrs +} // namespace llvm diff --git a/llvm/test/CodeGen/RISCV/attributes-encoding.s b/llvm/test/CodeGen/RISCV/attributes-encoding.s new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/attributes-encoding.s @@ -0,0 +1,42 @@ +// This tests that RISCV attributes are properly encoded. + +// RUN: llvm-mc < %s -triple=riscv32 -filetype=obj -o - \ +// RUN: | llvm-readobj -S --sd | FileCheck %s + +// Tag_RISCV_stack_align +.attribute stack_align, 16 + +// Tag_RISCV_arch +.attribute arch, "rv32i2p0_m2p0_a2p0_c2p0" + +// Tag_RISCV_unaligned_access +.attribute unaligned_access, 0 + +// Tag_RISCV_priv_spec +.attribute priv_spec, 2 + +// Tag_RISCV_priv_spec_minor +.attribute priv_spec_minor, 0 + +// Tag_RISCV_priv_spec_revision +.attribute priv_spec_revision, 0 + +// CHECK: Section { +// CHECK: Name: .riscv.attributes +// CHECK-NEXT: Type: SHT_RISCV_ATTRIBUTES (0x70000003) +// CHECK-NEXT: Flags [ (0x0) +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x0 +// CHECK-NEXT: Offset: 0x34 +// CHECK-NEXT: Size: 51 +// CHECK-NEXT: Link: 0 +// CHECK-NEXT: Info: 0 +// CHECK-NEXT: AddressAlignment: 1 +// CHECK-NEXT: EntrySize: 0 +// CHECK-NEXT: SectionData ( +// CHECK-NEXT: 0000: 41320000 00726973 63760001 28000000 +// CHECK-NEXT: 0010: 04100572 76333269 3270305F 6D327030 +// CHECK-NEXT: 0020: 5F613270 305F6332 70300006 0008020A +// CHECK-NEXT: 0030: 000C00 +// CHECK-NEXT: ) +// CHECK-NEXT: }