diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp index 7b9c9c6c6c385..4b7eab0e7710d 100644 --- a/lld/ELF/Arch/RISCV.cpp +++ b/lld/ELF/Arch/RISCV.cpp @@ -1135,11 +1135,34 @@ static void mergeAtomic(DenseMap::iterator it, }; } +static void mergeX3RegUse(DenseMap::iterator it, + const InputSectionBase *oldSection, + const InputSectionBase *newSection, + unsigned int oldTag, unsigned int newTag) { + // X3/GP register usage are incompatible and cannot be merged, with the + // exception of the UNKNOWN or 0 value. + using RISCVAttrs::RISCVX3RegUse::X3RegUsage; + if (newTag == X3RegUsage::UNKNOWN) + return; + if (oldTag == X3RegUsage::UNKNOWN) { + it->getSecond() = newTag; + return; + } + if (oldTag != newTag) { + error(toString(oldSection) + " has x3_reg_usage=" + Twine(oldTag) + + " but " + toString(newSection) + + " has x3_reg_usage=" + Twine(newTag)); + return; + } + // TODO: do we need to check the tags are < 2047? +} + static RISCVAttributesSection * mergeAttributesSection(const SmallVector §ions) { RISCVISAInfo::OrderedExtensionMap exts; const InputSectionBase *firstStackAlign = nullptr; const InputSectionBase *firstAtomicAbi = nullptr; + const InputSectionBase *firstX3RegUse = nullptr; unsigned firstStackAlignValue = 0, xlen = 0; bool hasArch = false; @@ -1197,6 +1220,18 @@ mergeAttributesSection(const SmallVector §ions) { } } continue; + + case llvm::RISCVAttrs::AttrType::X3_REG_USAGE: + if (auto i = parser.getAttributeValue(tag.attr)) { + auto r = merged.intAttr.try_emplace(tag.attr, *i); + if (r.second) { + firstX3RegUse = sec; + } else { + mergeX3RegUse(r.first, firstX3RegUse, sec, r.first->getSecond(), + *i); + } + } + continue; } // Fallback for deprecated priv_spec* and other unknown attributes: retain diff --git a/lld/test/ELF/riscv-attributes.s b/lld/test/ELF/riscv-attributes.s index 77c2c3cb263fd..e0f71ce227dd1 100644 --- a/lld/test/ELF/riscv-attributes.s +++ b/lld/test/ELF/riscv-attributes.s @@ -77,6 +77,22 @@ # RUN: ld.lld diff_stack_align.o atomic_abi_A7.o -o atomic_abi_A7_none # RUN: llvm-readobj -A atomic_abi_A7_none | FileCheck %s --check-prefix=NONE_A7 + +# RUN: llvm-mc -filetype=obj -triple=riscv64 x3_reg_usage_unknown.s -o x3_reg_usage_unknown.o +# RUN: llvm-mc -filetype=obj -triple=riscv64 x3_reg_usage_gp.s -o x3_reg_usage_gp.o +# RUN: llvm-mc -filetype=obj -triple=riscv64 x3_reg_usage_scs.s -o x3_reg_usage_scs.o +# RUN: llvm-mc -filetype=obj -triple=riscv64 x3_reg_usage_tmp.s -o x3_reg_usage_tmp.o + +# RUN: not ld.lld x3_reg_usage_scs.o x3_reg_usage_gp.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=X3_REG_SCS_GP --implicit-check-not=error: +# X3_REG_SCS_GP: error: x3_reg_usage_scs.o:(.riscv.attributes) has x3_reg_usage=2 but x3_reg_usage_gp.o:(.riscv.attributes) has x3_reg_usage=1 + +# RUN: not ld.lld x3_reg_usage_scs.o x3_reg_usage_tmp.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=X3_REG_SCS_TMP --implicit-check-not=error: +# X3_REG_SCS_TMP: error: x3_reg_usage_scs.o:(.riscv.attributes) has x3_reg_usage=2 but x3_reg_usage_tmp.o:(.riscv.attributes) has x3_reg_usage=3 + + +# RUN: ld.lld x3_reg_usage_scs.o x3_reg_usage_unknown.o -o x3_reg_usage_scs_unknown +# RUN: llvm-readobj -A x3_reg_usage_scs_unknown | FileCheck %s --check-prefix=X3_REG_SCS_UKNOWN + ## 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 @@ -488,6 +504,36 @@ # A6S_A7-NEXT: } # A6S_A7-NEXT: } +#--- x3_reg_usage_unknown.s +.attribute x3_reg_usage, 0 + +#--- x3_reg_usage_gp.s +.attribute x3_reg_usage, 1 + +#--- x3_reg_usage_scs.s +.attribute x3_reg_usage, 2 + +#--- x3_reg_usage_tmp.s +.attribute x3_reg_usage, 3 + +# X3_REG_SCS_UKNOWN: BuildAttributes { +# X3_REG_SCS_UKNOWN-NEXT: FormatVersion: 0x41 +# X3_REG_SCS_UKNOWN-NEXT: Section 1 { +# X3_REG_SCS_UKNOWN-NEXT: SectionLength: 17 +# X3_REG_SCS_UKNOWN-NEXT: Vendor: riscv +# X3_REG_SCS_UKNOWN-NEXT: Tag: Tag_File (0x1) +# X3_REG_SCS_UKNOWN-NEXT: Size: 7 +# X3_REG_SCS_UKNOWN-NEXT: FileAttributes { +# X3_REG_SCS_UKNOWN-NEXT: Attribute { +# X3_REG_SCS_UKNOWN-NEXT: Tag: 16 +# X3_REG_SCS_UKNOWN-NEXT: Value: 2 +# X3_REG_SCS_UKNOWN-NEXT: TagName: x3_reg_usage +# X3_REG_SCS_UKNOWN-NEXT: Description: X3 reg usage is 2 +# X3_REG_SCS_UKNOWN-NEXT: } +# X3_REG_SCS_UKNOWN-NEXT: } +# X3_REG_SCS_UKNOWN-NEXT: } +# X3_REG_SCS_UKNOWN-NEXT: } + #--- unknown13.s .attribute 13, "0" #--- unknown13a.s diff --git a/llvm/include/llvm/Support/RISCVAttributeParser.h b/llvm/include/llvm/Support/RISCVAttributeParser.h index 9f295504de959..9e7d9149111ad 100644 --- a/llvm/include/llvm/Support/RISCVAttributeParser.h +++ b/llvm/include/llvm/Support/RISCVAttributeParser.h @@ -25,6 +25,7 @@ class RISCVAttributeParser : public ELFAttributeParser { Error unalignedAccess(unsigned tag); Error stackAlign(unsigned tag); Error atomicAbi(unsigned tag); + Error x3RegUsage(unsigned tag); public: RISCVAttributeParser(ScopedPrinter *sw) diff --git a/llvm/include/llvm/Support/RISCVAttributes.h b/llvm/include/llvm/Support/RISCVAttributes.h index 5def890a72735..2321ad5a48942 100644 --- a/llvm/include/llvm/Support/RISCVAttributes.h +++ b/llvm/include/llvm/Support/RISCVAttributes.h @@ -33,6 +33,7 @@ enum AttrType : unsigned { PRIV_SPEC_MINOR = 10, PRIV_SPEC_REVISION = 12, ATOMIC_ABI = 14, + X3_REG_USAGE = 16, }; namespace RISCVAtomicAbiTag { @@ -47,6 +48,18 @@ enum AtomicABI : unsigned { }; } // namespace RISCVAtomicAbiTag +namespace RISCVX3RegUse { +enum X3RegUsage : unsigned { + // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#tag_riscv_x3_reg_usage-16-uleb128value + UNKNOWN = 0, + GP = 1, + SCS = 2, + TMP = 3, + // 4-1023 reserved for future standard defined platform register. + // 1024-2047 reserved for nonstandard defined platform register. +}; +} // namespace RISCVX3RegUse + enum { NOT_ALLOWED = 0, ALLOWED = 1 }; } // namespace RISCVAttrs diff --git a/llvm/lib/Support/RISCVAttributeParser.cpp b/llvm/lib/Support/RISCVAttributeParser.cpp index 19c5a0e06903f..3926d18ac229a 100644 --- a/llvm/lib/Support/RISCVAttributeParser.cpp +++ b/llvm/lib/Support/RISCVAttributeParser.cpp @@ -41,6 +41,10 @@ const RISCVAttributeParser::DisplayHandler RISCVAttrs::ATOMIC_ABI, &RISCVAttributeParser::atomicAbi, }, + { + RISCVAttrs::X3_REG_USAGE, + &RISCVAttributeParser::x3RegUsage, + }, }; Error RISCVAttributeParser::atomicAbi(unsigned Tag) { @@ -49,6 +53,12 @@ Error RISCVAttributeParser::atomicAbi(unsigned Tag) { return Error::success(); } +Error RISCVAttributeParser::x3RegUsage(unsigned Tag) { + uint64_t Value = de.getULEB128(cursor); + printAttribute(Tag, Value, "X3 reg usage is " + utostr(Value)); + return Error::success(); +} + Error RISCVAttributeParser::unalignedAccess(unsigned tag) { static const char *strings[] = {"No unaligned access", "Unaligned access"}; return parseStringAttribute("Unaligned_access", tag, ArrayRef(strings)); diff --git a/llvm/lib/Support/RISCVAttributes.cpp b/llvm/lib/Support/RISCVAttributes.cpp index dc70d65acba06..51104263e6324 100644 --- a/llvm/lib/Support/RISCVAttributes.cpp +++ b/llvm/lib/Support/RISCVAttributes.cpp @@ -19,6 +19,7 @@ static constexpr TagNameItem tagData[] = { {PRIV_SPEC_MINOR, "Tag_priv_spec_minor"}, {PRIV_SPEC_REVISION, "Tag_priv_spec_revision"}, {ATOMIC_ABI, "Tag_atomic_abi"}, + {X3_REG_USAGE, "Tag_x3_reg_usage"}, }; constexpr TagNameMap RISCVAttributeTags{tagData}; diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp index adb17cec28c26..b66a68904d97c 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp @@ -82,6 +82,24 @@ void RISCVTargetStreamer::emitTargetAttributes(const MCSubtargetInfo &STI, : RISCVAttrs::RISCVAtomicAbiTag::AtomicABI::A6S; emitAttribute(RISCVAttrs::ATOMIC_ABI, AtomicABITag); } + + bool HasX3Gp = STI.hasFeature(RISCV::FeatureX3GP); + bool HasX3Scs = STI.hasFeature(RISCV::FeatureX3SCS); + bool HasX3Tmp = STI.hasFeature(RISCV::FeatureX3Tmp); + if ((HasX3Gp + HasX3Scs + HasX3Tmp) > 1) + report_fatal_error("Cannot set multiple ABIs for X3/GP"); + + unsigned X3AbiTag; + if (HasX3Gp) + X3AbiTag = RISCVAttrs::RISCVX3RegUse::GP; + else if (HasX3Scs) + X3AbiTag = RISCVAttrs::RISCVX3RegUse::SCS; + else if (HasX3Tmp) + X3AbiTag = RISCVAttrs::RISCVX3RegUse::TMP; + else + X3AbiTag = RISCVAttrs::RISCVX3RegUse::UNKNOWN; + + emitAttribute(RISCVAttrs::X3_REG_USAGE, X3AbiTag); } // This part is for ascii assembly output diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td index deb983528f323..d842d61491384 100644 --- a/llvm/lib/Target/RISCV/RISCVFeatures.td +++ b/llvm/lib/Target/RISCV/RISCVFeatures.td @@ -1307,3 +1307,24 @@ def FeatureForcedSWShadowStack : SubtargetFeature< "forced-sw-shadow-stack", "HasForcedSWShadowStack", "true", "Implement shadow stack with software.">; def HasForcedSWShadowStack : Predicate<"Subtarget->hasForcedSWShadowStack()">; + +def FeatureX3Unknown : SubtargetFeature<"x3-unknown", "X3Unknown", "true", + "X3 register has an unknown purpose.">; + +def FeatureX3GP : SubtargetFeature<"x3-gp", "X3GP", "true", + "X3 register is used as global pointer">; + +def FeatureX3SCS : SubtargetFeature<"x3-scs", "X3SCS", "true", + "X3 register is used as SCS poitner">; + +def FeatureX3Tmp : SubtargetFeature<"x3-tmp", "X3Tmp", "true", + "X3 register is used as a temporary register.">; + +def FeatureX3RegisterUsage + : SubtargetFeature<"x3-reg-usage", "HasX3Usage", "true", "Has the purpose of X3 been defined.">; + +def HasX3Usage + : Predicate<"Subtarget->HasXReg3Usage()">, + AssemblerPredicate<(any_of FeatureX3Unknown, FeatureX3GP, FeatureX3SCS, + FeatureX3Tmp), "Has the purpose of X3 been defined.">; + diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp index cb41577c5d943..ac0d703cc7269 100644 --- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp @@ -72,6 +72,12 @@ static void emitSCSPrologue(MachineFunction &MF, MachineBasicBlock &MBB, return; } + // Incompatibility checks are handled in RISCVTargetStreamer, but it is + // possible this IR doesn't have the subtarget feature, e.g. because of LTO. + if (!STI.hasFeature(RISCV::FeatureX3SCS)) + report_fatal_error("Cannot use the software based RISCV shadow call stack " + "without setting the ABI tag `+x3-scs`."); + Register SCSPReg = RISCVABI::getSCSPReg(); bool IsRV64 = STI.hasFeature(RISCV::Feature64Bit); diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.h b/llvm/lib/Target/RISCV/RISCVSubtarget.h index 85f8f5f654fe7..007eb28dbd5da 100644 --- a/llvm/lib/Target/RISCV/RISCVSubtarget.h +++ b/llvm/lib/Target/RISCV/RISCVSubtarget.h @@ -142,6 +142,8 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo { bool GETTER() const { return ATTRIBUTE; } #include "RISCVGenSubtargetInfo.inc" + bool hasX3RegUsage() const { return X3Unknown || X3GP || X3SCS || X3Tmp; } + bool hasStdExtCOrZca() const { return HasStdExtC || HasStdExtZca; } bool hasStdExtCOrZcd() const { return HasStdExtC || HasStdExtZcd; } bool hasStdExtCOrZcfOrZce() const { diff --git a/llvm/test/CodeGen/RISCV/attributes.ll b/llvm/test/CodeGen/RISCV/attributes.ll index 61b5e50c6d52f..c1ec4516eb8c9 100644 --- a/llvm/test/CodeGen/RISCV/attributes.ll +++ b/llvm/test/CodeGen/RISCV/attributes.ll @@ -256,6 +256,12 @@ ; RUN: llc -mtriple=riscv64 -mattr=+experimental-sspm %s -o - | FileCheck --check-prefix=RV64SSPM %s ; RUN: llc -mtriple=riscv64 -mattr=+experimental-supm %s -o - | FileCheck --check-prefix=RV64SUPM %s ; RUN: llc -mtriple=riscv64 -mattr=+experimental-ssqosid %s -o - | FileCheck --check-prefix=RV64SSQOSID %s +; RUN: llc -mtriple=riscv64 -mattr=+x3-unknown %s -o - | FileCheck --check-prefix=X3UNKNOWN %s +; RUN: llc -mtriple=riscv64 -mattr=+x3-gp %s -o - | FileCheck --check-prefix=X3GP %s +; RUN: llc -mtriple=riscv64 -mattr=+x3-scs %s -o - | FileCheck --check-prefix=X3SCS %s +; RUN: llc -mtriple=riscv64 -mattr=+x3-tmp %s -o - | FileCheck --check-prefix=X3TMP %s + +; RUN: not --crash llc -mtriple=riscv64 -mattr=+x3-tmp,+x3-gp < %s 2>&1 | FileCheck --check-prefix=X3ERR %s ; CHECK: .attribute 4, 16 @@ -512,6 +518,11 @@ ; RV64SSPM: .attribute 5, "rv64i2p1_sspm0p8" ; RV64SUPM: .attribute 5, "rv64i2p1_supm0p8" ; RV64SSQOSID: .attribute 5, "rv64i2p1_ssqosid1p0" +; X3UNKNOWN: .attribute 16, 0 +; X3GP: .attribute 16, 1 +; X3SCS: .attribute 16, 2 +; X3TMP: .attribute 16, 3 +; X3ERR: LLVM ERROR: Cannot set multiple ABIs for X3/GP define i32 @addi(i32 %a) { %1 = add i32 %a, 1 diff --git a/llvm/test/CodeGen/RISCV/saverestore-scs.ll b/llvm/test/CodeGen/RISCV/saverestore-scs.ll index 6072943b38477..b1f4950b17552 100644 --- a/llvm/test/CodeGen/RISCV/saverestore-scs.ll +++ b/llvm/test/CodeGen/RISCV/saverestore-scs.ll @@ -1,11 +1,11 @@ ;; Check that shadow call stack doesn't interfere with save/restore -; RUN: llc -mtriple=riscv32 < %s | FileCheck %s -check-prefix=RV32I -; RUN: llc -mtriple=riscv64 < %s | FileCheck %s -check-prefix=RV64I -; RUN: llc -mtriple=riscv32 -mattr=+save-restore < %s | FileCheck %s -check-prefix=RV32I-SR -; RUN: llc -mtriple=riscv64 -mattr=+save-restore < %s | FileCheck %s -check-prefix=RV64I-SR -; RUN: llc -mtriple=riscv32 -mattr=+f,+save-restore -target-abi=ilp32f < %s | FileCheck %s -check-prefix=RV32I-FP-SR -; RUN: llc -mtriple=riscv64 -mattr=+f,+d,+save-restore -target-abi=lp64d < %s | FileCheck %s -check-prefix=RV64I-FP-SR +; RUN: llc -mtriple=riscv32 -mattr=+x3-scs < %s | FileCheck %s -check-prefix=RV32I +; RUN: llc -mtriple=riscv64 -mattr=+x3-scs < %s | FileCheck %s -check-prefix=RV64I +; RUN: llc -mtriple=riscv32 -mattr=+x3-scs,+save-restore < %s | FileCheck %s -check-prefix=RV32I-SR +; RUN: llc -mtriple=riscv64 -mattr=+x3-scs,+save-restore < %s | FileCheck %s -check-prefix=RV64I-SR +; RUN: llc -mtriple=riscv32 -mattr=+x3-scs,+f,+save-restore -target-abi=ilp32f < %s | FileCheck %s -check-prefix=RV32I-FP-SR +; RUN: llc -mtriple=riscv64 -mattr=+x3-scs,+f,+d,+save-restore -target-abi=lp64d < %s | FileCheck %s -check-prefix=RV64I-FP-SR @var2 = global [30 x i32] zeroinitializer diff --git a/llvm/test/CodeGen/RISCV/shadowcallstack-missing-x3-attr.ll b/llvm/test/CodeGen/RISCV/shadowcallstack-missing-x3-attr.ll new file mode 100644 index 0000000000000..44dd20d20e194 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/shadowcallstack-missing-x3-attr.ll @@ -0,0 +1,23 @@ +; RUN: not --crash llc -mtriple=riscv32 < %s 2>&1 \ +; RUN: | FileCheck --check-prefix=X3ERR %s +; RUN: not --crash llc -mtriple=riscv64 < %s 2>&1 \ +; RUN: | FileCheck --check-prefix=X3ERR %s + +;; Its safe for Zicfiss not to set x3-scs. +; RUN: llc -mtriple=riscv64 < %s -mattr=+experimental-zicfiss \ +; RUN: | FileCheck --check-prefix=NOX3ERR %s + +;; It isn't safe w/ forced-sw-shadow-stack, though +; RUN: not --crash llc -mtriple=riscv64 <%s -mattr=+experimental-zicfiss,forced-sw-shadow-stack 2>&1 \ +; RUN: | FileCheck --check-prefix=X3ERR %s + +; X3ERR: LLVM ERROR: Cannot use the software based RISCV shadow call stack without setting the ABI tag `+x3-scs`. +; NOX3ERR-NOT: LLVM ERROR + +declare i32 @bar() + +define i32 @f1() shadowcallstack { + %res = call i32 @bar() + %res1 = add i32 %res, 1 + ret i32 %res +} diff --git a/llvm/test/CodeGen/RISCV/shadowcallstack.ll b/llvm/test/CodeGen/RISCV/shadowcallstack.ll index a320b44d2c6a8..a150c95cc4fa9 100644 --- a/llvm/test/CodeGen/RISCV/shadowcallstack.ll +++ b/llvm/test/CodeGen/RISCV/shadowcallstack.ll @@ -1,15 +1,15 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py -; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: llc -mtriple=riscv32 -verify-machineinstrs -mattr=+x3-scs < %s \ ; RUN: | FileCheck %s --check-prefix=RV32 -; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \ +; RUN: llc -mtriple=riscv64 -verify-machineinstrs -mattr=+x3-scs < %s \ ; RUN: | FileCheck %s --check-prefix=RV64 ; RUN: llc -mtriple=riscv32 -mattr=+experimental-zicfiss < %s \ ; RUN: -verify-machineinstrs | FileCheck %s --check-prefix=RV32-ZICFISS ; RUN: llc -mtriple=riscv64 -mattr=+experimental-zicfiss < %s \ ; RUN: -verify-machineinstrs | FileCheck %s --check-prefix=RV64-ZICFISS -; RUN: llc -mtriple=riscv32 -mattr=+experimental-zicfiss,forced-sw-shadow-stack \ +; RUN: llc -mtriple=riscv32 -mattr=+experimental-zicfiss,forced-sw-shadow-stack,+x3-scs \ ; RUN: -verify-machineinstrs < %s | FileCheck %s --check-prefix=RV32 -; RUN: llc -mtriple=riscv64 -mattr=+experimental-zicfiss,forced-sw-shadow-stack \ +; RUN: llc -mtriple=riscv64 -mattr=+experimental-zicfiss,forced-sw-shadow-stack,+x3-scs \ ; RUN: -verify-machineinstrs < %s | FileCheck %s --check-prefix=RV64 define void @f1() shadowcallstack { diff --git a/llvm/test/MC/RISCV/attribute.s b/llvm/test/MC/RISCV/attribute.s index 75b9c65ed1cc2..a1e8261d464af 100644 --- a/llvm/test/MC/RISCV/attribute.s +++ b/llvm/test/MC/RISCV/attribute.s @@ -27,3 +27,6 @@ .attribute atomic_abi, 0 # CHECK: attribute 14, 0 + +.attribute x3_reg_usage, 0 +# CHECK: attribute 16, 0 diff --git a/llvm/test/MC/RISCV/invalid-attribute.s b/llvm/test/MC/RISCV/invalid-attribute.s index 2ebf7ddc9aff8..5e317ef9e1948 100644 --- a/llvm/test/MC/RISCV/invalid-attribute.s +++ b/llvm/test/MC/RISCV/invalid-attribute.s @@ -36,3 +36,6 @@ .attribute atomic_abi, "16" # CHECK: [[@LINE-1]]:24: error: expected numeric constant + +.attribute x3_reg_usage, "16" +# CHECK: [[@LINE-1]]:26: error: expected numeric constant