Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -537,6 +537,13 @@ getModule().addModuleFlag(llvm::Module::Error, "min_enum_size", EnumWidth); } + if (Arch == llvm::Triple::riscv32 || Arch == llvm::Triple::riscv64) { + StringRef ABIStr = Target.getABI(); + llvm::LLVMContext &Ctx = TheModule.getContext(); + getModule().addModuleFlag(llvm::Module::Error, "target-abi", + llvm::MDString::get(Ctx, ABIStr)); + } + if (CodeGenOpts.SanitizeCfiCrossDso) { // Indicate that we want cross-DSO control flow integrity checks. getModule().addModuleFlag(llvm::Module::Override, "Cross-DSO CFI", 1); Index: clang/lib/Driver/ToolChains/RISCVToolchain.h =================================================================== --- clang/lib/Driver/ToolChains/RISCVToolchain.h +++ clang/lib/Driver/ToolChains/RISCVToolchain.h @@ -28,6 +28,7 @@ RuntimeLibType GetDefaultRuntimeLibType() const override; UnwindLibType GetUnwindLibType(const llvm::opt::ArgList &Args) const override; + bool HasNativeLLVMSupport() const override { return true; } void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; Index: clang/lib/Driver/ToolChains/RISCVToolchain.cpp =================================================================== --- clang/lib/Driver/ToolChains/RISCVToolchain.cpp +++ clang/lib/Driver/ToolChains/RISCVToolchain.cpp @@ -144,6 +144,12 @@ std::string Linker = getToolChain().GetProgramPath(getShortName()); + if (D.isUsingLTO()) { + assert(!Inputs.empty() && "Must have at least one input."); + AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0], + D.getLTOMode() == LTOK_Thin); + } + bool WantCRTs = !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles); Index: clang/test/CodeGen/riscv-metadata.c =================================================================== --- /dev/null +++ clang/test/CodeGen/riscv-metadata.c @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -triple riscv32 -target-abi ilp32 -emit-llvm -o - %s | FileCheck -check-prefix=ILP32 %s +// RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm -o - %s | FileCheck -check-prefix=ILP32F %s +// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-abi ilp32d -emit-llvm -o - %s | FileCheck -check-prefix=ILP32D %s +// RUN: %clang_cc1 -triple riscv64 -target-abi lp64 -emit-llvm -o - %s | FileCheck -check-prefix=LP64 %s +// RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-abi lp64f -emit-llvm -o - %s | FileCheck -check-prefix=LP64F %s +// RUN: %clang_cc1 -triple riscv64 -target-feature +d -target-abi lp64d -emit-llvm -o - %s | FileCheck -check-prefix=LP64D %s + +// ILP32: !{{[0-9]+}} = !{i32 1, !"target-abi", !"ilp32"} +// ILP32F: !{{[0-9]+}} = !{i32 1, !"target-abi", !"ilp32f"} +// ILP32D: !{{[0-9]+}} = !{i32 1, !"target-abi", !"ilp32d"} + +// LP64: !{{[0-9]+}} = !{i32 1, !"target-abi", !"lp64"} +// LP64F: !{{[0-9]+}} = !{i32 1, !"target-abi", !"lp64f"} +// LP64D: !{{[0-9]+}} = !{i32 1, !"target-abi", !"lp64d"} Index: clang/test/Driver/gold-lto.c =================================================================== --- clang/test/Driver/gold-lto.c +++ clang/test/Driver/gold-lto.c @@ -26,3 +26,15 @@ // RUN: %clang -target i686-linux-android -### %t.o -flto 2>&1 \ // RUN: | FileCheck %s --check-prefix=CHECK-X86-ANDROID // CHECK-X86-ANDROID: "-plugin" "{{.*}}{{[/\\]}}LLVMgold.{{dll|dylib|so}}" +// +//RUN: %clang -target riscv64-unknown-elf -### %t.o -flto 2>&1 \ +//RUN: -march=rv64imf -mabi=lp64f \ +//RUN: | FileCheck %s --check-prefix=CHECK-RISCV-BAREMETAL +// +//CHECK-RISCV-BAREMETAL: "-plugin" "{{.*}}{{[/\\]}}LLVMgold.{{dll|dylib|so}}" +// +//RUN: %clang -target riscv64-unknown-linux-gnu -### %t.o -flto 2>&1 \ +//RUN: -march=rv64imf -mabi=lp64f \ +//RUN: | FileCheck %s --check-prefix=CHECK-RISCV-LINUX +// +//CHECK-RISCV-LINUX: "-plugin" "{{.*}}{{[/\\]}}LLVMgold.{{dll|dylib|so}}" Index: llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp =================================================================== --- llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -188,6 +188,18 @@ Parser.addAliasForDirective(".word", ".4byte"); Parser.addAliasForDirective(".dword", ".8byte"); setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); + + if (Options.ABIName.back() == 'f' && + !getSTI().getFeatureBits()[RISCV::FeatureStdExtF]) { + errs() << "Hard-float 'f' ABI can't be used for a target that " + "doesn't support the F instruction set extension (ignoring " + "target-abi)\n"; + } else if (Options.ABIName.back() == 'd' && + !getSTI().getFeatureBits()[RISCV::FeatureStdExtD]) { + errs() << "Hard-float 'd' ABI can't be used for a target that " + "doesn't support the D instruction set extension (ignoring " + "target-abi)\n"; + } } }; Index: llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h =================================================================== --- llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h +++ llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h @@ -27,7 +27,8 @@ bool Is64Bit; bool ForceRelocs = false; const MCTargetOptions &TargetOptions; - RISCVABI::ABI TargetABI = RISCVABI::ABI_Unknown; + mutable RISCVABI::ABI TargetABI = RISCVABI::ABI_Unknown; + mutable bool ABIComputeOnDemand = true; public: RISCVAsmBackend(const MCSubtargetInfo &STI, uint8_t OSABI, bool Is64Bit, @@ -141,8 +142,17 @@ bool writeNopData(raw_ostream &OS, uint64_t Count) const override; - const MCTargetOptions &getTargetOptions() const { return TargetOptions; } - RISCVABI::ABI getTargetABI() const { return TargetABI; } + // The TargetOptions.ABIName will changed when the target-abi is passed by + // module flags, so we recompute the Targe ABI on-demand. + RISCVABI::ABI getTargetABI() const { + if (ABIComputeOnDemand) { + TargetABI = RISCVABI::computeTargetABI(STI.getTargetTriple(), + STI.getFeatureBits(), + TargetOptions.getABIName()); + ABIComputeOnDemand = false; + } + return TargetABI; + } }; } Index: llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h =================================================================== --- llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h +++ llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h @@ -15,6 +15,8 @@ namespace llvm { class RISCVTargetELFStreamer : public RISCVTargetStreamer { + const MCSubtargetInfo &STI; + public: MCELFStreamer &getStreamer(); RISCVTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI); @@ -25,6 +27,7 @@ virtual void emitDirectiveOptionNoRVC(); virtual void emitDirectiveOptionRelax(); virtual void emitDirectiveOptionNoRelax(); + virtual void finish() override; }; } #endif Index: llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp =================================================================== --- llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp +++ llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp @@ -22,7 +22,20 @@ // This part is for ELF object output. RISCVTargetELFStreamer::RISCVTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI) - : RISCVTargetStreamer(S) { + : RISCVTargetStreamer(S), STI(STI) {} + +MCELFStreamer &RISCVTargetELFStreamer::getStreamer() { + return static_cast(Streamer); +} + +void RISCVTargetELFStreamer::emitDirectiveOptionPush() {} +void RISCVTargetELFStreamer::emitDirectiveOptionPop() {} +void RISCVTargetELFStreamer::emitDirectiveOptionRVC() {} +void RISCVTargetELFStreamer::emitDirectiveOptionNoRVC() {} +void RISCVTargetELFStreamer::emitDirectiveOptionRelax() {} +void RISCVTargetELFStreamer::emitDirectiveOptionNoRelax() {} + +void RISCVTargetELFStreamer::finish() { MCAssembler &MCA = getStreamer().getAssembler(); const FeatureBitset &Features = STI.getFeatureBits(); auto &MAB = static_cast(MCA.getBackend()); @@ -55,14 +68,3 @@ MCA.setELFHeaderEFlags(EFlags); } - -MCELFStreamer &RISCVTargetELFStreamer::getStreamer() { - return static_cast(Streamer); -} - -void RISCVTargetELFStreamer::emitDirectiveOptionPush() {} -void RISCVTargetELFStreamer::emitDirectiveOptionPop() {} -void RISCVTargetELFStreamer::emitDirectiveOptionRVC() {} -void RISCVTargetELFStreamer::emitDirectiveOptionNoRVC() {} -void RISCVTargetELFStreamer::emitDirectiveOptionRelax() {} -void RISCVTargetELFStreamer::emitDirectiveOptionNoRelax() {} Index: llvm/lib/Target/RISCV/RISCVISelLowering.cpp =================================================================== --- llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -51,6 +51,20 @@ RISCVABI::ABI ABI = Subtarget.getTargetABI(); assert(ABI != RISCVABI::ABI_Unknown && "Improperly initialised target ABI"); + if ((ABI == RISCVABI::ABI_ILP32F || ABI == RISCVABI::ABI_LP64F) && + !Subtarget.hasStdExtF()) { + errs() << "Hard-float 'f' ABI can't be used for a target that " + "doesn't support the F instruction set extension (ignoring " + "target-abi)\n"; + ABI = Subtarget.is64Bit() ? RISCVABI::ABI_LP64 : RISCVABI::ABI_ILP32; + } else if ((ABI == RISCVABI::ABI_ILP32D || ABI == RISCVABI::ABI_LP64D) && + !Subtarget.hasStdExtD()) { + errs() << "Hard-float 'd' ABI can't be used for a target that " + "doesn't support the D instruction set extension (ignoring " + "target-abi)\n"; + ABI = Subtarget.is64Bit() ? RISCVABI::ABI_LP64 : RISCVABI::ABI_ILP32; + } + switch (ABI) { default: report_fatal_error("Don't know how to lower this ABI"); Index: llvm/lib/Target/RISCV/RISCVTargetMachine.cpp =================================================================== --- llvm/lib/Target/RISCV/RISCVTargetMachine.cpp +++ llvm/lib/Target/RISCV/RISCVTargetMachine.cpp @@ -15,6 +15,7 @@ #include "RISCVTargetObjectFile.h" #include "RISCVTargetTransformInfo.h" #include "TargetInfo/RISCVTargetInfo.h" +#include "Utils/RISCVBaseInfo.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/CodeGen/GlobalISel/IRTranslator.h" @@ -89,8 +90,22 @@ // creation will depend on the TM and the code generation flags on the // function that reside in TargetOptions. resetTargetOptions(F); - I = std::make_unique(TargetTriple, CPU, FS, - Options.MCOptions.getABIName(), *this); + auto ABIName = Options.MCOptions.getABIName(); + if (const MDString *ModuleTargetABI = dyn_cast_or_null( + F.getParent()->getModuleFlag("target-abi"))) { + auto TargetABI = RISCVABI::getTargetABI(ABIName); + if (TargetABI != RISCVABI::ABI_Unknown && + ModuleTargetABI->getString() != ABIName) { + errs() << "-target-abi option != target-abi module flag(ignoring " + "target-abi option)\n"; + } + ABIName = ModuleTargetABI->getString(); + // update MCoptions.ABIName because we can't update ABI info of + // MCAsmBackend in current stage. + this->Options.MCOptions.ABIName = ABIName; + } + + I = std::make_unique(TargetTriple, CPU, FS, ABIName, *this); } return I.get(); } Index: llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.h =================================================================== --- llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.h +++ llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.h @@ -202,6 +202,8 @@ ABI computeTargetABI(const Triple &TT, FeatureBitset FeatureBits, StringRef ABIName); +ABI getTargetABI(StringRef ABIName); + // Returns the register used to hold the stack pointer after realignment. Register getBPReg(); Index: llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.cpp =================================================================== --- llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.cpp +++ llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.cpp @@ -12,16 +12,7 @@ namespace RISCVABI { ABI computeTargetABI(const Triple &TT, FeatureBitset FeatureBits, StringRef ABIName) { - auto TargetABI = StringSwitch(ABIName) - .Case("ilp32", ABI_ILP32) - .Case("ilp32f", ABI_ILP32F) - .Case("ilp32d", ABI_ILP32D) - .Case("ilp32e", ABI_ILP32E) - .Case("lp64", ABI_LP64) - .Case("lp64f", ABI_LP64F) - .Case("lp64d", ABI_LP64D) - .Default(ABI_Unknown); - + auto TargetABI = getTargetABI(ABIName); bool IsRV64 = TT.isArch64Bit(); bool IsRV32E = FeatureBits[RISCV::FeatureRV32E]; @@ -37,17 +28,8 @@ errs() << "64-bit ABIs are not supported for 32-bit targets (ignoring " "target-abi)\n"; TargetABI = ABI_Unknown; - } else if (ABIName.endswith("f") && !FeatureBits[RISCV::FeatureStdExtF]) { - errs() << "Hard-float 'f' ABI can't be used for a target that " - "doesn't support the F instruction set extension (ignoring " - "target-abi)\n"; - TargetABI = ABI_Unknown; - } else if (ABIName.endswith("d") && !FeatureBits[RISCV::FeatureStdExtD]) { - errs() << "Hard-float 'd' ABI can't be used for a target that " - "doesn't support the D instruction set extension (ignoring " - "target-abi)\n"; - TargetABI = ABI_Unknown; } else if (IsRV32E && TargetABI != ABI_ILP32E && TargetABI != ABI_Unknown) { + // TODO: move this checking to RISCVTargetLowering and RISCVAsmParser errs() << "Only the ilp32e ABI is supported for RV32E (ignoring target-abi)\n"; TargetABI = ABI_Unknown; @@ -67,6 +49,19 @@ return ABI_ILP32; } +ABI getTargetABI(StringRef ABIName) { + auto TargetABI = StringSwitch(ABIName) + .Case("ilp32", ABI_ILP32) + .Case("ilp32f", ABI_ILP32F) + .Case("ilp32d", ABI_ILP32D) + .Case("ilp32e", ABI_ILP32E) + .Case("lp64", ABI_LP64) + .Case("lp64f", ABI_LP64F) + .Case("lp64d", ABI_LP64D) + .Default(ABI_Unknown); + return TargetABI; +} + // To avoid the BP value clobbered by a function call, we need to choose a // callee saved register to save the value. RV32E only has X8 and X9 as callee // saved registers and X8 will be used as fp. So we choose X9 as bp. Index: llvm/test/CodeGen/RISCV/module-target-abi.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/RISCV/module-target-abi.ll @@ -0,0 +1,24 @@ +; RUN: llc -mtriple=riscv32 < %s 2>&1 \ +; RUN: | FileCheck -check-prefix=DEFAULT %s +; RUN: llc -mtriple=riscv32 -target-abi ilp32 < %s 2>&1 \ +; RUN: | FileCheck -check-prefix=RV32IF-ILP32 %s +; RUN: llc -mtriple=riscv32 -target-abi ilp32f < %s 2>&1 \ +; RUN: | FileCheck -check-prefix=RV32IF-ILP32F %s +; RUN: llc -mtriple=riscv32 -filetype=obj < %s | llvm-readelf -h - | FileCheck -check-prefixes=FLAGS %s + +; RV32IF-ILP32F: -target-abi option != target-abi module flag(ignoring target-abi option) + +; FLAGS: Flags: 0x0 + +define float @foo(i32 %a) nounwind #0 { +; DEFAULT: # %bb.0: +; DEFAULT: fmv.x.w a0, ft0 +; RV32IF-ILP32: # %bb.0: +; RV32IF-ILP32: fmv.x.w a0, ft0 + %conv = sitofp i32 %a to float + ret float %conv +} + +attributes #0 = { "target-features"="+f"} +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"target-abi", !"ilp32"} Index: llvm/test/CodeGen/RISCV/subtarget-features-std-ext.ll =================================================================== --- llvm/test/CodeGen/RISCV/subtarget-features-std-ext.ll +++ llvm/test/CodeGen/RISCV/subtarget-features-std-ext.ll @@ -2,12 +2,17 @@ ; RUN: | FileCheck -check-prefix=RV32IF-ILP32 %s ; RUN: llc -mtriple=riscv32 -target-abi ilp32f < %s 2>&1 \ ; RUN: | FileCheck -check-prefix=RV32IF-ILP32F %s +; RUN: llc -mtriple=riscv32 -mattr=-f -target-abi ilp32f <%s 2>&1 \ +; RUN: | FileCheck -check-prefix=RV32I-ILP32F-FAILED %s + +; RV32I-ILP32F-FAILED: Hard-float 'f' ABI can't be used for a target that doesn't support the F instruction set extension -; RV32IF-ILP32F: Hard-float 'f' ABI can't be used for a target that doesn't support the F instruction set extension (ignoring target-abi) define float @foo(i32 %a) nounwind #0 { -; RV32IF-ILP32: # %bb.0: -; RV32IF-ILP32-NEXT: fcvt.s.w ft0, a0 +; RV32IF-ILP32: fcvt.s.w ft0, a0 +; RV32IF-ILP32-NEXT: fmv.x.w a0, ft0 +; RV32IF-ILP32F: fcvt.s.w fa0, a0 +; RV32IF-ILP32F-NEXT: ret %conv = sitofp i32 %a to float ret float %conv } Index: llvm/test/CodeGen/RISCV/subtarget-features-target-abi.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/RISCV/subtarget-features-target-abi.ll @@ -0,0 +1,26 @@ +; RUN: llc -mtriple=riscv32 < %s 2>&1 \ +; RUN: | FileCheck -check-prefix=DEFAULT %s +; RUN: llc -mtriple=riscv32 -target-abi ilp32 < %s 2>&1 \ +; RUN: | FileCheck -check-prefix=RV32IF-ILP32 %s +; RUN: llc -mtriple=riscv32 -target-abi ilp32f < %s 2>&1 \ +; RUN: | FileCheck -check-prefix=RV32IF-ILP32F %s +; RUN: llc -mtriple=riscv32 -filetype=obj < %s | llvm-readelf -h - | FileCheck -check-prefixes=FLAGS %s + +; RV32IF-ILP32: -target-abi option != target-abi module flag(ignoring target-abi option) + +; FLAGS: Flags: 0x2, single-float ABI + +define float @foo(i32 %a) nounwind #0 { +; DEFAULT: # %bb.0: +; DEFAULT-NEXT: fcvt.s.w fa0, a0 +; DEFAULT-NEXT: ret +; RV32IF-ILP32F: # %bb.0: +; RV32IF-ILP32F-NEXT: fcvt.s.w fa0, a0 +; RV32IF-ILP32F-NEXT: ret + %conv = sitofp i32 %a to float + ret float %conv +} + +attributes #0 = { "target-features"="+f"} +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"target-abi", !"ilp32f"}