Index: lib/Target/Sparc/Sparc.td =================================================================== --- lib/Target/Sparc/Sparc.td +++ lib/Target/Sparc/Sparc.td @@ -43,6 +43,9 @@ def UsePopc : SubtargetFeature<"popc", "UsePopc", "true", "Use the popc (population count) instruction">; +def FeatureSoftFloat : SubtargetFeature<"soft-float", "UseSoftFloat", "true", + "Use software emulation for floating point">; + //===----------------------------------------------------------------------===// // Register File, Calling Conv, Instruction Descriptions //===----------------------------------------------------------------------===// Index: lib/Target/Sparc/SparcISelLowering.h =================================================================== --- lib/Target/Sparc/SparcISelLowering.h +++ lib/Target/Sparc/SparcISelLowering.h @@ -54,9 +54,11 @@ class SparcTargetLowering : public TargetLowering { const SparcSubtarget *Subtarget; public: - SparcTargetLowering(TargetMachine &TM, const SparcSubtarget &STI); + SparcTargetLowering(const TargetMachine &TM, const SparcSubtarget &STI); SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; - + + bool useSoftFloat() const override; + /// computeKnownBitsForTargetNode - Determine which of the bits specified /// in Mask are known to be either zero or one and return them in the /// KnownZero/KnownOne bitsets. Index: lib/Target/Sparc/SparcISelLowering.cpp =================================================================== --- lib/Target/Sparc/SparcISelLowering.cpp +++ lib/Target/Sparc/SparcISelLowering.cpp @@ -1448,7 +1448,7 @@ } } -SparcTargetLowering::SparcTargetLowering(TargetMachine &TM, +SparcTargetLowering::SparcTargetLowering(const TargetMachine &TM, const SparcSubtarget &STI) : TargetLowering(TM), Subtarget(&STI) { MVT PtrVT = MVT::getIntegerVT(8 * TM.getPointerSize()); @@ -1463,9 +1463,11 @@ // Set up the register classes. addRegisterClass(MVT::i32, &SP::IntRegsRegClass); - addRegisterClass(MVT::f32, &SP::FPRegsRegClass); - addRegisterClass(MVT::f64, &SP::DFPRegsRegClass); - addRegisterClass(MVT::f128, &SP::QFPRegsRegClass); + if (!Subtarget->useSoftFloat()) { + addRegisterClass(MVT::f32, &SP::FPRegsRegClass); + addRegisterClass(MVT::f64, &SP::DFPRegsRegClass); + addRegisterClass(MVT::f128, &SP::QFPRegsRegClass); + } if (Subtarget->is64Bit()) { addRegisterClass(MVT::i64, &SP::I64RegsRegClass); } else { @@ -1804,6 +1806,10 @@ computeRegisterProperties(Subtarget->getRegisterInfo()); } +bool SparcTargetLowering::useSoftFloat() const { + return Subtarget->useSoftFloat(); +} + const char *SparcTargetLowering::getTargetNodeName(unsigned Opcode) const { switch ((SPISD::NodeType)Opcode) { case SPISD::FIRST_NUMBER: break; Index: lib/Target/Sparc/SparcSubtarget.h =================================================================== --- lib/Target/Sparc/SparcSubtarget.h +++ lib/Target/Sparc/SparcSubtarget.h @@ -37,6 +37,7 @@ bool Is64Bit; bool HasHardQuad; bool UsePopc; + bool UseSoftFloat; SparcInstrInfo InstrInfo; SparcTargetLowering TLInfo; SelectionDAGTargetInfo TSInfo; @@ -44,7 +45,7 @@ public: SparcSubtarget(const Triple &TT, const std::string &CPU, - const std::string &FS, TargetMachine &TM, bool is64bit); + const std::string &FS, const TargetMachine &TM, bool is64bit); const SparcInstrInfo *getInstrInfo() const override { return &InstrInfo; } const TargetFrameLowering *getFrameLowering() const override { @@ -69,6 +70,7 @@ bool useDeprecatedV8Instructions() const { return V8DeprecatedInsts; } bool hasHardQuad() const { return HasHardQuad; } bool usePopc() const { return UsePopc; } + bool useSoftFloat() const { return UseSoftFloat; } /// ParseSubtargetFeatures - Parses features string setting specified /// subtarget options. Definition of function is auto generated by tblgen. Index: lib/Target/Sparc/SparcSubtarget.cpp =================================================================== --- lib/Target/Sparc/SparcSubtarget.cpp +++ lib/Target/Sparc/SparcSubtarget.cpp @@ -33,7 +33,8 @@ IsVIS = false; HasHardQuad = false; UsePopc = false; - + UseSoftFloat = false; + // Determine default and user specified characteristics std::string CPUName = CPU; if (CPUName.empty()) @@ -50,7 +51,7 @@ } SparcSubtarget::SparcSubtarget(const Triple &TT, const std::string &CPU, - const std::string &FS, TargetMachine &TM, + const std::string &FS, const TargetMachine &TM, bool is64Bit) : SparcGenSubtargetInfo(TT, CPU, FS), Is64Bit(is64Bit), InstrInfo(initializeSubtargetDependencies(CPU, FS)), TLInfo(TM, *this), Index: lib/Target/Sparc/SparcTargetMachine.h =================================================================== --- lib/Target/Sparc/SparcTargetMachine.h +++ lib/Target/Sparc/SparcTargetMachine.h @@ -23,6 +23,7 @@ class SparcTargetMachine : public LLVMTargetMachine { std::unique_ptr TLOF; SparcSubtarget Subtarget; + mutable StringMap> SubtargetMap; public: SparcTargetMachine(const Target &T, const Triple &TT, StringRef CPU, StringRef FS, const TargetOptions &Options, @@ -30,9 +31,8 @@ bool is64bit); ~SparcTargetMachine() override; - const SparcSubtarget *getSubtargetImpl(const Function &) const override { - return &Subtarget; - } + const SparcSubtarget *getSubtargetImpl(const Function &) const override; + // Pass Pipeline Configuration TargetPassConfig *createPassConfig(PassManagerBase &PM) override; Index: lib/Target/Sparc/SparcTargetMachine.cpp =================================================================== --- lib/Target/Sparc/SparcTargetMachine.cpp +++ lib/Target/Sparc/SparcTargetMachine.cpp @@ -68,6 +68,41 @@ SparcTargetMachine::~SparcTargetMachine() {} + +const SparcSubtarget * +SparcTargetMachine::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; + + // FIXME: This is related to the code below to reset the target options, + // we need to know whether or not the soft float flag is set on the + // function, so we can enable it as a subtarget feature. + bool softFloat = + F.hasFnAttribute("use-soft-float") && + F.getFnAttribute("use-soft-float").getValueAsString() == "true"; + + if (softFloat) + FS += FS.empty() ? "+soft-float" : ",+soft-float"; + + auto &I = SubtargetMap[CPU + FS]; + 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 = llvm::make_unique(TargetTriple, CPU, FS, *this, + Subtarget.is64Bit()); + } + return I.get(); +} + namespace { /// Sparc Code Generator Pass Configuration Options. class SparcPassConfig : public TargetPassConfig { Index: test/CodeGen/SPARC/softfloat.ll =================================================================== --- /dev/null +++ test/CodeGen/SPARC/softfloat.ll @@ -0,0 +1,136 @@ +; RUN: llc -march=sparc -mattr=soft-float -O0 < %s | FileCheck %s + +; Arithmetic functions +define double @test_add() #0 { +entry: + %a = alloca double, align 8 + %b = alloca double, align 8 + %0 = load double, double* %a, align 8 + %1 = load double, double* %b, align 8 + %add = fadd double %0, %1 + ret double %add + + ; CHECK-LABEL: __adddf3 +} + +define double @test_mul() #0 { +entry: + %a = alloca double, align 8 + %b = alloca double, align 8 + %0 = load double, double* %a, align 8 + %1 = load double, double* %b, align 8 + %mul = fmul double %0, %1 + ret double %mul + + ; CHECK-LABEL: __muldf3 +} + +define double @test_sub() #0 { +entry: + %a = alloca double, align 8 + %b = alloca double, align 8 + %0 = load double, double* %a, align 8 + %1 = load double, double* %b, align 8 + %sub = fsub double %0, %1 + ret double %sub + + ; CHECK-LABEL: __subdf3 +} + +define double @test_div() #0 { +entry: + %a = alloca double, align 8 + %b = alloca double, align 8 + %0 = load double, double* %a, align 8 + %1 = load double, double* %b, align 8 + %div = fdiv double %0, %1 + ret double %div + + ; CHECK-LABEL: __divdf3 +} + +; Comparison functions + +define i1 @test_unorddf2() #0 { +entry: + %a = alloca double, align 8 + %b = alloca double, align 8 + %0 = load double, double* %a, align 8 + %1 = load double, double* %b, align 8 + %cmp = fcmp uno double %0, %1 + ret i1 %cmp + + ; CHECK-LABEL: __unorddf2 +} + +define i1 @test_eqdf2() #0 { +entry: + %a = alloca double, align 8 + %b = alloca double, align 8 + %0 = load double, double* %a, align 8 + %1 = load double, double* %b, align 8 + %cmp = fcmp oeq double %0, %1 + ret i1 %cmp + + ; CHECK-LABEL: __eqdf2 +} + +define i1 @test_nedf2() #0 { +entry: + %a = alloca double, align 8 + %b = alloca double, align 8 + %0 = load double, double* %a, align 8 + %1 = load double, double* %b, align 8 + %cmp = fcmp une double %0, %1 + ret i1 %cmp + + ; CHECK-LABEL: __nedf2 +} + +define i1 @test_gedf2() #0 { +entry: + %a = alloca double, align 8 + %b = alloca double, align 8 + %0 = load double, double* %a, align 8 + %1 = load double, double* %b, align 8 + %cmp = fcmp oge double %0, %1 + ret i1 %cmp + + ; CHECK-LABEL: __gedf2 +} + +define i1 @test_ltdf2() #0 { +entry: + %a = alloca double, align 8 + %b = alloca double, align 8 + %0 = load double, double* %a, align 8 + %1 = load double, double* %b, align 8 + %cmp = fcmp olt double %0, %1 + ret i1 %cmp + + ; CHECK-LABEL: __ltdf2 +} + +define i1 @test_ledf2() #0 { +entry: + %a = alloca double, align 8 + %b = alloca double, align 8 + %0 = load double, double* %a, align 8 + %1 = load double, double* %b, align 8 + %cmp = fcmp ole double %0, %1 + ret i1 %cmp + + ; CHECK-LABEL: __ledf2 +} + +define i1 @test_gtdf2() #0 { +entry: + %a = alloca double, align 8 + %b = alloca double, align 8 + %0 = load double, double* %a, align 8 + %1 = load double, double* %b, align 8 + %cmp = fcmp ogt double %0, %1 + ret i1 %cmp + + ; CHECK-LABEL: __gtdf2 +}