diff --git a/lld/test/ELF/lto/riscv-incompatible-attributes.ll b/lld/test/ELF/lto/riscv-incompatible-attributes.ll new file mode 100644 --- /dev/null +++ b/lld/test/ELF/lto/riscv-incompatible-attributes.ll @@ -0,0 +1,17 @@ +; REQUIRES: riscv + +; RUN: llvm-as %S/Inputs/riscv-attributes1.ll -o %t1.o +; RUN: llvm-as %S/Inputs/riscv-attributes2.ll -o %t2.o +; RUN: llvm-as %s -o %t3.o +; RUN: not ld.lld %t1.o %t2.o %t3.o -o %t 2> %t.err +; RUN: FileCheck %s --input-file %t.err + +; CHECK: standard extension 'zfinx' can't be specified with extension 'f' + +target datalayout = "e-m:e-p:32:32-i64:64-n32-S128" +target triple = "riscv32-unknown-linux-gnu" +attributes #0 = { "frame-pointer"="none" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+32bit,+i,+a,+m,+zfinx,-relax,-save-restore" } + +define void @main() #0 { + ret void +} diff --git a/lld/test/ELF/lto/riscv-merge-attributes.ll b/lld/test/ELF/lto/riscv-merge-attributes.ll --- a/lld/test/ELF/lto/riscv-merge-attributes.ll +++ b/lld/test/ELF/lto/riscv-merge-attributes.ll @@ -9,10 +9,10 @@ ; CHECK: BuildAttributes { ; CHECK-NEXT: FormatVersion: 0x41 ; CHECK-NEXT: Section 1 { -; CHECK-NEXT: SectionLength: 27 +; CHECK-NEXT: SectionLength: 59 ; CHECK-NEXT: Vendor: riscv ; CHECK-NEXT: Tag: Tag_File (0x1) -; CHECK-NEXT: Size: 17 +; CHECK-NEXT: Size: 49 ; CHECK-NEXT: FileAttributes { ; CHECK-NEXT: Attribute { ; CHECK-NEXT: Tag: 4 @@ -23,7 +23,7 @@ ; CHECK-NEXT: Attribute { ; CHECK-NEXT: Tag: 5 ; CHECK-NEXT: TagName: arch -; CHECK-NEXT: Value: rv32i2p1 +; CHECK-NEXT: Value: rv32i2p0_m2p0_a2p0_f2p0_d2p0_c2p0_zbb1p0 ; CHECK-NEXT: } ; CHECK-NEXT: } ; CHECK-NEXT: } diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -200,6 +200,14 @@ } } +static void mergeFnTargetFeatures(SubtargetFeatures &Features, Module &Mod) { + for (Function &F : Mod) { + Attribute FSAttr = F.getFnAttribute("target-features"); + if (FSAttr.isValid()) + Features.AddFeature(FSAttr.getValueAsString()); + } +} + static std::unique_ptr createTargetMachine(const Config &Conf, const Target *TheTarget, Module &M) { StringRef TheTriple = M.getTargetTriple(); @@ -208,6 +216,8 @@ for (const std::string &A : Conf.MAttrs) Features.AddFeature(A); + mergeFnTargetFeatures(Features, M); + std::optional RelocModel; if (Conf.RelocModel) RelocModel = *Conf.RelocModel; diff --git a/llvm/lib/Support/RISCVISAInfo.cpp b/llvm/lib/Support/RISCVISAInfo.cpp --- a/llvm/lib/Support/RISCVISAInfo.cpp +++ b/llvm/lib/Support/RISCVISAInfo.cpp @@ -793,7 +793,15 @@ // Additional dependency checks. // TODO: The 'q' extension requires rv64. - // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'. + if ((HasF || HasD) && HasE) + return createStringError(errc::invalid_argument, + "standard user-level extension 'e' can't be " + "specified with extensions 'f' and 'd'"); + + if (HasF && HasZfinx) + return createStringError( + errc::invalid_argument, + "standard extension 'zfinx' can't be specified with extension 'f'"); return Error::success(); } 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 @@ -258,8 +258,10 @@ // Use computeTargetABI to check if ABIName is valid. If invalid, output // error message. - RISCVABI::computeTargetABI(STI.getTargetTriple(), STI.getFeatureBits(), - ABIName); + auto ABIInfo = RISCVABI::computeTargetABI(STI.getTargetTriple(), + STI.getFeatureBits(), ABIName); + if (!ABIInfo) + report_fatal_error(ABIInfo.takeError()); const MCObjectFileInfo *MOFI = Parser.getContext().getObjectFileInfo(); ParserOptions.IsPicEnabled = MOFI->isPositionIndependent(); diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h @@ -390,8 +390,8 @@ // Returns the target ABI, or else a StringError if the requested ABIName is // not supported for the given TT and FeatureBits combination. -ABI computeTargetABI(const Triple &TT, FeatureBitset FeatureBits, - StringRef ABIName); +Expected computeTargetABI(const Triple &TT, FeatureBitset FeatureBits, + StringRef ABIName); ABI getTargetABI(StringRef ABIName); diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp @@ -36,8 +36,8 @@ } // namespace RISCVInsnOpcode namespace RISCVABI { -ABI computeTargetABI(const Triple &TT, FeatureBitset FeatureBits, - StringRef ABIName) { +Expected computeTargetABI(const Triple &TT, FeatureBitset FeatureBits, + StringRef ABIName) { auto TargetABI = getTargetABI(ABIName); bool IsRV64 = TT.isArch64Bit(); bool IsRV32E = FeatureBits[RISCV::FeatureRV32E]; @@ -67,7 +67,7 @@ // If no explicit ABI is given, try to compute the default ABI. auto ISAInfo = RISCVFeatures::parseFeatureBits(IsRV64, FeatureBits); if (!ISAInfo) - report_fatal_error(ISAInfo.takeError()); + return std::move(ISAInfo.takeError()); return getTargetABI((*ISAInfo)->computeDefaultABI()); } 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 @@ -35,8 +35,13 @@ MCAssembler &MCA = getStreamer().getAssembler(); const FeatureBitset &Features = STI.getFeatureBits(); auto &MAB = static_cast(MCA.getBackend()); - setTargetABI(RISCVABI::computeTargetABI(STI.getTargetTriple(), Features, - MAB.getTargetOptions().getABIName())); + auto ABIInfo = RISCVABI::computeTargetABI( + STI.getTargetTriple(), Features, MAB.getTargetOptions().getABIName()); + if (!ABIInfo) { + errs() << toString(ABIInfo.takeError()); + exit(1); + } + setTargetABI(*ABIInfo); } RISCVELFStreamer &RISCVTargetELFStreamer::getStreamer() { diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp --- a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp +++ b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp @@ -68,7 +68,10 @@ XLen = 64; } - TargetABI = RISCVABI::computeTargetABI(TT, getFeatureBits(), ABIName); + auto ABIInfo = RISCVABI::computeTargetABI(TT, getFeatureBits(), ABIName); + if (!ABIInfo) + report_fatal_error(ABIInfo.takeError()); + TargetABI = *ABIInfo; RISCVFeatures::validate(TT, getFeatureBits()); return *this; } diff --git a/llvm/test/MC/RISCV/target-abi-invalid.s b/llvm/test/MC/RISCV/target-abi-invalid.s --- a/llvm/test/MC/RISCV/target-abi-invalid.s +++ b/llvm/test/MC/RISCV/target-abi-invalid.s @@ -28,17 +28,11 @@ # RUN: | FileCheck -check-prefix=RV32IFD-LP64D %s # RUN: llvm-mc -triple=riscv32 -mattr=+e -target-abi lp64 < %s 2>&1 \ # RUN: | FileCheck -check-prefix=RV32E-LP64 %s -# RUN: llvm-mc -triple=riscv32 -mattr=+e,+f -target-abi lp64f < %s 2>&1 \ -# RUN: | FileCheck -check-prefix=RV32EF-LP64F %s -# RUN: llvm-mc -triple=riscv32 -mattr=+e,+d -target-abi lp64f < %s 2>&1 \ -# RUN: | FileCheck -check-prefix=RV32EFD-LP64D %s # RV32I-LP64: 64-bit ABIs are not supported for 32-bit targets (ignoring target-abi) # RV32IF-LP64F: 64-bit ABIs are not supported for 32-bit targets (ignoring target-abi) # RV32IFD-LP64D: 64-bit ABIs are not supported for 32-bit targets (ignoring target-abi) # RV32E-LP64: 64-bit ABIs are not supported for 32-bit targets (ignoring target-abi) -# RV32EF-LP64F: 64-bit ABIs are not supported for 32-bit targets (ignoring target-abi) -# RV32EFD-LP64D: 64-bit ABIs are not supported for 32-bit targets (ignoring target-abi) # RUN: llvm-mc -triple=riscv32 -target-abi ilp32f < %s 2>&1 \ # RUN: | FileCheck -check-prefix=RV32I-ILP32F %s @@ -63,17 +57,8 @@ # RV64IF-LP64D: Hard-float 'd' ABI can't be used for a target that doesn't support the D instruction set extension (ignoring target-abi) # RUN: llvm-mc -triple=riscv32 -mattr=+e -target-abi ilp32 < %s 2>&1 \ -# RUN: | FileCheck -check-prefix=RV32EF-ILP32F %s -# RUN: llvm-mc -triple=riscv32 -mattr=+e,+f -target-abi ilp32f < %s 2>&1 \ -# RUN: | FileCheck -check-prefix=RV32EF-ILP32F %s -# RUN: llvm-mc -triple=riscv32 -mattr=+e,+d -target-abi ilp32f < %s 2>&1 \ -# RUN: | FileCheck -check-prefix=RV32EFD-ILP32F %s -# RUN: llvm-mc -triple=riscv32 -mattr=+e,+d -target-abi ilp32d < %s 2>&1 \ -# RUN: | FileCheck -check-prefix=RV32EFD-ILP32D %s +# RUN: | FileCheck -check-prefix=RV32E-ILP32 %s # RV32E-ILP32: Only the ilp32e ABI is supported for RV32E (ignoring target-abi) -# RV32EF-ILP32F: Only the ilp32e ABI is supported for RV32E (ignoring target-abi) -# RV32EFD-ILP32F: Only the ilp32e ABI is supported for RV32E (ignoring target-abi) -# RV32EFD-ILP32D: Only the ilp32e ABI is supported for RV32E (ignoring target-abi) nop