diff --git a/clang/include/clang/Basic/BuiltinsPPC.def b/clang/include/clang/Basic/BuiltinsPPC.def --- a/clang/include/clang/Basic/BuiltinsPPC.def +++ b/clang/include/clang/Basic/BuiltinsPPC.def @@ -780,6 +780,10 @@ BUILTIN(__builtin_cntlzdm, "ULLiULLiULLi", "") BUILTIN(__builtin_cnttzdm, "ULLiULLiULLi", "") +// Double-double (un)pack +BUILTIN(__builtin_unpack_longdouble, "dLdIi", "") +BUILTIN(__builtin_pack_longdouble, "Lddd", "") + // Generate random number BUILTIN(__builtin_darn, "LLi", "") BUILTIN(__builtin_darn_raw, "LLi", "") diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9802,6 +9802,8 @@ "this builtin is only valid on POWER%0 or later CPUs">; def err_ppc_builtin_requires_vsx : Error< "this builtin requires VSX to be enabled">; +def err_ppc_builtin_requires_abi : Error< + "this builtin requires ABI -mabi=%0">; def err_ppc_invalid_use_mma_type : Error< "invalid use of PPC MMA type">; def err_ppc_invalid_test_data_class_type : Error< diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -3382,6 +3382,18 @@ case PPC::BI__builtin_tabortdci: return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31) || SemaBuiltinConstantArgRange(TheCall, 2, 0, 31); + // According to GCC 'Basic PowerPC Built-in Functions Available on ISA 2.05', + // __builtin_(un)pack_longdouble are available only if long double uses IBM + // extended double representation. + case PPC::BI__builtin_unpack_longdouble: + if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 1)) + return true; + LLVM_FALLTHROUGH; + case PPC::BI__builtin_pack_longdouble: + if (&TI.getLongDoubleFormat() != &llvm::APFloat::PPCDoubleDouble()) + return Diag(TheCall->getBeginLoc(), diag::err_ppc_builtin_requires_abi) + << "ibmlongdouble"; + return false; case PPC::BI__builtin_altivec_dst: case PPC::BI__builtin_altivec_dstt: case PPC::BI__builtin_altivec_dstst: diff --git a/clang/test/CodeGen/builtins-ppc.c b/clang/test/CodeGen/builtins-ppc.c --- a/clang/test/CodeGen/builtins-ppc.c +++ b/clang/test/CodeGen/builtins-ppc.c @@ -36,3 +36,13 @@ // CHECK: call double @llvm.ppc.setflm(double %1) res = __builtin_setflm(res); } + +double test_builtin_unpack_ldbl(long double x) { + // CHECK: call double @llvm.ppc.unpack.longdouble(ppc_fp128 %0, i32 1) + return __builtin_unpack_longdouble(x, 1); +} + +long double test_builtin_pack_ldbl(double x, double y) { + // CHECK: call ppc_fp128 @llvm.ppc.pack.longdouble(double %0, double %1) + return __builtin_pack_longdouble(x, y); +} diff --git a/llvm/include/llvm/IR/Intrinsics.h b/llvm/include/llvm/IR/Intrinsics.h --- a/llvm/include/llvm/IR/Intrinsics.h +++ b/llvm/include/llvm/IR/Intrinsics.h @@ -140,7 +140,8 @@ Subdivide2Argument, Subdivide4Argument, VecOfBitcastsToInt, - AMX + AMX, + PPCQuad, } Kind; union { diff --git a/llvm/include/llvm/IR/IntrinsicsPowerPC.td b/llvm/include/llvm/IR/IntrinsicsPowerPC.td --- a/llvm/include/llvm/IR/IntrinsicsPowerPC.td +++ b/llvm/include/llvm/IR/IntrinsicsPowerPC.td @@ -50,6 +50,15 @@ Intrinsic<[llvm_i64_ty], [llvm_i64_ty, llvm_i64_ty], [IntrNoMem]>; + def int_ppc_unpack_longdouble : GCCBuiltin<"__builtin_unpack_longdouble">, + Intrinsic<[llvm_double_ty], + [llvm_ppcf128_ty, llvm_i32_ty], + [IntrNoMem]>; + def int_ppc_pack_longdouble : GCCBuiltin<"__builtin_pack_longdouble">, + Intrinsic<[llvm_ppcf128_ty], + [llvm_double_ty, llvm_double_ty], + [IntrNoMem]>; + // Generate a random number def int_ppc_darn : GCCBuiltin<"__builtin_darn">, Intrinsic<[llvm_i64_ty], [], [IntrNoMem]>; 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::PPCQuad, 0)); + return; case IIT_I1: OutputTable.push_back(IITDescriptor::get(IITDescriptor::Integer, 1)); return; @@ -1250,6 +1254,7 @@ case IITDescriptor::Float: return Type::getFloatTy(Context); case IITDescriptor::Double: return Type::getDoubleTy(Context); case IITDescriptor::Quad: return Type::getFP128Ty(Context); + case IITDescriptor::PPCQuad: return Type::getPPC_FP128Ty(Context); case IITDescriptor::Integer: return IntegerType::get(Context, D.Integer_Width); @@ -1432,6 +1437,7 @@ case IITDescriptor::Float: return !Ty->isFloatTy(); case IITDescriptor::Double: return !Ty->isDoubleTy(); case IITDescriptor::Quad: return !Ty->isFP128Ty(); + case IITDescriptor::PPCQuad: return !Ty->isPPC_FP128Ty(); case IITDescriptor::Integer: return !Ty->isIntegerTy(D.Integer_Width); case IITDescriptor::Vector: { VectorType *VT = dyn_cast(Ty); diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -601,6 +601,8 @@ // We want to custom lower some of our intrinsics. setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); + setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::f64, Custom); + setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::ppcf128, Custom); // To handle counter-based loop conditions. setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i1, Custom); @@ -10428,6 +10430,16 @@ } return DAG.getMergeValues(RetOps, dl); } + + case Intrinsic::ppc_unpack_longdouble: { + auto *Idx = dyn_cast(Op.getOperand(2)); + assert(Idx && (Idx->getSExtValue() == 0 || Idx->getSExtValue() == 1) && + "Argument of long double unpack must be 0 or 1!"); + return DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::f64, Op.getOperand(1), + DAG.getConstant(!!(Idx->getSExtValue()), dl, + Idx->getValueType(0))); + } + case Intrinsic::ppc_compare_exp_lt: case Intrinsic::ppc_compare_exp_gt: case Intrinsic::ppc_compare_exp_eq: @@ -11109,6 +11121,15 @@ Results.push_back(NewInt.getValue(1)); break; } + case ISD::INTRINSIC_WO_CHAIN: { + unsigned IntrinsicID = + cast(N->getOperand(0))->getZExtValue(); + + if (IntrinsicID == Intrinsic::ppc_pack_longdouble) + Results.push_back(DAG.getNode(ISD::BUILD_PAIR, dl, MVT::ppcf128, + N->getOperand(2), N->getOperand(1))); + break; + } case ISD::VAARG: { if (!Subtarget.isSVR4ABI() || Subtarget.isPPC64()) return; diff --git a/llvm/test/CodeGen/PowerPC/longdouble-pack.ll b/llvm/test/CodeGen/PowerPC/longdouble-pack.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/longdouble-pack.ll @@ -0,0 +1,34 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=powerpc64le-unknown-linux < %s | FileCheck %s +; RUN: llc -mtriple=powerpc64-ibm-aix-xcoff < %s | FileCheck %s + +define double @ldbl_1(ppc_fp128 %x) { +; CHECK-LABEL: ldbl_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: fmr 1, 2 +; CHECK-NEXT: blr +entry: + %0 = call double @llvm.ppc.unpack.longdouble(ppc_fp128 %x, i32 0) + ret double %0 +} + +define double @ldbl_2(ppc_fp128 %x) { +; CHECK-LABEL: ldbl_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: blr +entry: + %0 = call double @llvm.ppc.unpack.longdouble(ppc_fp128 %x, i32 1) + ret double %0 +} + +define ppc_fp128 @ldbl_pack(double %x, double %y) { +; CHECK-LABEL: ldbl_pack: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: blr +entry: + %0 = call ppc_fp128 @llvm.ppc.pack.longdouble(double %x, double %y) + ret ppc_fp128 %0 +} + +declare double @llvm.ppc.unpack.longdouble(ppc_fp128, i32) +declare ppc_fp128 @llvm.ppc.pack.longdouble(double, double) 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);