SelectionDAG: fold (fp_to_u/sint (s/uint_to_fp)) here too
authorMehdi Amini <mehdi.amini@apple.com>
Mon, 16 Feb 2015 21:47:58 +0000 (21:47 +0000)
committerMehdi Amini <mehdi.amini@apple.com>
Mon, 16 Feb 2015 21:47:58 +0000 (21:47 +0000)
Update SPARC tests to match.

From: Fiona Glaser <fglaser@apple.com>

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@229438 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/SelectionDAG/DAGCombiner.cpp
test/CodeGen/SPARC/float.ll
test/CodeGen/SPARC/fp128.ll
test/CodeGen/X86/float-conv-elim.ll [new file with mode: 0644]

index 8571091..c4a1a1f 100644 (file)
@@ -7845,6 +7845,50 @@ SDValue DAGCombiner::visitUINT_TO_FP(SDNode *N) {
   return SDValue();
 }
 
+// Fold (fp_to_{s/u}int ({s/u}int_to_fpx)) -> zext x, sext x, trunc x, or x
+static SDValue FoldIntToFPToInt(SDNode *N, SelectionDAG &DAG) {
+  SDValue N0 = N->getOperand(0);
+  EVT VT = N->getValueType(0);
+
+  if (N0.getOpcode() != ISD::UINT_TO_FP && N0.getOpcode() != ISD::SINT_TO_FP)
+    return SDValue();
+
+  SDValue Src = N0.getOperand(0);
+  EVT SrcVT = Src.getValueType();
+  bool IsInputSigned = N0.getOpcode() == ISD::SINT_TO_FP;
+  bool IsOutputSigned = N->getOpcode() == ISD::FP_TO_SINT;
+
+  // We can safely assume the conversion won't overflow the output range,
+  // because (for example) (uint8_t)18293.f is undefined behavior.
+
+  // Since we can assume the conversion won't overflow, our decision as to
+  // whether the input will fit in the float should depend on the minimum
+  // of the input range and output range.
+
+  // This means this is also safe for a signed input and unsigned output, since
+  // a negative input would lead to undefined behavior.
+  unsigned InputSize = (int)SrcVT.getScalarSizeInBits() - IsInputSigned;
+  unsigned OutputSize = (int)VT.getScalarSizeInBits() - IsOutputSigned;
+  unsigned ActualSize = std::min(InputSize, OutputSize);
+  const fltSemantics &sem = DAG.EVTToAPFloatSemantics(N0.getValueType());
+
+  // We can only fold away the float conversion if the input range can be
+  // represented exactly in the float range.
+  if (APFloat::semanticsPrecision(sem) >= ActualSize) {
+    if (VT.getScalarSizeInBits() > SrcVT.getScalarSizeInBits()) {
+      unsigned ExtOp = IsInputSigned && IsOutputSigned ? ISD::SIGN_EXTEND
+                                                       : ISD::ZERO_EXTEND;
+      return DAG.getNode(ExtOp, SDLoc(N), VT, Src);
+    }
+    if (VT.getScalarSizeInBits() < SrcVT.getScalarSizeInBits())
+      return DAG.getNode(ISD::TRUNCATE, SDLoc(N), VT, Src);
+    if (SrcVT == VT)
+      return Src;
+    return DAG.getNode(ISD::BITCAST, SDLoc(N), VT, Src);
+  }
+  return SDValue();
+}
+
 SDValue DAGCombiner::visitFP_TO_SINT(SDNode *N) {
   SDValue N0 = N->getOperand(0);
   ConstantFPSDNode *N0CFP = dyn_cast<ConstantFPSDNode>(N0);
@@ -7854,7 +7898,7 @@ SDValue DAGCombiner::visitFP_TO_SINT(SDNode *N) {
   if (N0CFP)
     return DAG.getNode(ISD::FP_TO_SINT, SDLoc(N), VT, N0);
 
-  return SDValue();
+  return FoldIntToFPToInt(N, DAG);
 }
 
 SDValue DAGCombiner::visitFP_TO_UINT(SDNode *N) {
@@ -7866,7 +7910,7 @@ SDValue DAGCombiner::visitFP_TO_UINT(SDNode *N) {
   if (N0CFP)
     return DAG.getNode(ISD::FP_TO_UINT, SDLoc(N), VT, N0);
 
-  return SDValue();
+  return FoldIntToFPToInt(N, DAG);
 }
 
 SDValue DAGCombiner::visitFP_ROUND(SDNode *N) {
index 6636704..d7a79cb 100644 (file)
@@ -154,11 +154,11 @@ entry:
 ; SPARC64:          fitod
 ; SPARC64:          fdtoi
 
-define void @test_itod_dtoi(i32 %a, i32* %ptr0, double* %ptr1) {
+define void @test_itod_dtoi(i32 %a, double %b, i32* %ptr0, double* %ptr1) {
 entry:
   %0 = sitofp i32 %a to double
   store double %0, double* %ptr1, align 8
-  %1 = fptosi double %0 to i32
+  %1 = fptosi double %b to i32
   store i32 %1, i32* %ptr0, align 8
   ret void
 }
index abd89bf..a06112a 100644 (file)
@@ -182,26 +182,28 @@ entry:
 }
 
 ; HARD-LABEL:    test_itoq_qtoi
-; HARD:          call _Q_lltoq
-; HARD:          call _Q_qtoll
-; HARD:          fitoq
-; HARD:          fqtoi
+; HARD-DAG:      call _Q_lltoq
+; HARD-DAG:      call _Q_qtoll
+; HARD-DAG:      fitoq
+; HARD-DAG:      fqtoi
 
 ; SOFT-LABEL:    test_itoq_qtoi
-; SOFT:          call _Q_lltoq
-; SOFT:          call _Q_qtoll
-; SOFT:          call _Q_itoq
-; SOFT:          call _Q_qtoi
+; SOFT-DAG:      call _Q_lltoq
+; SOFT-DAG:      call _Q_qtoll
+; SOFT-DAG:      call _Q_itoq
+; SOFT-DAG:      call _Q_qtoi
 
-define void @test_itoq_qtoi(i64 %a, i32 %b, i64* %ptr0, fp128* %ptr1) {
+define void @test_itoq_qtoi(i64 %a, i32 %b, fp128* %c, fp128* %d, i64* %ptr0, fp128* %ptr1) {
 entry:
   %0 = sitofp i64 %a to fp128
   store  fp128 %0, fp128* %ptr1, align 8
-  %1 = fptosi fp128 %0 to i64
+  %cval = load fp128* %c, align 8
+  %1 = fptosi fp128 %cval to i64
   store  i64 %1, i64* %ptr0, align 8
   %2 = sitofp i32 %b to fp128
   store  fp128 %2, fp128* %ptr1, align 8
-  %3 = fptosi fp128 %2 to i32
+  %dval = load fp128* %d, align 8
+  %3 = fptosi fp128 %dval to i32
   %4 = bitcast i64* %ptr0 to i32*
   store  i32 %3, i32* %4, align 8
   ret void
@@ -219,15 +221,17 @@ entry:
 ; SOFT-DAG:      call _Q_utoq
 ; SOFT-DAG:      call _Q_qtou
 
-define void @test_utoq_qtou(i64 %a, i32 %b, i64* %ptr0, fp128* %ptr1) {
+define void @test_utoq_qtou(i64 %a, i32 %b, fp128* %c, fp128* %d, i64* %ptr0, fp128* %ptr1) {
 entry:
   %0 = uitofp i64 %a to fp128
   store  fp128 %0, fp128* %ptr1, align 8
-  %1 = fptoui fp128 %0 to i64
+  %cval = load fp128* %c, align 8
+  %1 = fptoui fp128 %cval to i64
   store  i64 %1, i64* %ptr0, align 8
   %2 = uitofp i32 %b to fp128
   store  fp128 %2, fp128* %ptr1, align 8
-  %3 = fptoui fp128 %2 to i32
+  %dval = load fp128* %d, align 8
+  %3 = fptoui fp128 %dval to i32
   %4 = bitcast i64* %ptr0 to i32*
   store  i32 %3, i32* %4, align 8
   ret void
diff --git a/test/CodeGen/X86/float-conv-elim.ll b/test/CodeGen/X86/float-conv-elim.ll
new file mode 100644 (file)
index 0000000..13dde4a
--- /dev/null
@@ -0,0 +1,32 @@
+; RUN: llc -mcpu=x86-64 < %s | FileCheck %s
+
+; Make sure the float conversion is folded away as it should be.
+; CHECK-LABEL: foo
+; CHECK-NOT: cvt
+; CHECK: movzbl
+define i32 @foo(i8 %a) #0 {
+  %conv = uitofp i8 %a to float
+  %conv1 = fptosi float %conv to i32
+  ret i32 %conv1
+}
+
+; CHECK-LABEL: foo2
+; CHECK-NOT: cvt
+; CHECK: movsbl
+define i32 @foo2(i8 %a) #0 {
+  %conv = sitofp i8 %a to float
+  %conv1 = fptosi float %conv to i32
+  ret i32 %conv1
+}
+
+; CHECK-LABEL: bar
+; CHECK-NOT: cvt
+; CHECK: movl
+define zeroext i8 @bar(i8 zeroext %a) #0 {
+  %conv = uitofp i8 %a to float
+  %conv1 = fptoui float %conv to i8
+  ret i8 %conv1
+}
+
+attributes #0 = { nounwind ssp uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+