[llvm] r267489 - [Sparc] Fix double-float fabs and fneg on little endian CPUs.

James Y Knight via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 25 15:54:09 PDT 2016


Author: jyknight
Date: Mon Apr 25 17:54:09 2016
New Revision: 267489

URL: http://llvm.org/viewvc/llvm-project?rev=267489&view=rev
Log:
[Sparc] Fix double-float fabs and fneg on little endian CPUs.

The SparcV8 fneg and fabs instructions interestingly come only in a
single-float variant. Since the sign bit is always the topmost bit no
matter what size float it is, you simply operate on the high
subregister, as if it were a single float.

However, the layout of double-floats in the float registers is reversed
on little-endian CPUs, so that the high bits are in the second
subregister, rather than the first.

Thus, this expansion must check the endianness to use the correct
subregister.

Modified:
    llvm/trunk/lib/Target/Sparc/SparcISelLowering.cpp
    llvm/trunk/test/CodeGen/SPARC/float.ll
    llvm/trunk/test/CodeGen/SPARC/fp128.ll

Modified: llvm/trunk/lib/Target/Sparc/SparcISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Sparc/SparcISelLowering.cpp?rev=267489&r1=267488&r2=267489&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Sparc/SparcISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/Sparc/SparcISelLowering.cpp Mon Apr 25 17:54:09 2016
@@ -2649,24 +2649,29 @@ static SDValue LowerRETURNADDR(SDValue O
   return RetAddr;
 }
 
-static SDValue LowerF64Op(SDValue Op, SelectionDAG &DAG, unsigned opcode)
+static SDValue LowerF64Op(SDValue SrcReg64, SDLoc dl, SelectionDAG &DAG, unsigned opcode)
 {
-  SDLoc dl(Op);
-
-  assert(Op.getValueType() == MVT::f64 && "LowerF64Op called on non-double!");
+  assert(SrcReg64.getValueType() == MVT::f64 && "LowerF64Op called on non-double!");
   assert(opcode == ISD::FNEG || opcode == ISD::FABS);
 
   // Lower fneg/fabs on f64 to fneg/fabs on f32.
   // fneg f64 => fneg f32:sub_even, fmov f32:sub_odd.
   // fabs f64 => fabs f32:sub_even, fmov f32:sub_odd.
 
-  SDValue SrcReg64 = Op.getOperand(0);
+  // Note: in little-endian, the floating-point value is stored in the
+  // registers are in the opposite order, so the subreg with the sign
+  // bit is the highest-numbered (odd), rather than the
+  // lowest-numbered (even).
+
   SDValue Hi32 = DAG.getTargetExtractSubreg(SP::sub_even, dl, MVT::f32,
                                             SrcReg64);
   SDValue Lo32 = DAG.getTargetExtractSubreg(SP::sub_odd, dl, MVT::f32,
                                             SrcReg64);
 
-  Hi32 = DAG.getNode(opcode, dl, MVT::f32, Hi32);
+  if (DAG.getDataLayout().isLittleEndian())
+    Lo32 = DAG.getNode(opcode, dl, MVT::f32, Lo32);
+  else
+    Hi32 = DAG.getNode(opcode, dl, MVT::f32, Hi32);
 
   SDValue DstReg64 = SDValue(DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF,
                                                 dl, MVT::f64), 0);
@@ -2810,24 +2815,35 @@ static SDValue LowerFNEGorFABS(SDValue O
   assert((Op.getOpcode() == ISD::FNEG || Op.getOpcode() == ISD::FABS)
          && "invalid opcode");
 
+  SDLoc dl(Op);
+
   if (Op.getValueType() == MVT::f64)
-    return LowerF64Op(Op, DAG, Op.getOpcode());
+    return LowerF64Op(Op.getOperand(0), dl, DAG, Op.getOpcode());
   if (Op.getValueType() != MVT::f128)
     return Op;
 
   // Lower fabs/fneg on f128 to fabs/fneg on f64
   // fabs/fneg f128 => fabs/fneg f64:sub_even64, fmov f64:sub_odd64
+  // (As with LowerF64Op, on little-endian, we need to negate the odd
+  // subreg)
 
-  SDLoc dl(Op);
   SDValue SrcReg128 = Op.getOperand(0);
   SDValue Hi64 = DAG.getTargetExtractSubreg(SP::sub_even64, dl, MVT::f64,
                                             SrcReg128);
   SDValue Lo64 = DAG.getTargetExtractSubreg(SP::sub_odd64, dl, MVT::f64,
                                             SrcReg128);
-  if (isV9)
-    Hi64 = DAG.getNode(Op.getOpcode(), dl, MVT::f64, Hi64);
-  else
-    Hi64 = LowerF64Op(Hi64, DAG, Op.getOpcode());
+
+  if (DAG.getDataLayout().isLittleEndian()) {
+    if (isV9)
+      Lo64 = DAG.getNode(Op.getOpcode(), dl, MVT::f64, Lo64);
+    else
+      Lo64 = LowerF64Op(Lo64, dl, DAG, Op.getOpcode());
+  } else {
+    if (isV9)
+      Hi64 = DAG.getNode(Op.getOpcode(), dl, MVT::f64, Hi64);
+    else
+      Hi64 = LowerF64Op(Hi64, dl, DAG, Op.getOpcode());
+  }
 
   SDValue DstReg128 = SDValue(DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF,
                                                  dl, MVT::f128), 0);

Modified: llvm/trunk/test/CodeGen/SPARC/float.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/SPARC/float.ll?rev=267489&r1=267488&r2=267489&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/SPARC/float.ll (original)
+++ llvm/trunk/test/CodeGen/SPARC/float.ll Mon Apr 25 17:54:09 2016
@@ -1,11 +1,13 @@
-; RUN: llc -march=sparc < %s | FileCheck %s -check-prefix=V8
+; RUN: llc -march=sparc < %s | FileCheck %s -check-prefix=V8 -check-prefix=V8-BE
+; RUN: llc -march=sparcel < %s | FileCheck %s -check-prefix=V8 -check-prefix=V8-EL
 ; RUN: llc -march=sparc -O0 < %s | FileCheck %s -check-prefix=V8-UNOPT
 ; RUN: llc -march=sparc -mattr=v9 < %s | FileCheck %s -check-prefix=V9
 ; RUN: llc -mtriple=sparc64-unknown-linux < %s | FileCheck %s -check-prefix=SPARC64
 
 ; V8-LABEL:     test_neg:
 ; V8:     call get_double
-; V8:     fnegs %f0, %f0
+; V8-BE:     fnegs %f0, %f0
+; V8-EL:     fnegs %f1, %f1
 
 ; V8-UNOPT-LABEL:     test_neg:
 ; V8-UNOPT:     fnegs
@@ -27,7 +29,8 @@ entry:
 }
 
 ; V8-LABEL:     test_abs:
-; V8:     fabss %f0, %f0
+; V8-BE:     fabss %f0, %f0
+; V8-EL:     fabss %f1, %f1
 
 ; V8-UNOPT-LABEL:     test_abs:
 ; V8-UNOPT:     fabss

Modified: llvm/trunk/test/CodeGen/SPARC/fp128.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/SPARC/fp128.ll?rev=267489&r1=267488&r2=267489&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/SPARC/fp128.ll (original)
+++ llvm/trunk/test/CodeGen/SPARC/fp128.ll Mon Apr 25 17:54:09 2016
@@ -1,30 +1,24 @@
-; RUN: llc < %s -march=sparc -mattr=hard-quad-float | FileCheck %s --check-prefix=HARD
-; RUN: llc < %s -march=sparc -mattr=-hard-quad-float | FileCheck %s --check-prefix=SOFT
+; RUN: llc < %s -march=sparc -mattr=hard-quad-float | FileCheck %s --check-prefix=CHECK --check-prefix=HARD --check-prefix=BE
+; RUN: llc < %s -march=sparcel -mattr=hard-quad-float | FileCheck %s --check-prefix=CHECK --check-prefix=HARD --check-prefix=EL
+; RUN: llc < %s -march=sparc -mattr=-hard-quad-float | FileCheck %s --check-prefix=CHECK --check-prefix=SOFT --check-prefix=BE
+; RUN: llc < %s -march=sparcel -mattr=-hard-quad-float | FileCheck %s --check-prefix=CHECK --check-prefix=SOFT --check-prefix=EL
 
 
-; HARD-LABEL: f128_ops
-; HARD:       ldd
-; HARD:       ldd
-; HARD:       ldd
-; HARD:       ldd
+; CHECK-LABEL: f128_ops:
+; CHECK:      ldd
+; CHECK:      ldd
+; CHECK:      ldd
+; CHECK:      ldd
 ; HARD:       faddq [[R0:.+]],  [[R1:.+]],  [[R2:.+]]
 ; HARD:       fsubq [[R2]], [[R3:.+]], [[R4:.+]]
 ; HARD:       fmulq [[R4]], [[R5:.+]], [[R6:.+]]
 ; HARD:       fdivq [[R6]], [[R2]]
-; HARD:       std
-; HARD:       std
-
-; SOFT-LABEL: f128_ops
-; SOFT:       ldd
-; SOFT:       ldd
-; SOFT:       ldd
-; SOFT:       ldd
 ; SOFT:       call _Q_add
 ; SOFT:       call _Q_sub
 ; SOFT:       call _Q_mul
 ; SOFT:       call _Q_div
-; SOFT:       std
-; SOFT:       std
+; CHECK:      std
+; CHECK:      std
 
 define void @f128_ops(fp128* noalias sret %scalar.result, fp128* byval %a, fp128* byval %b, fp128* byval %c, fp128* byval %d) {
 entry:
@@ -40,19 +34,12 @@ entry:
   ret void
 }
 
-; HARD-LABEL: f128_spill
-; HARD:       std %f{{.+}}, [%[[S0:.+]]]
-; HARD:       std %f{{.+}}, [%[[S1:.+]]]
-; HARD-DAG:   ldd [%[[S0]]], %f{{.+}}
-; HARD-DAG:   ldd [%[[S1]]], %f{{.+}}
-; HARD:       jmp {{%[oi]7}}+12
-
-; SOFT-LABEL: f128_spill
-; SOFT:       std %f{{.+}}, [%[[S0:.+]]]
-; SOFT:       std %f{{.+}}, [%[[S1:.+]]]
-; SOFT-DAG:   ldd [%[[S0]]], %f{{.+}}
-; SOFT-DAG:   ldd [%[[S1]]], %f{{.+}}
-; SOFT:       jmp {{%[oi]7}}+12
+; CHECK-LABEL: f128_spill:
+; CHECK:       std %f{{.+}}, [%[[S0:.+]]]
+; CHECK:       std %f{{.+}}, [%[[S1:.+]]]
+; CHECK-DAG:   ldd [%[[S0]]], %f{{.+}}
+; CHECK-DAG:   ldd [%[[S1]]], %f{{.+}}
+; CHECK:       jmp {{%[oi]7}}+12
 
 define void @f128_spill(fp128* noalias sret %scalar.result, fp128* byval %a) {
 entry:
@@ -62,11 +49,9 @@ entry:
   ret void
 }
 
-; HARD-LABEL: f128_compare
+; CHECK-LABEL: f128_compare:
 ; HARD:       fcmpq
 ; HARD-NEXT:  nop
-
-; SOFT-LABEL: f128_compare
 ; SOFT:       _Q_cmp
 
 define i32 @f128_compare(fp128* byval %f0, fp128* byval %f1, i32 %a, i32 %b) {
@@ -78,11 +63,9 @@ entry:
    ret i32 %ret
 }
 
-; HARD-LABEL: f128_compare2
-; HARD:       fcmpq
-; HARD:       fb{{ule|g}}
-
-; SOFT-LABEL: f128_compare2
+; CHECK-LABEL: f128_compare2:
+; HARD:        fcmpq
+; HARD:        fb{{ule|g}}
 ; SOFT:       _Q_cmp
 ; SOFT:       cmp
 
@@ -99,11 +82,11 @@ entry:
 }
 
 
-; HARD-LABEL: f128_abs
-; HARD:       fabss
-
-; SOFT-LABEL: f128_abs
-; SOFT:       fabss
+; CHECK-LABEL: f128_abs:
+; CHECK:       ldd [%o0], %f0
+; CHECK:       ldd [%o0+8], %f2
+; BE:          fabss %f0, %f0
+; EL:          fabss %f3, %f3
 
 define void @f128_abs(fp128* noalias sret %scalar.result, fp128* byval %a) {
 entry:
@@ -115,10 +98,8 @@ entry:
 
 declare fp128 @llvm.fabs.f128(fp128) nounwind readonly
 
-; HARD-LABEL: int_to_f128
+; CHECK-LABEL: int_to_f128:
 ; HARD:       fitoq
-
-; SOFT-LABEL: int_to_f128
 ; SOFT:       _Q_itoq
 
 define void @int_to_f128(fp128* noalias sret %scalar.result, i32 %i) {
@@ -128,17 +109,12 @@ entry:
   ret void
 }
 
-; HARD-LABEL: fp128_unaligned
-; HARD:       ldub
-; HARD:       faddq
-; HARD:       stb
-; HARD:       ret
-
-; SOFT-LABEL: fp128_unaligned
-; SOFT:       ldub
+; CHECK-LABEL: fp128_unaligned:
+; CHECK:       ldub
+; HARD:        faddq
 ; SOFT:       call _Q_add
-; SOFT:       stb
-; SOFT:       ret
+; CHECK:       stb
+; CHECK:       ret
 
 define void @fp128_unaligned(fp128* %a, fp128* %b, fp128* %c) {
 entry:
@@ -149,10 +125,8 @@ entry:
   ret void
 }
 
-; HARD-LABEL: uint_to_f128
+; CHECK-LABEL: uint_to_f128:
 ; HARD:       fdtoq
-
-; SOFT-LABEL: uint_to_f128
 ; SOFT:       _Q_utoq
 
 define void @uint_to_f128(fp128* noalias sret %scalar.result, i32 %i) {
@@ -162,11 +136,9 @@ entry:
   ret void
 }
 
-; HARD-LABEL: f128_to_i32
+; CHECK-LABEL: f128_to_i32:
 ; HARD:       fqtoi
 ; HARD:       fqtoi
-
-; SOFT-LABEL: f128_to_i32
 ; SOFT:       call _Q_qtou
 ; SOFT:       call _Q_qtoi
 
@@ -181,13 +153,11 @@ entry:
   ret i32 %4
 }
 
-; HARD-LABEL:    test_itoq_qtoi
+; CHECK-LABEL:   test_itoq_qtoi
 ; HARD-DAG:      call _Q_lltoq
 ; HARD-DAG:      call _Q_qtoll
 ; HARD-DAG:      fitoq
 ; HARD-DAG:      fqtoi
-
-; SOFT-LABEL:    test_itoq_qtoi
 ; SOFT-DAG:      call _Q_lltoq
 ; SOFT-DAG:      call _Q_qtoll
 ; SOFT-DAG:      call _Q_itoq
@@ -209,15 +179,11 @@ entry:
   ret void
 }
 
-; HARD-LABEL:    test_utoq_qtou
-; HARD-DAG:      call _Q_ulltoq
-; HARD-DAG:      call _Q_qtoull
+; CHECK-LABEL:   test_utoq_qtou:
+; CHECK-DAG:     call _Q_ulltoq
+; CHECK-DAG:     call _Q_qtoull
 ; HARD-DAG:      fdtoq
 ; HARD-DAG:      fqtoi
-
-; SOFT-LABEL:    test_utoq_qtou
-; SOFT-DAG:      call _Q_ulltoq
-; SOFT-DAG:      call _Q_qtoull
 ; SOFT-DAG:      call _Q_utoq
 ; SOFT-DAG:      call _Q_qtou
 
@@ -237,8 +203,11 @@ entry:
   ret void
 }
 
-; SOFT-LABEL:     f128_neg
-; SOFT:           fnegs
+; CHECK-LABEL: f128_neg:
+; CHECK:       ldd [%o0], %f0
+; CHECK:       ldd [%o0+8], %f2
+; BE:          fnegs %f0, %f0
+; EL:          fnegs %f3, %f3
 
 define void @f128_neg(fp128* noalias sret %scalar.result, fp128* byval %a) {
 entry:




More information about the llvm-commits mailing list