diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp --- 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 @@ } } +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 intAttr; + DenseMap 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 §ions) { + RISCVISAInfo::OrderedExtensionMap exts; + const InputSectionBase *firstStackAlign = nullptr; + unsigned firstStackAlignValue = 0, xlen = 0; + bool hasArch = false; + + in.riscvAttributes = std::make_unique(); + auto &merged = static_cast(*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(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 [ "vendor-name" + // [ . + 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 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 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -2820,6 +2820,10 @@ 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 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -581,30 +581,6 @@ } } - if (sec.sh_type == SHT_RISCV_ATTRIBUTES && config->emachine == EM_RISCV) { - RISCVAttributeParser attributes; - ArrayRef 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(*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.h b/lld/ELF/SyntheticSections.h --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -1273,6 +1273,7 @@ // a partition. struct InStruct { std::unique_ptr attributes; + std::unique_ptr riscvAttributes; std::unique_ptr bss; std::unique_ptr bssRelRo; std::unique_ptr got; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -3807,6 +3807,7 @@ void InStruct::reset() { attributes.reset(); + riscvAttributes.reset(); bss.reset(); bssRelRo.reset(); got.reset(); diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -216,6 +216,7 @@ 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 --- a/lld/docs/ReleaseNotes.rst +++ b/lld/docs/ReleaseNotes.rst @@ -39,6 +39,9 @@ * ``--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 `_) Breaking changes ---------------- diff --git a/lld/test/ELF/lto/riscv-attributes.ll b/lld/test/ELF/lto/riscv-attributes.ll new file mode 100644 --- /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 --- /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,"",@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 --- 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,"",@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 --- a/llvm/include/llvm/Support/RISCVISAInfo.h +++ b/llvm/include/llvm/Support/RISCVISAInfo.h @@ -42,6 +42,9 @@ typedef std::map 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> parseArchString(StringRef Arch, bool EnableExperimentalExtension, @@ -73,6 +76,8 @@ static bool isSupportedExtension(StringRef Ext); static bool isSupportedExtension(StringRef Ext, unsigned MajorVersion, unsigned MinorVersion); + static llvm::Expected> + postProcessAndChecking(std::unique_ptr &&ISAInfo); private: RISCVISAInfo(unsigned XLen) @@ -95,9 +100,6 @@ void updateFLen(); void updateMinVLen(); void updateMaxELen(); - - static llvm::Expected> - postProcessAndChecking(std::unique_ptr &&ISAInfo); }; } // namespace llvm