diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.h b/llvm/lib/Target/RISCV/RISCVTargetMachine.h --- a/llvm/lib/Target/RISCV/RISCVTargetMachine.h +++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.h @@ -22,7 +22,7 @@ namespace llvm { class RISCVTargetMachine : public LLVMTargetMachine { std::unique_ptr TLOF; - RISCVSubtarget Subtarget; + mutable StringMap> SubtargetMap; public: RISCVTargetMachine(const Target &T, const Triple &TT, StringRef CPU, @@ -30,9 +30,11 @@ Optional RM, Optional CM, CodeGenOpt::Level OL, bool JIT); - const RISCVSubtarget *getSubtargetImpl(const Function &) const override { - return &Subtarget; - } + const RISCVSubtarget *getSubtargetImpl(const Function &F) const override; + // DO NOT IMPLEMENT: There is no such thing as a valid default subtarget, + // subtargets are per-function entities based on the target-specific + // attributes of each function. + const RISCVSubtarget *getSubtargetImpl() const = delete; TargetPassConfig *createPassConfig(PassManagerBase &PM) override; diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp --- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp +++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp @@ -64,11 +64,34 @@ : LLVMTargetMachine(T, computeDataLayout(TT), TT, CPU, FS, Options, getEffectiveRelocModel(TT, RM), getEffectiveCodeModel(CM, CodeModel::Small), OL), - TLOF(std::make_unique()), - Subtarget(TT, CPU, FS, Options.MCOptions.getABIName(), *this) { + TLOF(std::make_unique()) { initAsmInfo(); } +const RISCVSubtarget * +RISCVTargetMachine::getSubtargetImpl(const Function &F) const { + Attribute CPUAttr = F.getFnAttribute("target-cpu"); + Attribute FSAttr = F.getFnAttribute("target-features"); + + std::string CPU = !CPUAttr.hasAttribute(Attribute::None) + ? CPUAttr.getValueAsString().str() + : TargetCPU; + std::string FS = !FSAttr.hasAttribute(Attribute::None) + ? FSAttr.getValueAsString().str() + : TargetFS; + std::string Key = CPU + FS; + auto &I = SubtargetMap[Key]; + if (!I) { + // This needs to be done before we create a new subtarget since any + // 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); + } + return I.get(); +} + TargetTransformInfo RISCVTargetMachine::getTargetTransformInfo(const Function &F) { return TargetTransformInfo(RISCVTTIImpl(this, F)); diff --git a/llvm/test/CodeGen/RISCV/subtarget-features-std-ext.ll b/llvm/test/CodeGen/RISCV/subtarget-features-std-ext.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/subtarget-features-std-ext.ll @@ -0,0 +1,15 @@ +; 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 + +; 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 + %conv = sitofp i32 %a to float + ret float %conv +} + +attributes #0 = { "target-features"="+f"}