Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -484,14 +484,15 @@ if (TM.Options.UseSoftFloat || !Subtarget->hasF16C()) { setOperationAction(ISD::FP16_TO_FP, MVT::f32, Expand); setOperationAction(ISD::FP_TO_FP16, MVT::f32, Expand); + setOperationAction(ISD::FP_TO_FP16, MVT::f64, Expand); + setOperationAction(ISD::FP_TO_FP16, MVT::f80, Expand); + } else { + setOperationAction(ISD::FP_TO_FP16, MVT::f64, Custom); + setOperationAction(ISD::FP_TO_FP16, MVT::f80, Custom); } - // 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); - setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::f16, Expand); setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f16, Expand); setLoadExtAction(ISD::EXTLOAD, MVT::f80, MVT::f16, Expand); @@ -16792,6 +16793,24 @@ Op.getOperand(1), Op.getOperand(2)); } +static SDValue LowerFP_TO_FP16(SDValue Op, const X86Subtarget *Subtarget, + SelectionDAG &DAG) { + assert(Subtarget->hasF16C() && "This expansion requires feature F16C!"); + + if (!DAG.getTarget().Options.UnsafeFPMath) + // Let the backend expand this node into a library call. + return SDValue(); + + // Under fastmath, we can expand this node into a fround (from f64/f80 to f32) + // followed by a float-half conversion. + SDValue Op0 = Op.getOperand(0); + assert((Op0.getSimpleValueType() == MVT::f64 || + Op0.getSimpleValueType() == MVT::f80) && "Unexpected value type!"); + SDValue FloatVal = DAG.getNode(ISD::FP_ROUND, SDLoc(Op), MVT::f32, Op0, + DAG.getIntPtrConstant(0)); + return DAG.getNode(ISD::FP_TO_FP16, SDLoc(Op), MVT::i16, FloatVal); +} + static SDValue LowerFSINCOS(SDValue Op, const X86Subtarget *Subtarget, SelectionDAG &DAG) { assert(Subtarget->isTargetDarwin() && Subtarget->is64Bit()); @@ -16880,6 +16899,7 @@ case ISD::ANY_EXTEND: return LowerANY_EXTEND(Op, Subtarget, DAG); case ISD::FP_TO_SINT: return LowerFP_TO_SINT(Op, DAG); case ISD::FP_TO_UINT: return LowerFP_TO_UINT(Op, DAG); + case ISD::FP_TO_FP16: return LowerFP_TO_FP16(Op, Subtarget, DAG); case ISD::FP_EXTEND: return LowerFP_EXTEND(Op, DAG); case ISD::LOAD: return LowerExtendedLoad(Op, Subtarget, DAG); case ISD::FABS: Index: test/CodeGen/X86/fastmath-float-half-conversion.ll =================================================================== --- test/CodeGen/X86/fastmath-float-half-conversion.ll +++ test/CodeGen/X86/fastmath-float-half-conversion.ll @@ -0,0 +1,46 @@ +; RUN: llc -mtriple=x86_64-unknown-unknown -mattr=+f16c < %s | FileCheck %s + +define zeroext i16 @test1_fast(double %d) #0 { +; CHECK-LABEL: test1_fast: +; CHECK-NOT: callq {{_+}}truncdfhf2 +; CHECK: vcvtsd2ss %xmm0, %xmm0, %xmm0 +; CHECK-NEXT: vcvtps2ph $0, %xmm0, %xmm0 +; CHECK: ret +entry: + %0 = tail call i16 @llvm.convert.to.fp16.f64(double %d) + ret i16 %0 +} + +define zeroext i16 @test2_fast(x86_fp80 %d) #0 { +; CHECK-LABEL: test2_fast: +; CHECK-NOT: callq {{_+}}truncxfhf2 +; CHECK: vcvtps2ph $0, %xmm0, %xmm0 +; CHECK: ret +entry: + %0 = tail call i16 @llvm.convert.to.fp16.f80(x86_fp80 %d) + ret i16 %0 +} + +define zeroext i16 @test1(double %d) #1 { +; CHECK-LABEL: test1: +; CHECK: callq {{_+}}truncdfhf2 +; CHECK: ret +entry: + %0 = tail call i16 @llvm.convert.to.fp16.f64(double %d) + ret i16 %0 +} + +define zeroext i16 @test2(x86_fp80 %d) #1 { +; CHECK-LABEL: test2: +; CHECK: callq {{_+}}truncxfhf2 +; CHECK: ret +entry: + %0 = tail call i16 @llvm.convert.to.fp16.f80(x86_fp80 %d) + ret i16 %0 +} + +declare i16 @llvm.convert.to.fp16.f64(double) +declare i16 @llvm.convert.to.fp16.f80(x86_fp80) + +attributes #0 = { nounwind readnone uwtable "unsafe-fp-math"="true" "use-soft-float"="false" } +attributes #1 = { nounwind readnone uwtable "unsafe-fp-math"="false" "use-soft-float"="false" }