Index: lib/Target/Sparc/Sparc.td =================================================================== --- lib/Target/Sparc/Sparc.td +++ lib/Target/Sparc/Sparc.td @@ -46,6 +46,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 @@ -56,7 +56,9 @@ public: 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 @@ -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 { @@ -1802,6 +1804,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 @@ -39,6 +39,7 @@ bool Is64Bit; bool HasHardQuad; bool UsePopc; + bool UseSoftFloat; SparcInstrInfo InstrInfo; SparcTargetLowering TLInfo; SelectionDAGTargetInfo TSInfo; @@ -72,6 +73,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()) Index: lib/Target/Sparc/SparcTargetMachine.h =================================================================== --- lib/Target/Sparc/SparcTargetMachine.h +++ lib/Target/Sparc/SparcTargetMachine.h @@ -22,7 +22,8 @@ class SparcTargetMachine : public LLVMTargetMachine { std::unique_ptr TLOF; - SparcSubtarget Subtarget; + bool is64Bit; + 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 @@ -61,13 +61,48 @@ CodeGenOpt::Level OL, bool is64bit) : LLVMTargetMachine(T, computeDataLayout(TT, is64bit), TT, CPU, FS, Options, RM, CM, OL), - TLOF(make_unique()), - Subtarget(TT, CPU, FS, *this, is64bit) { + TLOF(make_unique()) { initAsmInfo(); + this->is64Bit = is64bit; } 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, + this->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 +}