diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h --- a/llvm/include/llvm/CodeGen/ISDOpcodes.h +++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h @@ -851,6 +851,12 @@ /// address spaces. ADDRSPACECAST, + /// PPCF128_TO_FP, FP_TO_PPCF128 - These operators perform conversion + /// between ppc_fp128 and IEEE float type, especially fp128, since their + /// conversion is neither truncation nor extension. + PPCF128_TO_FP, + FP_TO_PPCF128, + /// FP16_TO_FP, FP_TO_FP16 - These operators are used to perform promotions /// and truncation for half-precision (16 bit) floating numbers. These nodes /// form a semi-softened interface for dealing with f16 (as an i16), which diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -1346,6 +1346,12 @@ def int_convert_from_fp16 : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [llvm_i16_ty]>; } +// Intrinsics to support converting between 128-bit float point formats +let IntrProperties = [IntrNoMem, IntrWillReturn] in { +def int_convert_to_ppcf128 : DefaultAttrsIntrinsic<[llvm_ppcf128_ty], [llvm_f128_ty]>; +def int_convert_from_ppcf128 : DefaultAttrsIntrinsic<[llvm_f128_ty], [llvm_ppcf128_ty]>; +} + // Saturating floating point to integer intrinsics let IntrProperties = [IntrNoMem, IntrSpeculatable, IntrWillReturn] in { def int_fptoui_sat : DefaultAttrsIntrinsic<[llvm_anyint_ty], [llvm_anyfloat_ty]>; diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.def b/llvm/include/llvm/IR/RuntimeLibcalls.def --- a/llvm/include/llvm/IR/RuntimeLibcalls.def +++ b/llvm/include/llvm/IR/RuntimeLibcalls.def @@ -376,6 +376,8 @@ HANDLE_LIBCALL(UINTTOFP_I128_F80, "__floatuntixf") HANDLE_LIBCALL(UINTTOFP_I128_F128, "__floatuntitf") HANDLE_LIBCALL(UINTTOFP_I128_PPCF128, "__floatuntitf") +HANDLE_LIBCALL(CONVERT_F128_PPCF128, "__trunctfkf2") +HANDLE_LIBCALL(CONVERT_PPCF128_F128, "__extendkftf2") // Comparison HANDLE_LIBCALL(OEQ_F32, "__eqsf2") diff --git a/llvm/include/llvm/Target/TargetSelectionDAG.td b/llvm/include/llvm/Target/TargetSelectionDAG.td --- a/llvm/include/llvm/Target/TargetSelectionDAG.td +++ b/llvm/include/llvm/Target/TargetSelectionDAG.td @@ -158,6 +158,9 @@ def SDTFPExtendOp : SDTypeProfile<1, 1, [ // fpextend SDTCisFP<0>, SDTCisFP<1>, SDTCisOpSmallerThanOp<1, 0>, SDTCisSameNumEltsAs<0, 1> ]>; +def SDTFPCvtOp : SDTypeProfile<1, 1, [ // fp.convert + SDTCisFP<0>, SDTCisFP<1> +]>; def SDTIntToFPOp : SDTypeProfile<1, 1, [ // [su]int_to_fp SDTCisFP<0>, SDTCisInt<1>, SDTCisSameNumEltsAs<0, 1> ]>; @@ -503,6 +506,8 @@ def fp_to_uint_sat : SDNode<"ISD::FP_TO_UINT_SAT" , SDTFPToIntSatOp>; def f16_to_fp : SDNode<"ISD::FP16_TO_FP" , SDTIntToFPOp>; def fp_to_f16 : SDNode<"ISD::FP_TO_FP16" , SDTFPToIntOp>; +def ppcf128_to_fp : SDNode<"ISD::PPCF128_TO_FP", SDTFPCvtOp>; +def fp_to_ppcf128 : SDNode<"ISD::FP_TO_PPCF128", SDTFPCvtOp>; def strict_fadd : SDNode<"ISD::STRICT_FADD", SDTFPBinOp, [SDNPHasChain, SDNPCommutative]>; diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -1549,6 +1549,8 @@ case Intrinsic::fptosi_sat: case Intrinsic::convert_from_fp16: case Intrinsic::convert_to_fp16: + case Intrinsic::convert_from_ppcf128: + case Intrinsic::convert_to_ppcf128: case Intrinsic::amdgcn_cos: case Intrinsic::amdgcn_cubeid: case Intrinsic::amdgcn_cubema: diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp @@ -1258,6 +1258,9 @@ case ISD::UINT_TO_FP: ExpandFloatRes_XINT_TO_FP(N, Lo, Hi); break; case ISD::STRICT_FREM: case ISD::FREM: ExpandFloatRes_FREM(N, Lo, Hi); break; + case ISD::FP_TO_PPCF128: + ExpandFloatRes_CONVERT_FROM_FP(N, Lo, Hi); + break; } // If Lo/Hi is null, the sub-method took care of registering results etc. @@ -1644,6 +1647,11 @@ ReplaceValueWith(SDValue(LD, 1), Chain); } +void DAGTypeLegalizer::ExpandFloatRes_CONVERT_FROM_FP(SDNode *N, SDValue &Lo, + SDValue &Hi) { + ExpandFloatRes_Unary(N, RTLIB::CONVERT_F128_PPCF128, Lo, Hi); +} + void DAGTypeLegalizer::ExpandFloatRes_XINT_TO_FP(SDNode *N, SDValue &Lo, SDValue &Hi) { assert(N->getValueType(0) == MVT::ppcf128 && "Unsupported XINT_TO_FP!"); @@ -1792,6 +1800,9 @@ case ISD::SETCC: Res = ExpandFloatOp_SETCC(N); break; case ISD::STORE: Res = ExpandFloatOp_STORE(cast(N), OpNo); break; + case ISD::PPCF128_TO_FP: + Res = ExpandFloatOp_PPCF128_TO_FP(N); + break; } // If the result is null, the sub-method took care of registering results etc. @@ -2049,6 +2060,16 @@ RVT, N->getOperand(0), CallOptions, SDLoc(N)).first; } +SDValue DAGTypeLegalizer::ExpandFloatOp_PPCF128_TO_FP(SDNode *N) { + SDLoc dl(N); + SDValue Op = N->getOperand(0); + TargetLowering::MakeLibCallOptions CallOptions; + std::pair Tmp = + TLI.makeLibCall(DAG, RTLIB::CONVERT_PPCF128_F128, MVT::f128, Op, + CallOptions, dl, SDValue()); + return Tmp.first; +} + //===----------------------------------------------------------------------===// // Float Operand Promotion //===----------------------------------------------------------------------===// diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h @@ -634,6 +634,7 @@ void ExpandFloatRes_FTRUNC (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandFloatRes_LOAD (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandFloatRes_XINT_TO_FP(SDNode *N, SDValue &Lo, SDValue &Hi); + void ExpandFloatRes_CONVERT_FROM_FP(SDNode *N, SDValue &Lo, SDValue &Hi); // Float Operand Expansion. bool ExpandFloatOperand(SDNode *N, unsigned OpNo); @@ -647,6 +648,7 @@ SDValue ExpandFloatOp_LLRINT(SDNode *N); SDValue ExpandFloatOp_SELECT_CC(SDNode *N); SDValue ExpandFloatOp_SETCC(SDNode *N); + SDValue ExpandFloatOp_PPCF128_TO_FP(SDNode *N); SDValue ExpandFloatOp_STORE(SDNode *N, unsigned OpNo); void FloatExpandSetCCOperands(SDValue &NewLHS, SDValue &NewRHS, diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -6383,6 +6383,14 @@ DAG.getNode(ISD::BITCAST, sdl, MVT::f16, getValue(I.getArgOperand(0))))); return; + case Intrinsic::convert_to_ppcf128: + setValue(&I, DAG.getNode(ISD::FP_TO_PPCF128, sdl, MVT::ppcf128, + getValue(I.getArgOperand(0)))); + return; + case Intrinsic::convert_from_ppcf128: + setValue(&I, DAG.getNode(ISD::PPCF128_TO_FP, sdl, MVT::f128, + getValue(I.getArgOperand(0)))); + return; case Intrinsic::fptosi_sat: { EVT VT = TLI.getValueType(DAG.getDataLayout(), I.getType()); setValue(&I, DAG.getNode(ISD::FP_TO_SINT_SAT, sdl, VT, diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp @@ -357,6 +357,8 @@ case ISD::FP_TO_UINT_SAT: return "fp_to_uint_sat"; case ISD::BITCAST: return "bitcast"; case ISD::ADDRSPACECAST: return "addrspacecast"; + case ISD::PPCF128_TO_FP: return "ppcf128_to_fp"; + case ISD::FP_TO_PPCF128: return "fp_to_ppcf128"; case ISD::FP16_TO_FP: return "fp16_to_fp"; case ISD::STRICT_FP16_TO_FP: return "strict_fp16_to_fp"; case ISD::FP_TO_FP16: return "fp_to_fp16"; diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp --- a/llvm/lib/IR/Function.cpp +++ b/llvm/lib/IR/Function.cpp @@ -979,7 +979,8 @@ IIT_BF16 = 48, IIT_STRUCT9 = 49, IIT_V256 = 50, - IIT_AMX = 51 + IIT_AMX = 51, + IIT_PPCF128 = 52 }; static void DecodeIITType(unsigned &NextElt, ArrayRef Infos, @@ -1026,6 +1027,9 @@ case IIT_F128: OutputTable.push_back(IITDescriptor::get(IITDescriptor::Quad, 0)); return; + case IIT_PPCF128: + OutputTable.push_back(IITDescriptor::get(IITDescriptor::Quad, 0)); + return; case IIT_I1: OutputTable.push_back(IITDescriptor::get(IITDescriptor::Integer, 1)); return; @@ -1431,7 +1435,8 @@ case IITDescriptor::BFloat: return !Ty->isBFloatTy(); case IITDescriptor::Float: return !Ty->isFloatTy(); case IITDescriptor::Double: return !Ty->isDoubleTy(); - case IITDescriptor::Quad: return !Ty->isFP128Ty(); + case IITDescriptor::Quad: + return !Ty->isFP128Ty() && !Ty->isPPC_FP128Ty(); case IITDescriptor::Integer: return !Ty->isIntegerTy(D.Integer_Width); case IITDescriptor::Vector: { VectorType *VT = dyn_cast(Ty); diff --git a/llvm/test/CodeGen/PowerPC/f128-truncateNconv.ll b/llvm/test/CodeGen/PowerPC/f128-truncateNconv.ll --- a/llvm/test/CodeGen/PowerPC/f128-truncateNconv.ll +++ b/llvm/test/CodeGen/PowerPC/f128-truncateNconv.ll @@ -1403,3 +1403,96 @@ store i8 %conv, i8* %res, align 1 ret void } + +define void @qpConvppcf128(fp128 %src, ppc_fp128* %dst) { +; CHECK-LABEL: qpConvppcf128: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mflr r0 +; CHECK-NEXT: .cfi_def_cfa_offset 48 +; CHECK-NEXT: .cfi_offset lr, 16 +; CHECK-NEXT: .cfi_offset r30, -16 +; CHECK-NEXT: std r30, -16(r1) # 8-byte Folded Spill +; CHECK-NEXT: std r0, 16(r1) +; CHECK-NEXT: stdu r1, -48(r1) +; CHECK-NEXT: mr r30, r5 +; CHECK-NEXT: bl __trunctfkf2 +; CHECK-NEXT: nop +; CHECK-NEXT: stfd f2, 8(r30) +; CHECK-NEXT: stfd f1, 0(r30) +; CHECK-NEXT: addi r1, r1, 48 +; CHECK-NEXT: ld r0, 16(r1) +; CHECK-NEXT: ld r30, -16(r1) # 8-byte Folded Reload +; CHECK-NEXT: mtlr r0 +; CHECK-NEXT: blr +; +; CHECK-P8-LABEL: qpConvppcf128: +; CHECK-P8: # %bb.0: # %entry +; CHECK-P8-NEXT: mflr r0 +; CHECK-P8-NEXT: .cfi_def_cfa_offset 48 +; CHECK-P8-NEXT: .cfi_offset lr, 16 +; CHECK-P8-NEXT: .cfi_offset r30, -16 +; CHECK-P8-NEXT: std r30, -16(r1) # 8-byte Folded Spill +; CHECK-P8-NEXT: std r0, 16(r1) +; CHECK-P8-NEXT: stdu r1, -48(r1) +; CHECK-P8-NEXT: mr r30, r5 +; CHECK-P8-NEXT: bl __trunctfkf2 +; CHECK-P8-NEXT: nop +; CHECK-P8-NEXT: stfd f2, 8(r30) +; CHECK-P8-NEXT: stfd f1, 0(r30) +; CHECK-P8-NEXT: addi r1, r1, 48 +; CHECK-P8-NEXT: ld r0, 16(r1) +; CHECK-P8-NEXT: ld r30, -16(r1) # 8-byte Folded Reload +; CHECK-P8-NEXT: mtlr r0 +; CHECK-P8-NEXT: blr +entry: + %res = call ppc_fp128 @llvm.convert.to.ppcf128(fp128 %src) + store ppc_fp128 %res, ppc_fp128* %dst, align 16 + ret void +} + +define void @ppcf128Convqp(ppc_fp128 %src, fp128* %dst) { +; CHECK-LABEL: ppcf128Convqp: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mflr r0 +; CHECK-NEXT: .cfi_def_cfa_offset 48 +; CHECK-NEXT: .cfi_offset lr, 16 +; CHECK-NEXT: .cfi_offset r30, -16 +; CHECK-NEXT: std r30, -16(r1) # 8-byte Folded Spill +; CHECK-NEXT: std r0, 16(r1) +; CHECK-NEXT: stdu r1, -48(r1) +; CHECK-NEXT: mr r30, r5 +; CHECK-NEXT: bl __extendkftf2 +; CHECK-NEXT: nop +; CHECK-NEXT: stxv v2, 0(r30) +; CHECK-NEXT: addi r1, r1, 48 +; CHECK-NEXT: ld r0, 16(r1) +; CHECK-NEXT: ld r30, -16(r1) # 8-byte Folded Reload +; CHECK-NEXT: mtlr r0 +; CHECK-NEXT: blr +; +; CHECK-P8-LABEL: ppcf128Convqp: +; CHECK-P8: # %bb.0: # %entry +; CHECK-P8-NEXT: mflr r0 +; CHECK-P8-NEXT: .cfi_def_cfa_offset 48 +; CHECK-P8-NEXT: .cfi_offset lr, 16 +; CHECK-P8-NEXT: .cfi_offset r30, -16 +; CHECK-P8-NEXT: std r30, -16(r1) # 8-byte Folded Spill +; CHECK-P8-NEXT: std r0, 16(r1) +; CHECK-P8-NEXT: stdu r1, -48(r1) +; CHECK-P8-NEXT: mr r30, r5 +; CHECK-P8-NEXT: bl __extendkftf2 +; CHECK-P8-NEXT: nop +; CHECK-P8-NEXT: stvx v2, 0, r30 +; CHECK-P8-NEXT: addi r1, r1, 48 +; CHECK-P8-NEXT: ld r0, 16(r1) +; CHECK-P8-NEXT: ld r30, -16(r1) # 8-byte Folded Reload +; CHECK-P8-NEXT: mtlr r0 +; CHECK-P8-NEXT: blr +entry: + %res = call fp128 @llvm.convert.from.ppcf128(ppc_fp128 %src) + store fp128 %res, fp128* %dst, align 16 + ret void +} + +declare ppc_fp128 @llvm.convert.to.ppcf128(fp128) +declare fp128 @llvm.convert.from.ppcf128(ppc_fp128) diff --git a/llvm/utils/TableGen/IntrinsicEmitter.cpp b/llvm/utils/TableGen/IntrinsicEmitter.cpp --- a/llvm/utils/TableGen/IntrinsicEmitter.cpp +++ b/llvm/utils/TableGen/IntrinsicEmitter.cpp @@ -249,7 +249,8 @@ IIT_BF16 = 48, IIT_STRUCT9 = 49, IIT_V256 = 50, - IIT_AMX = 51 + IIT_AMX = 51, + IIT_PPCF128 = 52, }; static void EncodeFixedValueType(MVT::SimpleValueType VT, @@ -274,6 +275,7 @@ case MVT::f32: return Sig.push_back(IIT_F32); case MVT::f64: return Sig.push_back(IIT_F64); case MVT::f128: return Sig.push_back(IIT_F128); + case MVT::ppcf128: return Sig.push_back(IIT_PPCF128); case MVT::token: return Sig.push_back(IIT_TOKEN); case MVT::Metadata: return Sig.push_back(IIT_METADATA); case MVT::x86mmx: return Sig.push_back(IIT_MMX);