[llvm] r269892 - [Sparc] Add Soft Float support

Chris Dewhurst via llvm-commits llvm-commits at lists.llvm.org
Wed May 18 02:14:14 PDT 2016


Author: lerochris
Date: Wed May 18 04:14:13 2016
New Revision: 269892

URL: http://llvm.org/viewvc/llvm-project?rev=269892&view=rev
Log:
[Sparc] Add Soft Float support

This change adds support for software floating point operations for Sparc targets.

This is the first in a set of patches to enable software floating point on Sparc. The next patch will enable the option to be used with Clang.

Differential Revision: http://reviews.llvm.org/D19265

Added:
    llvm/trunk/test/CodeGen/SPARC/soft-float.ll
Modified:
    llvm/trunk/lib/Target/Sparc/Sparc.td
    llvm/trunk/lib/Target/Sparc/SparcISelLowering.cpp
    llvm/trunk/lib/Target/Sparc/SparcISelLowering.h
    llvm/trunk/lib/Target/Sparc/SparcSubtarget.cpp
    llvm/trunk/lib/Target/Sparc/SparcSubtarget.h
    llvm/trunk/lib/Target/Sparc/SparcTargetMachine.cpp
    llvm/trunk/lib/Target/Sparc/SparcTargetMachine.h
    llvm/trunk/test/CodeGen/SPARC/32abi.ll
    llvm/trunk/test/CodeGen/SPARC/64abi.ll

Modified: llvm/trunk/lib/Target/Sparc/Sparc.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Sparc/Sparc.td?rev=269892&r1=269891&r2=269892&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Sparc/Sparc.td (original)
+++ llvm/trunk/lib/Target/Sparc/Sparc.td Wed May 18 04:14:13 2016
@@ -46,6 +46,9 @@ def FeatureHardQuad
 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">;  
+
 //==== Features added predmoninantly for LEON subtarget support                               
 include "LeonFeatures.td"
 

Modified: llvm/trunk/lib/Target/Sparc/SparcISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Sparc/SparcISelLowering.cpp?rev=269892&r1=269891&r2=269892&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Sparc/SparcISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/Sparc/SparcISelLowering.cpp Wed May 18 04:14:13 2016
@@ -1463,9 +1463,11 @@ SparcTargetLowering::SparcTargetLowering
 
   // 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 {
@@ -1760,7 +1762,7 @@ SparcTargetLowering::SparcTargetLowering
     setOperationAction(ISD::FP_ROUND,  MVT::f32, Custom);
 
     // Setup Runtime library names.
-    if (Subtarget->is64Bit()) {
+    if (Subtarget->is64Bit() && !Subtarget->useSoftFloat()) {
       setLibcallName(RTLIB::ADD_F128,  "_Qp_add");
       setLibcallName(RTLIB::SUB_F128,  "_Qp_sub");
       setLibcallName(RTLIB::MUL_F128,  "_Qp_mul");
@@ -1778,7 +1780,7 @@ SparcTargetLowering::SparcTargetLowering
       setLibcallName(RTLIB::FPEXT_F64_F128, "_Qp_dtoq");
       setLibcallName(RTLIB::FPROUND_F128_F32, "_Qp_qtos");
       setLibcallName(RTLIB::FPROUND_F128_F64, "_Qp_qtod");
-    } else {
+    } else if (!Subtarget->useSoftFloat()) {
       setLibcallName(RTLIB::ADD_F128,  "_Q_add");
       setLibcallName(RTLIB::SUB_F128,  "_Q_sub");
       setLibcallName(RTLIB::MUL_F128,  "_Q_mul");
@@ -1806,6 +1808,10 @@ SparcTargetLowering::SparcTargetLowering
   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;

Modified: llvm/trunk/lib/Target/Sparc/SparcISelLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Sparc/SparcISelLowering.h?rev=269892&r1=269891&r2=269892&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Sparc/SparcISelLowering.h (original)
+++ llvm/trunk/lib/Target/Sparc/SparcISelLowering.h Wed May 18 04:14:13 2016
@@ -59,7 +59,9 @@ namespace llvm {
   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.

Modified: llvm/trunk/lib/Target/Sparc/SparcSubtarget.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Sparc/SparcSubtarget.cpp?rev=269892&r1=269891&r2=269892&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Sparc/SparcSubtarget.cpp (original)
+++ llvm/trunk/lib/Target/Sparc/SparcSubtarget.cpp Wed May 18 04:14:13 2016
@@ -34,6 +34,7 @@ SparcSubtarget &SparcSubtarget::initiali
   IsVIS = false;
   HasHardQuad = false;
   UsePopc = false;
+  UseSoftFloat = false;
 
   // Leon features
   HasLeonCasa = false;

Modified: llvm/trunk/lib/Target/Sparc/SparcSubtarget.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Sparc/SparcSubtarget.h?rev=269892&r1=269891&r2=269892&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Sparc/SparcSubtarget.h (original)
+++ llvm/trunk/lib/Target/Sparc/SparcSubtarget.h Wed May 18 04:14:13 2016
@@ -39,6 +39,7 @@ class SparcSubtarget : public SparcGenSu
   bool Is64Bit;
   bool HasHardQuad;
   bool UsePopc;
+  bool UseSoftFloat;
 
   // LEON features
   bool HasUmacSmac;
@@ -77,6 +78,7 @@ public:
   bool useDeprecatedV8Instructions() const { return V8DeprecatedInsts; }
   bool hasHardQuad() const { return HasHardQuad; }
   bool usePopc() const { return UsePopc; }
+  bool useSoftFloat() const { return UseSoftFloat; }
 
   // Leon options
   bool hasUmacSmac() const { return HasUmacSmac; }

Modified: llvm/trunk/lib/Target/Sparc/SparcTargetMachine.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Sparc/SparcTargetMachine.cpp?rev=269892&r1=269891&r2=269892&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Sparc/SparcTargetMachine.cpp (original)
+++ llvm/trunk/lib/Target/Sparc/SparcTargetMachine.cpp Wed May 18 04:14:13 2016
@@ -62,13 +62,47 @@ SparcTargetMachine::SparcTargetMachine(c
                                        CodeGenOpt::Level OL, bool is64bit)
     : LLVMTargetMachine(T, computeDataLayout(TT, is64bit), TT, CPU, FS, Options,
                         RM, CM, OL),
-      TLOF(make_unique<SparcELFTargetObjectFile>()),
-      Subtarget(TT, CPU, FS, *this, is64bit) {
+      TLOF(make_unique<SparcELFTargetObjectFile>()) {
   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<SparcSubtarget>(TargetTriple, CPU, FS, *this,
+                                          this->is64Bit);
+  }
+  return I.get();
+}
+
 namespace {
 /// Sparc Code Generator Pass Configuration Options.
 class SparcPassConfig : public TargetPassConfig {

Modified: llvm/trunk/lib/Target/Sparc/SparcTargetMachine.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Sparc/SparcTargetMachine.h?rev=269892&r1=269891&r2=269892&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Sparc/SparcTargetMachine.h (original)
+++ llvm/trunk/lib/Target/Sparc/SparcTargetMachine.h Wed May 18 04:14:13 2016
@@ -22,7 +22,8 @@ namespace llvm {
 
 class SparcTargetMachine : public LLVMTargetMachine {
   std::unique_ptr<TargetLoweringObjectFile> TLOF;
-  SparcSubtarget Subtarget;
+  bool is64Bit;
+  mutable StringMap<std::unique_ptr<SparcSubtarget>> SubtargetMap;
 public:
   SparcTargetMachine(const Target &T, const Triple &TT, StringRef CPU,
                      StringRef FS, const TargetOptions &Options,
@@ -30,9 +31,7 @@ public:
                      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;

Modified: llvm/trunk/test/CodeGen/SPARC/32abi.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/SPARC/32abi.ll?rev=269892&r1=269891&r2=269892&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/SPARC/32abi.ll (original)
+++ llvm/trunk/test/CodeGen/SPARC/32abi.ll Wed May 18 04:14:13 2016
@@ -1,5 +1,6 @@
-; RUN: llc < %s -march=sparc -disable-sparc-delay-filler -disable-sparc-leaf-proc | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-BE
-; RUN: llc < %s -march=sparcel -disable-sparc-delay-filler -disable-sparc-leaf-proc | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-LE
+; RUN: llc < %s -march=sparc -disable-sparc-delay-filler -disable-sparc-leaf-proc | FileCheck %s --check-prefix=CHECK --check-prefix=HARD --check-prefix=CHECK-BE
+; RUN: llc < %s -march=sparcel -disable-sparc-delay-filler -disable-sparc-leaf-proc | FileCheck %s --check-prefix=CHECK --check-prefix=HARD --check-prefix=CHECK-LE
+; RUN: llc < %s -march=sparc -disable-sparc-delay-filler -disable-sparc-leaf-proc -mattr=soft-float | FileCheck %s --check-prefix=CHECK --check-prefix=SOFT --check-prefix=CHECK-BE
 
 ; CHECK-LABEL: intarg:
 ; The save/restore frame is not strictly necessary here, but we would need to
@@ -55,29 +56,80 @@ define void @call_intarg(i32 %i0, i8* %i
 ;; straddling the boundary of regs and mem, and floats in regs and mem.
 ;
 ; CHECK-LABEL: floatarg:
-; CHECK: save %sp, -120, %sp
-; CHECK: mov %i5, %g2
-; CHECK-NEXT: ld [%fp+92], %g3
-; CHECK-NEXT: mov %i4, %i5
-; CHECK-NEXT: std %g2, [%fp+-24]
-; CHECK-NEXT: mov %i3, %i4
-; CHECK-NEXT: std %i4, [%fp+-16]
-; CHECK-NEXT: std %i0, [%fp+-8]
-; CHECK-NEXT: st %i2, [%fp+-28]
-; CHECK-NEXT: ld [%fp+104], %f0
-; CHECK-NEXT: ldd [%fp+96], %f2
-; CHECK-NEXT: ld [%fp+-28], %f1
-; CHECK-NEXT: ldd [%fp+-8], %f4
-; CHECK-NEXT: ldd [%fp+-16], %f6
-; CHECK-NEXT: ldd [%fp+-24], %f8
-; CHECK-NEXT: fstod %f1, %f10
-; CHECK-NEXT: faddd %f4, %f10, %f4
-; CHECK-NEXT: faddd %f6, %f4, %f4
-; CHECK-NEXT: faddd %f8, %f4, %f4
-; CHECK-NEXT: faddd %f2, %f4, %f2
-; CHECK-NEXT: fstod %f0, %f0
-; CHECK-NEXT: faddd %f0, %f2, %f0
-; CHECK-NEXT: restore
+; HARD: save %sp, -120, %sp
+; HARD: mov %i5, %g2
+; HARD-NEXT: ld [%fp+92], %g3
+; HARD-NEXT: mov %i4, %i5
+; HARD-NEXT: std %g2, [%fp+-24]
+; HARD-NEXT: mov %i3, %i4
+; HARD-NEXT: std %i4, [%fp+-16]
+; HARD-NEXT: std %i0, [%fp+-8]
+; HARD-NEXT: st %i2, [%fp+-28]
+; HARD-NEXT: ld [%fp+104], %f0
+; HARD-NEXT: ldd [%fp+96], %f2
+; HARD-NEXT: ld [%fp+-28], %f1
+; HARD-NEXT: ldd [%fp+-8], %f4
+; HARD-NEXT: ldd [%fp+-16], %f6
+; HARD-NEXT: ldd [%fp+-24], %f8
+; HARD-NEXT: fstod %f1, %f10
+; HARD-NEXT: faddd %f4, %f10, %f4
+; HARD-NEXT: faddd %f6, %f4, %f4
+; HARD-NEXT: faddd %f8, %f4, %f4
+; HARD-NEXT: faddd %f2, %f4, %f2
+; HARD-NEXT: fstod %f0, %f0
+; HARD-NEXT: faddd %f0, %f2, %f0
+; SOFT: save %sp, -96, %sp
+; SOFT: ld [%fp+104], %l0
+; SOFT-NEXT: ld [%fp+96], %l1
+; SOFT-NEXT: ld [%fp+100], %l2
+; SOFT-NEXT: ld [%fp+92], %l3
+; SOFT-NEXT:  mov  %i2, %o0
+; SOFT-NEXT: call __extendsfdf2
+; SOFT-NEXT: nop
+; SOFT-NEXT:  mov  %o0, %i2
+; SOFT-NEXT:  mov  %o1, %g2
+; SOFT-NEXT:  mov  %i0, %o0
+; SOFT-NEXT:  mov  %i1, %o1
+; SOFT-NEXT:  mov  %i2, %o2
+; SOFT-NEXT:  mov  %g2, %o3
+; SOFT-NEXT:  call __adddf3
+; SOFT-NEXT:  nop
+; SOFT-NEXT:  mov  %o0, %i0
+; SOFT-NEXT:  mov  %o1, %i1
+; SOFT-NEXT:  mov  %i3, %o0
+; SOFT-NEXT:  mov  %i4, %o1
+; SOFT-NEXT:  mov  %i0, %o2
+; SOFT-NEXT:  mov  %i1, %o3
+; SOFT-NEXT:  call __adddf3
+; SOFT-NEXT:  nop
+; SOFT-NEXT:  mov  %o0, %i0
+; SOFT-NEXT:  mov  %o1, %i1
+; SOFT-NEXT:  mov  %i5, %o0
+; SOFT-NEXT:  mov  %l3, %o1
+; SOFT-NEXT:  mov  %i0, %o2
+; SOFT-NEXT:  mov  %i1, %o3
+; SOFT-NEXT:  call __adddf3
+; SOFT-NEXT:  nop
+; SOFT-NEXT:  mov  %o0, %i0
+; SOFT-NEXT:  mov  %o1, %i1
+; SOFT-NEXT:  mov  %l1, %o0
+; SOFT-NEXT:  mov  %l2, %o1
+; SOFT-NEXT:  mov  %i0, %o2
+; SOFT-NEXT:  mov  %i1, %o3
+; SOFT-NEXT:  call __adddf3
+; SOFT-NEXT:  nop
+; SOFT-NEXT:  mov  %o0, %i0
+; SOFT-NEXT:  mov  %o1, %i1
+; SOFT-NEXT:  mov  %l0, %o0
+; SOFT-NEXT:  call __extendsfdf2
+; SOFT-NEXT:  nop
+; SOFT-NEXT:  mov  %i0, %o2
+; SOFT-NEXT:  mov  %i1, %o3
+; SOFT-NEXT:  call __adddf3
+; SOFT-NEXT:  nop
+; SOFT-NEXT:  mov  %o0, %i0
+; SOFT-NEXT:  mov  %o1, %i1
+; CHECK: restore
 define double @floatarg(double %a0,   ; %i0,%i1
                         float %a1,    ; %i2
                         double %a2,   ; %i3, %i4
@@ -95,18 +147,30 @@ define double @floatarg(double %a0,   ;
 }
 
 ; CHECK-LABEL: call_floatarg:
-; CHECK: save %sp, -112, %sp
-; CHECK: mov %i2, %o1
-; CHECK-NEXT: mov %i1, %o0
-; CHECK-NEXT: st %i0, [%sp+104]
-; CHECK-NEXT: std %o0, [%sp+96]
-; CHECK-NEXT: st %o1, [%sp+92]
-; CHECK-NEXT: mov %i0, %o2
-; CHECK-NEXT: mov %o0, %o3
-; CHECK-NEXT: mov %o1, %o4
-; CHECK-NEXT: mov %o0, %o5
-; CHECK-NEXT: call floatarg
-; CHECK: std %f0, [%i4]
+; HARD: save %sp, -112, %sp
+; HARD: mov %i2, %o1
+; HARD-NEXT: mov %i1, %o0
+; HARD-NEXT: st %i0, [%sp+104]
+; HARD-NEXT: std %o0, [%sp+96]
+; HARD-NEXT: st %o1, [%sp+92]
+; HARD-NEXT: mov %i0, %o2
+; HARD-NEXT: mov %o0, %o3
+; HARD-NEXT: mov %o1, %o4
+; HARD-NEXT: mov %o0, %o5
+; HARD-NEXT: call floatarg
+; HARD: std %f0, [%i4]
+; SOFT: st %i0, [%sp+104]
+; SOFT-NEXT:  st %i2, [%sp+100]
+; SOFT-NEXT:  st %i1, [%sp+96]
+; SOFT-NEXT:  st %i2, [%sp+92]
+; SOFT-NEXT:  mov  %i1, %o0
+; SOFT-NEXT:  mov  %i2, %o1
+; SOFT-NEXT:  mov  %i0, %o2
+; SOFT-NEXT:  mov  %i1, %o3
+; SOFT-NEXT:  mov  %i2, %o4
+; SOFT-NEXT:  mov  %i1, %o5
+; SOFT-NEXT:  call floatarg
+; SOFT:  std %o0, [%i4]
 ; CHECK: restore
 define void @call_floatarg(float %f1, double %d2, float %f5, double *%p) {
   %r = call double @floatarg(double %d2, float %f1, double %d2, double %d2,

Modified: llvm/trunk/test/CodeGen/SPARC/64abi.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/SPARC/64abi.ll?rev=269892&r1=269891&r2=269892&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/SPARC/64abi.ll (original)
+++ llvm/trunk/test/CodeGen/SPARC/64abi.ll Wed May 18 04:14:13 2016
@@ -1,4 +1,5 @@
-; RUN: llc < %s -march=sparcv9 -disable-sparc-delay-filler -disable-sparc-leaf-proc | FileCheck %s
+; RUN: llc < %s -march=sparcv9 -disable-sparc-delay-filler -disable-sparc-leaf-proc | FileCheck %s --check-prefix=CHECK --check-prefix=HARD
+; RUN: llc < %s -march=sparcv9 -disable-sparc-delay-filler -disable-sparc-leaf-proc -mattr=soft-float | FileCheck %s --check-prefix=CHECK --check-prefix=SOFT
 
 ; CHECK-LABEL: intarg:
 ; The save/restore frame is not strictly necessary here, but we would need to
@@ -54,13 +55,22 @@ define void @call_intarg(i32 %i0, i8* %i
 }
 
 ; CHECK-LABEL: floatarg:
-; CHECK: save %sp, -128, %sp
-; CHECK: ld [%fp+2307], [[F:%f[0-9]+]]
-; CHECK: fstod %f1,
-; CHECK: faddd %f2,
-; CHECK: faddd %f4,
-; CHECK: faddd %f6,
-; CHECK: fadds %f31, [[F]]
+; HARD: save %sp, -128, %sp
+; HARD: ld [%fp+2307], [[F:%f[0-9]+]]
+; HARD: fstod %f1,
+; HARD: faddd %f2,
+; HARD: faddd %f4,
+; HARD: faddd %f6,
+; HARD: fadds %f31, [[F]]
+; SOFT: save %sp, -176, %sp
+; SOFT: srl %i0, 0, %o0
+; SOFT-NEXT: call __extendsfdf2
+; SOFT: mov  %o0, %i0
+; SOFT: mov  %i1, %o0
+; SOFT: mov  %i2, %o0
+; SOFT: mov  %i3, %o0
+; SOFT: ld [%fp+2299], %o0
+; SOFT: ld [%fp+2307], %o1
 define double @floatarg(float %a0,    ; %f1
                         double %a1,   ; %d2
                         double %a2,   ; %d4
@@ -92,13 +102,32 @@ define double @floatarg(float %a0,    ;
 ; CHECK-LABEL: call_floatarg:
 ; CHECK: save %sp, -272, %sp
 ; Store 8 bytes in full slot.
-; CHECK: std %f2, [%sp+2311]
+; HARD: std %f2, [%sp+2311]
 ; Store 4 bytes, right-aligned in slot.
-; CHECK: st %f1, [%sp+2307]
-; CHECK: fmovd %f2, %f4
+; HARD: st %f1, [%sp+2307]
+; HARD: fmovd %f2, %f4
+; SOFT: stx %i1, [%sp+2311]
+; SOFT: stx %i0, [%sp+2303]
+; SOFT: stx %i2, [%sp+2295]
+; SOFT: stx %i2, [%sp+2287]
+; SOFT: stx %i2, [%sp+2279]
+; SOFT: stx %i2, [%sp+2271]
+; SOFT: stx %i2, [%sp+2263]
+; SOFT: stx %i2, [%sp+2255]
+; SOFT: stx %i2, [%sp+2247]
+; SOFT: stx %i2, [%sp+2239]
+; SOFT: stx %i2, [%sp+2231]
+; SOFT: stx %i2, [%sp+2223]
+; SOFT: mov  %i2, %o0
+; SOFT: mov  %i1, %o1
+; SOFT: mov  %i1, %o2
+; SOFT: mov  %i1, %o3
+; SOFT: mov  %i2, %o4
+; SOFT: mov  %i2, %o5
 ; CHECK: call floatarg
 ; CHECK-NOT: add %sp
 ; CHECK: restore
+
 define void @call_floatarg(float %f1, double %d2, float %f5, double *%p) {
   %r = call double @floatarg(float %f5, double %d2, double %d2, double %d2,
                              float %f5, float %f5,  float %f5,  float %f5,
@@ -112,9 +141,21 @@ define void @call_floatarg(float %f1, do
 ; CHECK-LABEL: mixedarg:
 ; CHECK: ldx [%fp+2247]
 ; CHECK: ldx [%fp+2231]
-; CHECK: fstod %f3
-; CHECK: faddd %f6
-; CHECK: faddd %f16
+; SOFT: ldx [%fp+2239], %i0
+; HARD: fstod %f3
+; HARD: faddd %f6
+; HARD: faddd %f16
+; SOFT: mov  %o0, %i1
+; SOFT-NEXT: mov  %i3, %o0
+; SOFT-NEXT: mov  %i1, %o1
+; SOFT-NEXT: call __adddf3
+; SOFT: mov  %o0, %i1
+; SOFT-NEXT: mov  %i0, %o0
+; SOFT-NEXT: mov  %i1, %o1
+; SOFT-NEXT: call __adddf3
+; HARD: std %f0, [%i1]
+; SOFT: stx %o0, [%i5]
+
 define void @mixedarg(i8 %a0,      ; %i0
                       float %a1,   ; %f3
                       i16 %a2,     ; %i2
@@ -135,12 +176,15 @@ define void @mixedarg(i8 %a0,      ; %i0
 
 ; CHECK-LABEL: call_mixedarg:
 ; CHECK: stx %i2, [%sp+2247]
+; SOFT:  stx %i1, [%sp+2239]
 ; CHECK: stx %i0, [%sp+2223]
-; CHECK: fmovd %f2, %f6
-; CHECK: fmovd %f2, %f16
+; HARD: fmovd %f2, %f6
+; HARD: fmovd %f2, %f16
+; SOFT: mov  %i1, %o3
 ; CHECK: call mixedarg
 ; CHECK-NOT: add %sp
 ; CHECK: restore
+
 define void @call_mixedarg(i64 %i0, double %f2, i16* %i2) {
   call void @mixedarg(i8 undef,
                       float undef,
@@ -158,8 +202,10 @@ define void @call_mixedarg(i64 %i0, doub
 ; The inreg attribute is used to indicate 32-bit sized struct elements that
 ; share an 8-byte slot.
 ; CHECK-LABEL: inreg_fi:
-; CHECK: fstoi %f1
-; CHECK: srlx %i0, 32, [[R:%[gilo][0-7]]]
+; SOFT: srlx %i0, 32, [[R:%[gilo][0-7]]]
+; HARD: fstoi %f1
+; SOFT: call __fixsfsi
+; HARD: srlx %i0, 32, [[R:%[gilo][0-7]]]
 ; CHECK: sub [[R]],
 define i32 @inreg_fi(i32 inreg %a0,     ; high bits of %i0
                      float inreg %a1) { ; %f1
@@ -171,8 +217,11 @@ define i32 @inreg_fi(i32 inreg %a0,
 ; CHECK-LABEL: call_inreg_fi:
 ; Allocate space for 6 arguments, even when only 2 are used.
 ; CHECK: save %sp, -176, %sp
-; CHECK: sllx %i1, 32, %o0
-; CHECK: fmovs %f5, %f1
+; HARD:  sllx %i1, 32, %o0
+; HARD:  fmovs %f5, %f1
+; SOFT:  srl %i2, 0, %i0
+; SOFT:  sllx %i1, 32, %i1
+; SOFT:  or %i1, %i0, %o0
 ; CHECK: call inreg_fi
 define void @call_inreg_fi(i32* %p, i32 %i1, float %f5) {
   %x = call i32 @inreg_fi(i32 %i1, float %f5)
@@ -180,7 +229,10 @@ define void @call_inreg_fi(i32* %p, i32
 }
 
 ; CHECK-LABEL: inreg_ff:
-; CHECK: fsubs %f0, %f1, %f0
+; HARD: fsubs %f0, %f1, %f0
+; SOFT: srlx %i0, 32, %o0
+; SOFT: srl %i0, 0, %o1
+; SOFT: call __subsf3
 define float @inreg_ff(float inreg %a0,   ; %f0
                        float inreg %a1) { ; %f1
   %rv = fsub float %a0, %a1
@@ -188,8 +240,11 @@ define float @inreg_ff(float inreg %a0,
 }
 
 ; CHECK-LABEL: call_inreg_ff:
-; CHECK: fmovs %f3, %f0
-; CHECK: fmovs %f5, %f1
+; HARD: fmovs %f3, %f0
+; HARD: fmovs %f5, %f1
+; SOFT: srl %i2, 0, %i0
+; SOFT: sllx %i1, 32, %i1
+; SOFT: or %i1, %i0, %o0
 ; CHECK: call inreg_ff
 define void @call_inreg_ff(i32* %p, float %f3, float %f5) {
   %x = call float @inreg_ff(float %f3, float %f5)
@@ -197,7 +252,9 @@ define void @call_inreg_ff(i32* %p, floa
 }
 
 ; CHECK-LABEL: inreg_if:
-; CHECK: fstoi %f0
+; HARD: fstoi %f0
+; SOFT: srlx %i0, 32, %o0
+; SOFT: call __fixsfsi
 ; CHECK: sub %i0
 define i32 @inreg_if(float inreg %a0, ; %f0
                      i32 inreg %a1) { ; low bits of %i0
@@ -207,8 +264,11 @@ define i32 @inreg_if(float inreg %a0, ;
 }
 
 ; CHECK-LABEL: call_inreg_if:
-; CHECK: fmovs %f3, %f0
-; CHECK: mov %i2, %o0
+; HARD: fmovs %f3, %f0
+; HARD: mov %i2, %o0
+; SOFT: srl %i2, 0, %i0
+; SOFT: sllx %i1, 32, %i1
+; SOFT: or %i1, %i0, %o0
 ; CHECK: call inreg_if
 define void @call_inreg_if(i32* %p, float %f3, i32 %i2) {
   %x = call i32 @inreg_if(float %f3, i32 %i2)
@@ -265,7 +325,8 @@ define void @call_ret_i64_pair(i64* %i0)
 ; This is not a C struct, the i32 member uses 8 bytes, but the float only 4.
 ; CHECK-LABEL: ret_i32_float_pair:
 ; CHECK: ld [%i2], %i0
-; CHECK: ld [%i3], %f2
+; HARD: ld [%i3], %f2
+; SOFT: ld [%i3], %i1
 define { i32, float } @ret_i32_float_pair(i32 %a0, i32 %a1,
                                           i32* %p, float* %q) {
   %r1 = load i32, i32* %p
@@ -279,7 +340,8 @@ define { i32, float } @ret_i32_float_pai
 ; CHECK-LABEL: call_ret_i32_float_pair:
 ; CHECK: call ret_i32_float_pair
 ; CHECK: st %o0, [%i0]
-; CHECK: st %f2, [%i1]
+; HARD: st %f2, [%i1]
+; SOFT: st %o1, [%i1]
 define void @call_ret_i32_float_pair(i32* %i0, float* %i1) {
   %rv = call { i32, float } @ret_i32_float_pair(i32 undef, i32 undef,
                                                 i32* undef, float* undef)
@@ -293,7 +355,8 @@ define void @call_ret_i32_float_pair(i32
 ; This is a C struct, each member uses 4 bytes.
 ; CHECK-LABEL: ret_i32_float_packed:
 ; CHECK: ld [%i2], [[R:%[gilo][0-7]]]
-; CHECK: ld [%i3], %f1
+; HARD: ld [%i3], %f1
+; SOFT: ld [%i3], %i1
 ; CHECK: sllx [[R]], 32, %i0
 define inreg { i32, float } @ret_i32_float_packed(i32 %a0, i32 %a1,
                                                   i32* %p, float* %q) {
@@ -309,7 +372,8 @@ define inreg { i32, float } @ret_i32_flo
 ; CHECK: call ret_i32_float_packed
 ; CHECK: srlx %o0, 32, [[R:%[gilo][0-7]]]
 ; CHECK: st [[R]], [%i0]
-; CHECK: st %f1, [%i1]
+; HARD: st %f1, [%i1]
+; SOFT: st %o0, [%i1]
 define void @call_ret_i32_float_packed(i32* %i0, float* %i1) {
   %rv = call { i32, float } @ret_i32_float_packed(i32 undef, i32 undef,
                                                   i32* undef, float* undef)
@@ -413,13 +477,21 @@ entry:
 declare i32 @use_buf(i32, i8*)
 
 ; CHECK-LABEL: test_fp128_args:
-; CHECK-DAG:   std %f0, [%fp+{{.+}}]
-; CHECK-DAG:   std %f2, [%fp+{{.+}}]
-; CHECK-DAG:   std %f6, [%fp+{{.+}}]
-; CHECK-DAG:   std %f4, [%fp+{{.+}}]
-; CHECK:       add %fp, [[Offset:[0-9]+]], %o0
-; CHECK:       call _Qp_add
-; CHECK:       ldd [%fp+[[Offset]]], %f0
+; HARD-DAG:   std %f0, [%fp+{{.+}}]
+; HARD-DAG:   std %f2, [%fp+{{.+}}]
+; HARD-DAG:   std %f6, [%fp+{{.+}}]
+; HARD-DAG:   std %f4, [%fp+{{.+}}]
+; HARD:       add %fp, [[Offset:[0-9]+]], %o0
+; HARD:       call _Qp_add
+; HARD:       ldd [%fp+[[Offset]]], %f0
+; SOFT-DAG:       mov  %i0, %o0
+; SOFT-DAG:       mov  %i1, %o1
+; SOFT-DAG:       mov  %i2, %o2
+; SOFT-DAG:       mov  %i3, %o3
+; SOFT:           call __addtf3
+; SOFT:           mov  %o0, %i0
+; SOFT:           mov  %o1, %i1
+
 define fp128 @test_fp128_args(fp128 %a, fp128 %b) {
 entry:
   %0 = fadd fp128 %a, %b
@@ -429,11 +501,14 @@ entry:
 declare i64 @receive_fp128(i64 %a, ...)
 
 ; CHECK-LABEL: test_fp128_variable_args:
-; CHECK-DAG:   std %f4, [%sp+[[Offset0:[0-9]+]]]
-; CHECK-DAG:   std %f6, [%sp+[[Offset1:[0-9]+]]]
-; CHECK-DAG:   ldx [%sp+[[Offset0]]], %o2
-; CHECK-DAG:   ldx [%sp+[[Offset1]]], %o3
-; CHECK:       call receive_fp128
+; HARD-DAG:   std %f4, [%sp+[[Offset0:[0-9]+]]]
+; HARD-DAG:   std %f6, [%sp+[[Offset1:[0-9]+]]]
+; HARD-DAG:   ldx [%sp+[[Offset0]]], %o2
+; HARD-DAG:   ldx [%sp+[[Offset1]]], %o3
+; SOFT-DAG:   mov  %i0, %o0
+; SOFT-DAG:   mov  %i1, %o1
+; SOFT-DAG:   mov  %i2, %o2
+; CHECK:      call receive_fp128
 define i64 @test_fp128_variable_args(i64 %a, fp128 %b) {
 entry:
   %0 = call i64 (i64, ...) @receive_fp128(i64 %a, fp128 %b)
@@ -441,14 +516,22 @@ entry:
 }
 
 ; CHECK-LABEL: test_call_libfunc:
-; CHECK:       st %f1, [%fp+[[Offset0:[0-9]+]]]
-; CHECK:       fmovs %f3, %f1
-; CHECK:       call cosf
-; CHECK:       st %f0, [%fp+[[Offset1:[0-9]+]]]
-; CHECK:       ld [%fp+[[Offset0]]], %f1
-; CHECK:       call sinf
-; CHECK:       ld [%fp+[[Offset1]]], %f1
-; CHECK:       fmuls %f1, %f0, %f0
+; HARD:   st %f1, [%fp+[[Offset0:[0-9]+]]]
+; HARD:   fmovs %f3, %f1
+; SOFT:   srl %i1, 0, %o0
+; CHECK:  call cosf
+; HARD:   st %f0, [%fp+[[Offset1:[0-9]+]]]
+; HARD:   ld [%fp+[[Offset0]]], %f1
+; SOFT:   mov  %o0, %i1
+; SOFT:   srl %i0, 0, %o0
+; CHECK:  call sinf
+; HARD:   ld [%fp+[[Offset1]]], %f1
+; HARD:   fmuls %f1, %f0, %f0
+; SOFT:   mov  %o0, %i0
+; SOFT:   mov  %i1, %o0
+; SOFT:   mov  %i0, %o1
+; SOFT:   call __mulsf3
+; SOFT:   sllx %o0, 32, %i0
 
 define inreg float @test_call_libfunc(float %arg0, float %arg1) {
 entry:
@@ -460,5 +543,3 @@ entry:
 
 declare inreg float @cosf(float %arg) readnone nounwind
 declare inreg float @sinf(float %arg) readnone nounwind
-
-

Added: llvm/trunk/test/CodeGen/SPARC/soft-float.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/SPARC/soft-float.ll?rev=269892&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/SPARC/soft-float.ll (added)
+++ llvm/trunk/test/CodeGen/SPARC/soft-float.ll Wed May 18 04:14:13 2016
@@ -0,0 +1,235 @@
+; RUN: llc -march=sparc -mattr=soft-float -O0 < %s | FileCheck %s
+
+; Arithmetic functions
+
+define float @test_addsf3(float %a, float %b) #0 {
+  ; CHECK-LABEL:  test_addsf3:
+  ; CHECK:        call __addsf3
+  %add = fadd float %a, %b
+  ret float %add
+}
+
+define double @test_adddf3(double %a, double %b) #0 {
+  ; CHECK-LABEL:  test_adddf3:
+  ; CHECK:        call __adddf3
+  %add = fadd double %a, %b
+  ret double %add
+}
+
+define fp128 @test_addtf3(fp128 %a, fp128 %b) #0 {
+  ; CHECK-LABEL:  test_addtf3:
+  ; CHECK:        call __addtf3
+  %add = fadd fp128 %a, %b
+  ret fp128 %add
+}
+
+define float @test_mulsf3(float %a, float %b) #0 {
+  ; CHECK-LABEL:  test_mulsf3:
+  ; CHECK:        call __mulsf3
+  %mul = fmul float %a, %b
+  ret float %mul
+}
+
+define double @test_muldf3(double %a, double %b) #0 {
+  ; CHECK-LABEL:  test_muldf3:
+  ; CHECK:        call __muldf3
+  %mul = fmul double %a, %b
+  ret double %mul
+}
+
+define fp128 @test_multf3(fp128 %a, fp128 %b) #0 {
+  ; CHECK-LABEL:  test_multf3:
+  ; CHECK:        call __multf3
+  %mul = fmul fp128 %a, %b
+  ret fp128 %mul
+}
+
+define float @test_subsf3(float %a, float %b) #0 {
+  ; CHCEK-LABEL:  test_subsf3:
+  ; CHECK:        call __subsf3
+  %sub = fsub float %a, %b
+  ret float %sub
+}
+
+define double @test_subdf3(double %a, double %b) #0 {
+  ; CHCEK-LABEL:  test_subdf3:
+  ; CHECK:        call __subdf3
+  %sub = fsub double %a, %b
+  ret double %sub
+}
+
+define fp128 @test_subtf3(fp128 %a, fp128 %b) #0 {
+  ; CHCEK-LABEL:  test_subtf3:
+  ; CHECK:        call __subtf3
+  %sub = fsub fp128 %a, %b
+  ret fp128 %sub
+}
+
+define float @test_divsf3(float %a, float %b) #0 {
+  ; CHECK-LABEL:  test_divsf3:
+  ; CHECK:        call __divsf3
+  %div = fdiv float %a, %b
+  ret float %div
+}
+
+define double @test_divdf3(double %a, double %b) #0 {
+  ; CHECK-LABEL:  test_divdf3:
+  ; CHECK:        call __divdf3
+  %div = fdiv double %a, %b
+  ret double %div
+}
+
+define fp128 @test_divtf3(fp128 %a, fp128 %b) #0 {
+  ; CHECK-LABEL:  test_divtf3:
+  ; CHECK:        call __divtf3
+  %div = fdiv fp128 %a, %b
+  ret fp128 %div
+}
+
+; Comparison functions
+define i1 @test_unordsf2(float %a, float %b) #0 {
+  ; CHECK-LABEL:  test_unordsf2:
+  ; CHECK:        call __unordsf2
+  %cmp = fcmp uno float %a, %b
+  ret i1 %cmp
+}
+
+define i1 @test_unorddf2(double %a, double %b) #0 {
+  ; CHECK-LABEL:  test_unorddf2:
+  ; CHECK:        call __unorddf2
+  %cmp = fcmp uno double %a, %b
+  ret i1 %cmp
+}
+
+define i1 @test_unordtf2(fp128 %a, fp128 %b) #0 {
+  ; CHECK-LABEL:  test_unordtf2:
+  ; CHECK:        call __unordtf2
+  %cmp = fcmp uno fp128 %a, %b
+  ret i1 %cmp
+}
+
+define i1 @test_eqsf2(float %a, float %b) #0 {
+  ; CHECK-LABEL:  test_eqsf2:
+  ; CHECK:        call __eqsf2
+  %cmp = fcmp oeq float %a, %b
+  ret i1 %cmp
+}
+
+define i1 @test_eqdf2(double %a, double %b) #0 {
+  ; CHECK-LABEL:  test_eqdf2:
+  ; CHECK:        call __eqdf2
+  %cmp = fcmp oeq double %a, %b
+  ret i1 %cmp
+}
+
+define i1 @test_eqtf2(fp128 %a, fp128 %b) #0 {
+  ; CHECK-LABEL:  test_eqtf2:
+  ; CHECK:        call __eqtf2
+  %cmp = fcmp oeq fp128 %a, %b
+  ret i1 %cmp
+}
+
+define i1 @test_nesf2(float %a, float %b) #0 {
+  ; CHECK-LABEL:  test_nesf2:
+  ; CHECK:        call __nesf2
+  %cmp = fcmp une float %a, %b
+  ret i1 %cmp
+}
+
+define i1 @test_nedf2(double %a, double %b) #0 {
+  ; CHECK-LABEL:  test_nedf2:
+  ; CHECK:        call __nedf2
+  %cmp = fcmp une double %a, %b
+  ret i1 %cmp
+}
+
+define i1 @test_netf2(fp128 %a, fp128 %b) #0 {
+  ; CHECK-LABEL:  test_netf2:
+  ; CHECK:        call __netf2
+  %cmp = fcmp une fp128 %a, %b
+  ret i1 %cmp
+}
+
+define i1 @test_gesf2(float %a, float %b) #0 {
+  ; CHECK-LABLE:  test_gesf2:
+  ; CHECK:        call __gesf2
+  %cmp = fcmp oge float %a, %b
+  ret i1 %cmp
+}
+
+define i1 @test_gedf2(double %a, double %b) #0 {
+  ; CHECK-LABLE:  test_gedf2:
+  ; CHECK:        call __gedf2
+  %cmp = fcmp oge double %a, %b
+  ret i1 %cmp
+}
+
+define i1 @test_getf2(fp128 %a, fp128 %b) #0 {
+  ; CHECK-LABLE:  test_getf2:
+  ; CHECK:        call __getf2
+  %cmp = fcmp oge fp128 %a, %b
+  ret i1 %cmp
+}
+
+define i1 @test_ltsf2(float %a, float %b) #0 {
+  ; CHECK-LABEL:  test_ltsf2:
+  ; CHECK:        call __ltsf2
+  %cmp = fcmp olt float %a, %b
+  ret i1 %cmp
+}
+
+define i1 @test_ltdf2(double %a, double %b) #0 {
+  ; CHECK-LABEL:  test_ltdf2:
+  ; CHECK:        call __ltdf2
+  %cmp = fcmp olt double %a, %b
+  ret i1 %cmp
+}
+
+define i1 @test_lttf2(fp128 %a, fp128 %b) #0 {
+  ; CHECK-LABEL:  test_lttf2:
+  ; CHECK:        call __lttf2
+  %cmp = fcmp olt fp128 %a, %b
+  ret i1 %cmp
+}
+
+define i1 @test_lesf2(float %a, float %b) #0 {
+  ; CHECK-LABEL:  test_lesf2:
+  ; CHECK:        call __lesf2
+  %cmp = fcmp ole float %a, %b
+  ret i1 %cmp
+}
+
+define i1 @test_ledf2(double %a, double %b) #0 {
+  ; CHECK-LABEL:  test_ledf2:
+  ; CHECK:        call __ledf2
+  %cmp = fcmp ole double %a, %b
+  ret i1 %cmp
+}
+
+define i1 @test_letf2(fp128 %a, fp128 %b) #0 {
+  ; CHECK-LABEL:  test_letf2:
+  ; CHECK:        call __letf2
+  %cmp = fcmp ole fp128 %a, %b
+  ret i1 %cmp
+}
+
+define i1 @test_gtsf2(float %a, float %b) #0 {
+  ; CHECK-LABEL:  test_gtsf2:
+  ; CHECK:        call __gtsf2
+  %cmp = fcmp ogt float %a, %b
+  ret i1 %cmp
+}
+
+define i1 @test_gtdf2(double %a, double %b) #0 {
+  ; CHECK-LABEL:  test_gtdf2:
+  ; CHECK:        call __gtdf2
+  %cmp = fcmp ogt double %a, %b
+  ret i1 %cmp
+}
+
+define i1 @test_gttf2(fp128 %a, fp128 %b) #0 {
+  ; CHECK-LABEL:  test_gttf2:
+  ; CHECK:        call __gttf2
+  %cmp = fcmp ogt fp128 %a, %b
+  ret i1 %cmp
+}




More information about the llvm-commits mailing list