[lld] 8a900f2 - [ELF] Merge SHT_RISCV_ATTRIBUTES sections
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Thu Dec 8 01:53:46 PST 2022
Author: Fangrui Song
Date: 2022-12-08T09:53:40Z
New Revision: 8a900f2438b4a167b98404565ad4da2645cc9330
URL: https://github.com/llvm/llvm-project/commit/8a900f2438b4a167b98404565ad4da2645cc9330
DIFF: https://github.com/llvm/llvm-project/commit/8a900f2438b4a167b98404565ad4da2645cc9330.diff
LOG: [ELF] Merge SHT_RISCV_ATTRIBUTES sections
Currently we take the first SHT_RISCV_ATTRIBUTES (.riscv.attributes) as the
output. If we link an object without an extension with an object with the
extension, the output Tag_RISCV_arch may not contain the extension and some
tools like objdump -d will not decode the related instructions.
This patch implements
Tag_RISCV_stack_align/Tag_RISCV_arch/Tag_RISCV_unaligned_access merge as
specified by
https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#attributes
For the deprecated Tag_RISCV_priv_spec{,_minor,_revision}, dump the attribute to
the output iff all input agree on the value. This is different from GNU ld but
our simple approach should be ok for deprecated tags.
`RISCVAttributeParser::handler` currently warns about unknown tags. This
behavior is retained. In GNU ld arm, tags >= 64 (mod 128) are ignored with a
warning. If RISC-V ever wants to do something similar
(https://github.com/riscv-non-isa/riscv-elf-psabi-doc/issues/352), consider
documenting it in the psABI and changing RISCVAttributeParser.
Like GNU ld, zero value integer attributes and empty string attributes are not
dumped to the output.
Reviewed By: asb, kito-cheng
Differential Revision: https://reviews.llvm.org/D138550
Added:
lld/test/ELF/lto/riscv-attributes.ll
lld/test/ELF/riscv-attributes-place.s
Modified:
lld/ELF/Arch/RISCV.cpp
lld/ELF/Driver.cpp
lld/ELF/InputFiles.cpp
lld/ELF/SyntheticSections.cpp
lld/ELF/SyntheticSections.h
lld/ELF/Target.h
lld/docs/ReleaseNotes.rst
lld/test/ELF/riscv-attributes.s
llvm/include/llvm/Support/RISCVISAInfo.h
Removed:
################################################################################
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index c339f89395750..a2f56472467af 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -11,6 +11,11 @@
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
+#include "llvm/Support/ELFAttributes.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/RISCVAttributeParser.h"
+#include "llvm/Support/RISCVAttributes.h"
+#include "llvm/Support/RISCVISAInfo.h"
#include "llvm/Support/TimeProfiler.h"
using namespace llvm;
@@ -816,6 +821,205 @@ void elf::riscvFinalizeRelax(int passes) {
}
}
+namespace {
+// Representation of the merged .riscv.attributes input sections. The psABI
+// specifies merge policy for attributes. E.g. if we link an object without an
+// extension with an object with the extension, the output Tag_RISCV_arch shall
+// contain the extension. Some tools like objdump parse .riscv.attributes and
+// disabling some instructions if the first Tag_RISCV_arch does not contain an
+// extension.
+class RISCVAttributesSection final : public SyntheticSection {
+public:
+ RISCVAttributesSection()
+ : SyntheticSection(0, SHT_RISCV_ATTRIBUTES, 1, ".riscv.attributes") {}
+
+ size_t getSize() const override { return size; }
+ void writeTo(uint8_t *buf) override;
+
+ static constexpr StringRef vendor = "riscv";
+ DenseMap<unsigned, unsigned> intAttr;
+ DenseMap<unsigned, StringRef> strAttr;
+ size_t size = 0;
+};
+} // namespace
+
+static void mergeArch(RISCVISAInfo::OrderedExtensionMap &mergedExts,
+ unsigned &mergedXlen, const InputSectionBase *sec,
+ StringRef s) {
+ auto maybeInfo =
+ RISCVISAInfo::parseArchString(s, /*EnableExperimentalExtension=*/true,
+ /*ExperimentalExtensionVersionCheck=*/true);
+ if (!maybeInfo) {
+ errorOrWarn(toString(sec) + ": " + s + ": " +
+ llvm::toString(maybeInfo.takeError()));
+ return;
+ }
+
+ // Merge extensions.
+ RISCVISAInfo &info = **maybeInfo;
+ if (mergedExts.empty()) {
+ mergedExts = info.getExtensions();
+ mergedXlen = info.getXLen();
+ } else {
+ for (const auto &ext : info.getExtensions()) {
+ if (auto it = mergedExts.find(ext.first); it != mergedExts.end()) {
+ // TODO This is untested because RISCVISAInfo::parseArchString does not
+ // accept unsupported versions yet.
+ if (std::tie(it->second.MajorVersion, it->second.MinorVersion) >=
+ std::tie(ext.second.MajorVersion, ext.second.MinorVersion))
+ continue;
+ }
+ mergedExts[ext.first] = ext.second;
+ }
+ }
+}
+
+static RISCVAttributesSection *
+mergeAttributesSection(const SmallVector<InputSectionBase *, 0> §ions) {
+ RISCVISAInfo::OrderedExtensionMap exts;
+ const InputSectionBase *firstStackAlign = nullptr;
+ unsigned firstStackAlignValue = 0, xlen = 0;
+ bool hasArch = false;
+
+ in.riscvAttributes = std::make_unique<RISCVAttributesSection>();
+ auto &merged = static_cast<RISCVAttributesSection &>(*in.riscvAttributes);
+
+ // Collect all tags values from attributes section.
+ const auto &attributesTags = RISCVAttrs::getRISCVAttributeTags();
+ for (const InputSectionBase *sec : sections) {
+ RISCVAttributeParser parser;
+ if (Error e = parser.parse(sec->content(), support::little))
+ warn(toString(sec) + ": " + llvm::toString(std::move(e)));
+ for (const auto &tag : attributesTags) {
+ switch (RISCVAttrs::AttrType(tag.attr)) {
+ // Integer attributes.
+ case RISCVAttrs::STACK_ALIGN:
+ if (auto i = parser.getAttributeValue(tag.attr)) {
+ auto r = merged.intAttr.try_emplace(tag.attr, *i);
+ if (r.second) {
+ firstStackAlign = sec;
+ firstStackAlignValue = *i;
+ } else if (r.first->second != *i) {
+ errorOrWarn(toString(sec) + " has stack_align=" + Twine(*i) +
+ " but " + toString(firstStackAlign) +
+ " has stack_align=" + Twine(firstStackAlignValue));
+ }
+ }
+ continue;
+ case RISCVAttrs::UNALIGNED_ACCESS:
+ if (auto i = parser.getAttributeValue(tag.attr))
+ merged.intAttr[tag.attr] |= *i;
+ continue;
+
+ // String attributes.
+ case RISCVAttrs::ARCH:
+ if (auto s = parser.getAttributeString(tag.attr)) {
+ hasArch = true;
+ mergeArch(exts, xlen, sec, *s);
+ }
+ continue;
+
+ // Attributes which use the default handling.
+ case RISCVAttrs::PRIV_SPEC:
+ case RISCVAttrs::PRIV_SPEC_MINOR:
+ case RISCVAttrs::PRIV_SPEC_REVISION:
+ break;
+ }
+
+ // Fallback for deprecated priv_spec* and other unknown attributes: retain
+ // the attribute if all input sections agree on the value. GNU ld uses 0
+ // and empty strings as default values which are not dumped to the output.
+ // TODO Adjust after resolution to
+ // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/issues/352
+ if (tag.attr % 2 == 0) {
+ if (auto i = parser.getAttributeValue(tag.attr)) {
+ auto r = merged.intAttr.try_emplace(tag.attr, *i);
+ if (!r.second && r.first->second != *i)
+ r.first->second = 0;
+ }
+ } else if (auto s = parser.getAttributeString(tag.attr)) {
+ auto r = merged.strAttr.try_emplace(tag.attr, *s);
+ if (!r.second && r.first->second != *s)
+ r.first->second = {};
+ }
+ }
+ }
+
+ if (hasArch) {
+ if (auto result = RISCVISAInfo::postProcessAndChecking(
+ std::make_unique<RISCVISAInfo>(xlen, exts))) {
+ merged.strAttr.try_emplace(RISCVAttrs::ARCH,
+ saver().save((*result)->toString()));
+ } else {
+ errorOrWarn(llvm::toString(result.takeError()));
+ }
+ }
+
+ // The total size of headers: format-version [ <section-length> "vendor-name"
+ // [ <file-tag> <size>.
+ size_t size = 5 + merged.vendor.size() + 1 + 5;
+ for (auto &attr : merged.intAttr)
+ if (attr.second != 0)
+ size += getULEB128Size(attr.first) + getULEB128Size(attr.second);
+ for (auto &attr : merged.strAttr)
+ if (!attr.second.empty())
+ size += getULEB128Size(attr.first) + attr.second.size() + 1;
+ merged.size = size;
+ return &merged;
+}
+
+void RISCVAttributesSection::writeTo(uint8_t *buf) {
+ const size_t size = getSize();
+ uint8_t *const end = buf + size;
+ *buf = ELFAttrs::Format_Version;
+ write32(buf + 1, size - 1);
+ buf += 5;
+
+ memcpy(buf, vendor.data(), vendor.size());
+ buf += vendor.size() + 1;
+
+ *buf = ELFAttrs::File;
+ write32(buf + 1, end - buf);
+ buf += 5;
+
+ for (auto &attr : intAttr) {
+ if (attr.second == 0)
+ continue;
+ buf += encodeULEB128(attr.first, buf);
+ buf += encodeULEB128(attr.second, buf);
+ }
+ for (auto &attr : strAttr) {
+ if (attr.second.empty())
+ continue;
+ buf += encodeULEB128(attr.first, buf);
+ memcpy(buf, attr.second.data(), attr.second.size());
+ buf += attr.second.size() + 1;
+ }
+}
+
+void elf::mergeRISCVAttributesSections() {
+ // Find the first input SHT_RISCV_ATTRIBUTES; return if not found.
+ size_t place =
+ llvm::find_if(ctx.inputSections,
+ [](auto *s) { return s->type == SHT_RISCV_ATTRIBUTES; }) -
+ ctx.inputSections.begin();
+ if (place == ctx.inputSections.size())
+ return;
+
+ // Extract all SHT_RISCV_ATTRIBUTES sections into `sections`.
+ SmallVector<InputSectionBase *, 0> sections;
+ llvm::erase_if(ctx.inputSections, [&](InputSectionBase *s) {
+ if (s->type != SHT_RISCV_ATTRIBUTES)
+ return false;
+ sections.push_back(s);
+ return true;
+ });
+
+ // Add the merged section.
+ ctx.inputSections.insert(ctx.inputSections.begin() + place,
+ mergeAttributesSection(sections));
+}
+
TargetInfo *elf::getRISCVTargetInfo() {
static RISCV target;
return ⌖
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index a7d1cab433220..a051228518cba 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -2820,6 +2820,10 @@ void LinkerDriver::link(opt::InputArgList &args) {
if (!config->relocatable)
combineEhSections();
+ // Merge .riscv.attributes sections.
+ if (config->emachine == EM_RISCV)
+ mergeRISCVAttributesSections();
+
{
llvm::TimeTraceScope timeScope("Assign sections");
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index 7edb69655638d..aafef65b054da 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -581,30 +581,6 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
}
}
- if (sec.sh_type == SHT_RISCV_ATTRIBUTES && config->emachine == EM_RISCV) {
- RISCVAttributeParser attributes;
- ArrayRef<uint8_t> contents =
- check(this->getObj().getSectionContents(sec));
- StringRef name = check(obj.getSectionName(sec, shstrtab));
- this->sections[i] = &InputSection::discarded;
- if (Error e = attributes.parse(contents, support::little)) {
- InputSection isec(*this, sec, name);
- warn(toString(&isec) + ": " + llvm::toString(std::move(e)));
- } else {
- // FIXME: Validate arch tag contains C if and only if EF_RISCV_RVC is
- // present.
-
- // FIXME: Retain the first attribute section we see. Tools such as
- // llvm-objdump make use of the attribute section to determine which
- // standard extensions to enable. In a full implementation we would
- // merge all attribute sections.
- if (in.attributes == nullptr) {
- in.attributes = std::make_unique<InputSection>(*this, sec, name);
- this->sections[i] = in.attributes.get();
- }
- }
- }
-
if (sec.sh_type != SHT_GROUP)
continue;
StringRef signature = getShtGroupSignature(objSections, sec);
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 2ca3b63396577..b7e5114a0ee12 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -3807,6 +3807,7 @@ void PartitionIndexSection::writeTo(uint8_t *buf) {
void InStruct::reset() {
attributes.reset();
+ riscvAttributes.reset();
bss.reset();
bssRelRo.reset();
got.reset();
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 3dc9c8e0d2693..391eb6bf3661c 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -1273,6 +1273,7 @@ inline Partition &SectionBase::getPartition() const {
// a partition.
struct InStruct {
std::unique_ptr<InputSection> attributes;
+ std::unique_ptr<SyntheticSection> riscvAttributes;
std::unique_ptr<BssSection> bss;
std::unique_ptr<BssSection> bssRelRo;
std::unique_ptr<GotSection> got;
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
index fb3d8ff71c887..e6a78169058a5 100644
--- a/lld/ELF/Target.h
+++ b/lld/ELF/Target.h
@@ -216,6 +216,7 @@ void addPPC64SaveRestore();
uint64_t getPPC64TocBase();
uint64_t getAArch64Page(uint64_t expr);
void riscvFinalizeRelax(int passes);
+void mergeRISCVAttributesSections();
LLVM_LIBRARY_VISIBILITY extern const TargetInfo *target;
TargetInfo *getTarget();
diff --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst
index cf52fd3222860..c350aa9e714c5 100644
--- a/lld/docs/ReleaseNotes.rst
+++ b/lld/docs/ReleaseNotes.rst
@@ -39,6 +39,9 @@ ELF Improvements
* ``--no-undefined-version`` is now the default; symbols named in version
scripts that have no matching symbol in the output will be reported. Use
``--undefined-version`` to revert to the old behavior.
+* The output ``SHT_RISCV_ATTRIBUTES`` section now merges all input components
+ instead of picking the first input component.
+ (`D138550 <https://reviews.llvm.org/D138550>`_)
Breaking changes
----------------
diff --git a/lld/test/ELF/lto/riscv-attributes.ll b/lld/test/ELF/lto/riscv-attributes.ll
new file mode 100644
index 0000000000000..eb99397bbda8c
--- /dev/null
+++ b/lld/test/ELF/lto/riscv-attributes.ll
@@ -0,0 +1,53 @@
+; REQUIRES: riscv
+
+; RUN: rm -rf %t && split-file %s %t && cd %t
+; RUN: llvm-mc -filetype=obj -triple=riscv32 1.s -o 1.o
+; RUN: llvm-mc -filetype=obj -triple=riscv32 2.s -o 2.o
+; RUN: llvm-as a.ll -o a.bc
+; RUN: ld.lld 1.o 2.o a.bc -o out
+; RUN: llvm-readelf --arch-specific out | FileCheck %s
+
+; CHECK: BuildAttributes {
+; CHECK-NEXT: FormatVersion: 0x41
+; CHECK-NEXT: Section 1 {
+; CHECK-NEXT: SectionLength: 61
+; CHECK-NEXT: Vendor: riscv
+; CHECK-NEXT: Tag: Tag_File (0x1)
+; CHECK-NEXT: Size: 51
+; CHECK-NEXT: FileAttributes {
+; CHECK-NEXT: Attribute {
+; CHECK-NEXT: Tag: 4
+; CHECK-NEXT: Value: 16
+; CHECK-NEXT: TagName: stack_align
+; CHECK-NEXT: Description: Stack alignment is 16-bytes
+; CHECK-NEXT: }
+; CHECK-NEXT: Attribute {
+; CHECK-NEXT: Tag: 6
+; CHECK-NEXT: Value: 1
+; CHECK-NEXT: TagName: unaligned_access
+; CHECK-NEXT: Description: Unaligned access
+; CHECK-NEXT: }
+; CHECK-NEXT: Attribute {
+; CHECK-NEXT: Tag: 5
+; CHECK-NEXT: TagName: arch
+; CHECK-NEXT: Value: rv32i2p0_m2p0_a2p0_f2p0_d2p0_c2p0_zbb1p0
+; CHECK-NEXT: }
+; CHECK-NEXT: }
+; CHECK-NEXT: }
+; CHECK-NEXT: }
+
+;--- 1.s
+.attribute 4, 16
+.attribute 5, "rv32i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"
+;--- 2.s
+.attribute 4, 16
+.attribute 5, "rv32i2p0_m2p0_f2p0_d2p0_zbb1p0"
+.attribute 6, 1
+
+;--- a.ll
+target datalayout = "e-m:e-p:32:32-i64:64-n32-S128"
+target triple = "riscv32"
+
+define void @_start() {
+ ret void
+}
diff --git a/lld/test/ELF/riscv-attributes-place.s b/lld/test/ELF/riscv-attributes-place.s
new file mode 100644
index 0000000000000..4d265bd045c71
--- /dev/null
+++ b/lld/test/ELF/riscv-attributes-place.s
@@ -0,0 +1,29 @@
+# REQUIRES: riscv
+## The merged SHT_RISCV_ATTRIBUTES is placed at the first input
+## SHT_RISCV_ATTRIBUTES.
+
+# RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.o
+# RUN: ld.lld -e 0 %t.o %t.o -o %t
+# RUN: llvm-readelf -S %t | FileCheck %s
+
+# CHECK: Name Type Address Off Size ES Flg Lk Inf Al
+# CHECK: .riscv.a PROGBITS 0000000000000000 [[#%x,]] 000002 00 0 0 1
+# CHECK-NEXT: .riscv.attributes RISCV_ATTRIBUTES 0000000000000000 [[#%x,]] 00001a 00 0 0 1
+# CHECK-NEXT: .riscv.b PROGBITS 0000000000000000 [[#%x,]] 000002 00 0 0 1
+
+.section .riscv.a,""
+.byte 0
+
+.section .riscv.attributes,"", at 0x70000003
+.byte 0x41
+.long .Lend-.riscv.attributes-1
+.asciz "riscv" # vendor
+.Lbegin:
+.byte 1 # Tag_File
+.long .Lend-.Lbegin
+.byte 5 # Tag_RISCV_arch
+.asciz "rv64i2"
+.Lend:
+
+.section .riscv.b,""
+.byte 0
diff --git a/lld/test/ELF/riscv-attributes.s b/lld/test/ELF/riscv-attributes.s
index 36e506a1df662..3776673c5f142 100644
--- a/lld/test/ELF/riscv-attributes.s
+++ b/lld/test/ELF/riscv-attributes.s
@@ -1,10 +1,51 @@
# REQUIRES: riscv
-# RUN: llvm-mc -filetype=obj -triple=riscv64-unknown-elf -mattr=-relax %s -o %t.o
-# RUN: ld.lld %t.o -o %t
-# RUN: llvm-readelf --arch-specific %t | FileCheck %s
-# RUN: ld.lld %t.o %t.o -o %t2
-# RUN: llvm-readelf --arch-specific %t2 | FileCheck %s
+# RUN: rm -rf %t && split-file %s %t && cd %t
+# RUN: llvm-mc -filetype=obj -triple=riscv64 a.s -o a.o
+# RUN: ld.lld -e 0 a.o -o out 2>&1 | count 0
+# RUN: llvm-readobj --arch-specific out | FileCheck %s
+# RUN: ld.lld -e 0 a.o a.o -o out1 2>&1 | count 0
+# RUN: llvm-readobj --arch-specific out1 | FileCheck %s
+# RUN: ld.lld -r a.o a.o -o out1 2>&1 | count 0
+# RUN: llvm-readobj --arch-specific out1 | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=riscv64 b.s -o b.o
+# RUN: llvm-mc -filetype=obj -triple=riscv64 c.s -o c.o
+# RUN: ld.lld a.o b.o c.o -o out2
+# RUN: llvm-readobj --arch-specific out2 | FileCheck %s --check-prefix=CHECK2
+
+# RUN: llvm-mc -filetype=obj -triple=riscv64 invalid_ext.s -o invalid_ext.o
+# RUN: not ld.lld invalid_ext.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=INVALID_EXT --implicit-check-not=error:
+# INVALID_EXT: error: invalid_ext.o:(.riscv.attributes): rv64i2p0_y2p0: invalid standard user-level extension 'y'
+
+## A zero value attribute is not printed.
+# RUN: llvm-mc -filetype=obj -triple=riscv64 unaligned_access_0.s -o unaligned_access_0.o
+# RUN: ld.lld -e 0 --fatal-warnings a.o unaligned_access_0.o -o unaligned_access_0
+# RUN: llvm-readobj -A unaligned_access_0 | FileCheck /dev/null --implicit-check-not='TagName: unaligned_access'
+
+## Differing stack_align values lead to an error.
+# RUN: llvm-mc -filetype=obj -triple=riscv64
diff _stack_align.s -o
diff _stack_align.o
+# RUN: not ld.lld a.o b.o c.o
diff _stack_align.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=STACK_ALIGN --implicit-check-not=error:
+# STACK_ALIGN: error:
diff _stack_align.o:(.riscv.attributes) has stack_align=32 but a.o:(.riscv.attributes) has stack_align=16
+
+## The deprecated priv_spec is not handled as GNU ld does.
+## Differing priv_spec attributes lead to an absent attribute.
+# RUN: llvm-mc -filetype=obj -triple=riscv64
diff _priv_spec.s -o
diff _priv_spec.o
+# RUN: ld.lld -e 0 --fatal-warnings a.o b.o c.o
diff _priv_spec.o -o
diff _priv_spec
+# RUN: llvm-readobj -A
diff _priv_spec | FileCheck /dev/null --implicit-check-not='TagName: priv_spec'
+
+## Unknown tags currently lead to warnings.
+# RUN: llvm-mc -filetype=obj -triple=riscv64 unknown13.s -o unknown13.o
+# RUN: llvm-mc -filetype=obj -triple=riscv64 unknown13a.s -o unknown13a.o
+# RUN: ld.lld -e 0 unknown13.o unknown13.o unknown13a.o -o unknown13 2>&1 | FileCheck %s --check-prefix=UNKNOWN13 --implicit-check-not=warning:
+# UNKNOWN13-COUNT-2: warning: unknown13.o:(.riscv.attributes): invalid tag 0xd at offset 0x10
+# UNKNOWN13: warning: unknown13a.o:(.riscv.attributes): invalid tag 0xd at offset 0x10
+
+# RUN: llvm-mc -filetype=obj -triple=riscv64 unknown22.s -o unknown22.o
+# RUN: llvm-mc -filetype=obj -triple=riscv64 unknown22a.s -o unknown22a.o
+# RUN: ld.lld -e 0 unknown22.o unknown22.o unknown22a.o -o unknown22 2>&1 | FileCheck %s --check-prefix=UNKNOWN22 --implicit-check-not=warning:
+# UNKNOWN22-COUNT-2: warning: unknown22.o:(.riscv.attributes): invalid tag 0x16 at offset 0x10
+# UNKNOWN22: warning: unknown22a.o:(.riscv.attributes): invalid tag 0x16 at offset 0x10
# CHECK: BuildAttributes {
# CHECK-NEXT: FormatVersion: 0x41
@@ -29,5 +70,91 @@
# CHECK-NEXT: }
# CHECK-NEXT: }
-.attribute 4, 16
-.attribute 5, "rv64i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"
+# CHECK2: BuildAttributes {
+# CHECK2-NEXT: FormatVersion: 0x41
+# CHECK2-NEXT: Section 1 {
+# CHECK2-NEXT: SectionLength: 95
+# CHECK2-NEXT: Vendor: riscv
+# CHECK2-NEXT: Tag: Tag_File (0x1)
+# CHECK2-NEXT: Size: 85
+# CHECK2-NEXT: FileAttributes {
+# CHECK2-NEXT: Attribute {
+# CHECK2-NEXT: Tag: 4
+# CHECK2-NEXT: Value: 16
+# CHECK2-NEXT: TagName: stack_align
+# CHECK2-NEXT: Description: Stack alignment is 16-bytes
+# CHECK2-NEXT: }
+# CHECK2-NEXT: Attribute {
+# CHECK2-NEXT: Tag: 6
+# CHECK2-NEXT: Value: 1
+# CHECK2-NEXT: TagName: unaligned_access
+# CHECK2-NEXT: Description: Unaligned access
+# CHECK2-NEXT: }
+# CHECK2-NEXT: Attribute {
+# CHECK2-NEXT: Tag: 8
+# CHECK2-NEXT: TagName: priv_spec
+# CHECK2-NEXT: Value: 2
+# CHECK2-NEXT: }
+# CHECK2-NEXT: Attribute {
+# CHECK2-NEXT: Tag: 10
+# CHECK2-NEXT: TagName: priv_spec_minor
+# CHECK2-NEXT: Value: 2
+# CHECK2-NEXT: }
+# CHECK2-NEXT: Attribute {
+# CHECK2-NEXT: Tag: 5
+# CHECK2-NEXT: TagName: arch
+# CHECK2-NEXT: Value: rv64i2p0_m2p0_a2p0_f2p0_d2p0_c2p0_zkt1p0_zve32f1p0_zve32x1p0_zvl32b1p0
+# CHECK2-NEXT: }
+# CHECK2-NEXT: }
+# CHECK2-NEXT: }
+# CHECK2-NEXT: }
+
+#--- a.s
+.attribute stack_align, 16
+.attribute arch, "rv64i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"
+.attribute unaligned_access, 0
+
+#--- b.s
+.attribute stack_align, 16
+.attribute arch, "rv64i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"
+.attribute priv_spec, 2
+.attribute priv_spec_minor, 2
+
+#--- c.s
+.attribute stack_align, 16
+.attribute arch, "rv64i2p0_f2p0_zkt1p0_zve32f1p0_zve32x1p0_zvl32b1p0"
+.attribute unaligned_access, 1
+.attribute priv_spec, 2
+.attribute priv_spec_minor, 2
+
+#--- invalid_ext.s
+.section .riscv.attributes,"", at 0x70000003
+.byte 0x41
+.long .Lend-.riscv.attributes-1
+.asciz "riscv" # vendor
+.Lbegin:
+.byte 1 # Tag_File
+.long .Lend-.Lbegin
+.byte 5 # Tag_RISCV_arch
+.asciz "rv64i2p0_y2p0"
+.Lend:
+
+#--- unaligned_access_0.s
+.attribute unaligned_access, 0
+
+#---
diff _stack_align.s
+.attribute stack_align, 32
+
+#---
diff _priv_spec.s
+.attribute priv_spec, 3
+.attribute priv_spec_minor, 3
+
+#--- unknown13.s
+.attribute 13, "0"
+#--- unknown13a.s
+.attribute 13, "1"
+
+#--- unknown22.s
+.attribute 22, 1
+#--- unknown22a.s
+.attribute 22, 2
diff --git a/llvm/include/llvm/Support/RISCVISAInfo.h b/llvm/include/llvm/Support/RISCVISAInfo.h
index ced3baf416fcb..4529b742f4073 100644
--- a/llvm/include/llvm/Support/RISCVISAInfo.h
+++ b/llvm/include/llvm/Support/RISCVISAInfo.h
@@ -42,6 +42,9 @@ class RISCVISAInfo {
typedef std::map<std::string, RISCVExtensionInfo, ExtensionComparator>
OrderedExtensionMap;
+ RISCVISAInfo(unsigned XLen, OrderedExtensionMap &Exts)
+ : XLen(XLen), FLen(0), MinVLen(0), MaxELen(0), MaxELenFp(0), Exts(Exts) {}
+
/// Parse RISCV ISA info from arch string.
static llvm::Expected<std::unique_ptr<RISCVISAInfo>>
parseArchString(StringRef Arch, bool EnableExperimentalExtension,
@@ -73,6 +76,8 @@ class RISCVISAInfo {
static bool isSupportedExtension(StringRef Ext);
static bool isSupportedExtension(StringRef Ext, unsigned MajorVersion,
unsigned MinorVersion);
+ static llvm::Expected<std::unique_ptr<RISCVISAInfo>>
+ postProcessAndChecking(std::unique_ptr<RISCVISAInfo> &&ISAInfo);
private:
RISCVISAInfo(unsigned XLen)
@@ -95,9 +100,6 @@ class RISCVISAInfo {
void updateFLen();
void updateMinVLen();
void updateMaxELen();
-
- static llvm::Expected<std::unique_ptr<RISCVISAInfo>>
- postProcessAndChecking(std::unique_ptr<RISCVISAInfo> &&ISAInfo);
};
} // namespace llvm
More information about the llvm-commits
mailing list