CodeGen: generate single libcall for fptrunc -> f16 operations.
authorTim Northover <tnorthover@apple.com>
Thu, 17 Jul 2014 11:12:12 +0000 (11:12 +0000)
committerTim Northover <tnorthover@apple.com>
Thu, 17 Jul 2014 11:12:12 +0000 (11:12 +0000)
Previously we asserted on this code. Currently compiler-rt doesn't
actually implement any of these new libcalls, but external help is
pretty much the only viable option for LLVM.

I've followed the much more generic "__truncST2" naming, as opposed to
the odd name for f32 -> f16 truncation. This can obviously be changed
later, or overridden by any targets that need to.

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

include/llvm/CodeGen/RuntimeLibcalls.h
lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
lib/CodeGen/SelectionDAG/LegalizeTypes.h
lib/CodeGen/TargetLoweringBase.cpp
lib/Target/X86/X86ISelLowering.cpp
test/CodeGen/X86/cvt16.ll

index 009b8a0f697a1ba50bee6d8f20548495d24adf09..81db8a2f79b577d7f68141ef16fc0c3a72bd8265 100644 (file)
@@ -210,6 +210,10 @@ namespace RTLIB {
     FPEXT_F32_F64,
     FPEXT_F16_F32,
     FPROUND_F32_F16,
+    FPROUND_F64_F16,
+    FPROUND_F80_F16,
+    FPROUND_F128_F16,
+    FPROUND_PPCF128_F16,
     FPROUND_F64_F32,
     FPROUND_F80_F32,
     FPROUND_F128_F32,
index 58f290e113704554fcab75846740533d475ca6d5..16c5b4ba77681486f2af5f820b5cd5541d80f0c5 100644 (file)
@@ -3529,13 +3529,13 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node) {
         DAG.getNode(ISD::FP_EXTEND, dl, Node->getValueType(0), Res));
     break;
   }
-  case ISD::FP_TO_FP16:
-    // Can't use two-step truncation here because the rounding may be
-    // significant.
-    assert(Node->getOperand(0).getValueType() == MVT::f32 &&
-           "Don't know libcall for FPROUND_F64_F16");
-    Results.push_back(ExpandLibCall(RTLIB::FPROUND_F32_F16, Node, false));
+  case ISD::FP_TO_FP16: {
+    RTLIB::Libcall LC =
+        RTLIB::getFPROUND(Node->getOperand(0).getValueType(), MVT::f16);
+    assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unable to expand fp_to_fp16");
+    Results.push_back(ExpandLibCall(LC, Node, false));
     break;
+  }
   case ISD::ConstantFP: {
     ConstantFPSDNode *CFP = cast<ConstantFPSDNode>(Node);
     // Check to see if this FP immediate is already legal.
index f6796e0828f248823b8f859553fd76a7a7f1a9e9..20ec3ac5e62469c6d78382b1d7804526248cfc34 100644 (file)
@@ -632,10 +632,10 @@ bool DAGTypeLegalizer::SoftenFloatOperand(SDNode *N, unsigned OpNo) {
 
   case ISD::BITCAST:     Res = SoftenFloatOp_BITCAST(N); break;
   case ISD::BR_CC:       Res = SoftenFloatOp_BR_CC(N); break;
+  case ISD::FP_TO_FP16:  // Same as FP_ROUND for softening purposes
   case ISD::FP_ROUND:    Res = SoftenFloatOp_FP_ROUND(N); break;
   case ISD::FP_TO_SINT:  Res = SoftenFloatOp_FP_TO_SINT(N); break;
   case ISD::FP_TO_UINT:  Res = SoftenFloatOp_FP_TO_UINT(N); break;
-  case ISD::FP_TO_FP16:  Res = SoftenFloatOp_FP_TO_FP16(N); break;
   case ISD::SELECT_CC:   Res = SoftenFloatOp_SELECT_CC(N); break;
   case ISD::SETCC:       Res = SoftenFloatOp_SETCC(N); break;
   case ISD::STORE:       Res = SoftenFloatOp_STORE(N, OpNo); break;
@@ -662,10 +662,15 @@ SDValue DAGTypeLegalizer::SoftenFloatOp_BITCAST(SDNode *N) {
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatOp_FP_ROUND(SDNode *N) {
+  // We actually deal with the partially-softened FP_TO_FP16 node too, which
+  // returns an i16 so doesn't meet the constraints necessary for FP_ROUND.
+  assert(N->getOpcode() == ISD::FP_ROUND || N->getOpcode() == ISD::FP_TO_FP16);
+
   EVT SVT = N->getOperand(0).getValueType();
   EVT RVT = N->getValueType(0);
+  EVT FloatRVT = N->getOpcode() == ISD::FP_TO_FP16 ? MVT::f16 : RVT;
 
-  RTLIB::Libcall LC = RTLIB::getFPROUND(SVT, RVT);
+  RTLIB::Libcall LC = RTLIB::getFPROUND(SVT, FloatRVT);
   assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unsupported FP_ROUND libcall");
 
   SDValue Op = GetSoftenedFloat(N->getOperand(0));
@@ -711,15 +716,6 @@ SDValue DAGTypeLegalizer::SoftenFloatOp_FP_TO_UINT(SDNode *N) {
   return TLI.makeLibCall(DAG, LC, RVT, &Op, 1, false, SDLoc(N)).first;
 }
 
-SDValue DAGTypeLegalizer::SoftenFloatOp_FP_TO_FP16(SDNode *N) {
-  assert(N->getOperand(0).getValueType() == MVT::f32 &&
-         "Cannot soften in one step");
-  EVT RVT = N->getValueType(0);
-  RTLIB::Libcall LC = RTLIB::FPROUND_F32_F16;
-  SDValue Op = GetSoftenedFloat(N->getOperand(0));
-  return TLI.makeLibCall(DAG, LC, RVT, &Op, 1, false, SDLoc(N)).first;
-}
-
 SDValue DAGTypeLegalizer::SoftenFloatOp_SELECT_CC(SDNode *N) {
   SDValue NewLHS = N->getOperand(0), NewRHS = N->getOperand(1);
   ISD::CondCode CCCode = cast<CondCodeSDNode>(N->getOperand(4))->get();
index 92a1b70a58c16d7d82656df30fa972a9b0eab9ec..63c74a05232eaef8455260c3540b8647986528c5 100644 (file)
@@ -428,7 +428,6 @@ private:
   SDValue SoftenFloatOp_FP_ROUND(SDNode *N);
   SDValue SoftenFloatOp_FP_TO_SINT(SDNode *N);
   SDValue SoftenFloatOp_FP_TO_UINT(SDNode *N);
-  SDValue SoftenFloatOp_FP_TO_FP16(SDNode *N);
   SDValue SoftenFloatOp_SELECT_CC(SDNode *N);
   SDValue SoftenFloatOp_SETCC(SDNode *N);
   SDValue SoftenFloatOp_STORE(SDNode *N, unsigned OpNo);
index c574fd4854a97a92cbce043b8d4503a1ca86ab94..efbcd3398649da2775169ef4b2f455ec8515ccbb 100644 (file)
@@ -220,6 +220,10 @@ static void InitLibcallNames(const char **Names, const Triple &TT) {
   Names[RTLIB::FPEXT_F32_F64] = "__extendsfdf2";
   Names[RTLIB::FPEXT_F16_F32] = "__gnu_h2f_ieee";
   Names[RTLIB::FPROUND_F32_F16] = "__gnu_f2h_ieee";
+  Names[RTLIB::FPROUND_F64_F16] = "__truncdfhf2";
+  Names[RTLIB::FPROUND_F80_F16] = "__truncxfhf2";
+  Names[RTLIB::FPROUND_F128_F16] = "__trunctfhf2";
+  Names[RTLIB::FPROUND_PPCF128_F16] = "__trunctfhf2";
   Names[RTLIB::FPROUND_F64_F32] = "__truncdfsf2";
   Names[RTLIB::FPROUND_F80_F32] = "__truncxfsf2";
   Names[RTLIB::FPROUND_F128_F32] = "__trunctfsf2";
@@ -434,7 +438,18 @@ RTLIB::Libcall RTLIB::getFPEXT(EVT OpVT, EVT RetVT) {
 /// getFPROUND - Return the FPROUND_*_* value for the given types, or
 /// UNKNOWN_LIBCALL if there is none.
 RTLIB::Libcall RTLIB::getFPROUND(EVT OpVT, EVT RetVT) {
-  if (RetVT == MVT::f32) {
+  if (RetVT == MVT::f16) {
+    if (OpVT == MVT::f32)
+      return FPROUND_F32_F16;
+    if (OpVT == MVT::f64)
+      return FPROUND_F64_F16;
+    if (OpVT == MVT::f80)
+      return FPROUND_F80_F16;
+    if (OpVT == MVT::f128)
+      return FPROUND_F128_F16;
+    if (OpVT == MVT::ppcf128)
+      return FPROUND_PPCF128_F16;
+  } else if (RetVT == MVT::f32) {
     if (OpVT == MVT::f64)
       return FPROUND_F64_F32;
     if (OpVT == MVT::f80)
index d3d2c76de215ae4385d532c64d35b40e272bc109..e8fe5c9da6a44da12ffbeacad20037daf840e3d6 100644 (file)
@@ -523,9 +523,11 @@ void X86TargetLowering::resetOperationActions() {
     setOperationAction(ISD::FP_TO_FP16, MVT::f32, Expand);
   }
 
-  // There's never any support for extending beyond MVT::f32.
+  // There's never any support for operations beyond MVT::f32.
   setOperationAction(ISD::FP16_TO_FP, MVT::f64, Expand);
   setOperationAction(ISD::FP16_TO_FP, MVT::f80, Expand);
+  setOperationAction(ISD::FP_TO_FP16, MVT::f64, Expand);
+  setOperationAction(ISD::FP_TO_FP16, MVT::f80, Expand);
 
   if (Subtarget->hasPOPCNT()) {
     setOperationAction(ISD::CTPOP          , MVT::i8   , Promote);
index 501145ca7151000544aae48d0219f1d20cf325e7..4d920e2d23d250371c5373c9f25264e142452e21 100644 (file)
@@ -73,6 +73,17 @@ define double @test4(i16* nocapture %src) {
 ; F16C: vcvtss2sd
 ; F16C: ret
 
+
+define i16 @test5(double %src) {
+  %val = tail call i16 @llvm.convert.to.fp16.f64(double %src)
+  ret i16 %val
+}
+; CHECK-LABEL: test5:
+; LIBCALL: jmp  __truncdfhf2
+; SOFTFLOAT: callq  __truncdfhf2
+; F16C: jmp __truncdfhf2
+
 declare float @llvm.convert.from.fp16.f32(i16) nounwind readnone
 declare i16 @llvm.convert.to.fp16.f32(float) nounwind readnone
 declare double @llvm.convert.from.fp16.f64(i16) nounwind readnone
+declare i16 @llvm.convert.to.fp16.f64(double) nounwind readnone