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 @@ -1,4 +1,4 @@ -//===-- SparcISelLowering.h - Sparc DAG Lowering Interface ------*- C++ -*-===// + // // The LLVM Compiler Infrastructure // @@ -56,7 +56,9 @@ public: SparcTargetLowering(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 { @@ -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; @@ -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()) 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 +}