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 @@ -152,6 +152,13 @@ BUILTIN(__builtin_ppc_mtspr, "vIiULi", "") BUILTIN(__builtin_ppc_stfiw, "viC*d", "") BUILTIN(__builtin_ppc_addex, "LLiLLiLLiCIi", "") +// select +BUILTIN(__builtin_ppc_maxfe, "LdLdLdLd.", "t") +BUILTIN(__builtin_ppc_maxfl, "dddd.", "t") +BUILTIN(__builtin_ppc_maxfs, "ffff.", "t") +BUILTIN(__builtin_ppc_minfe, "LdLdLdLd.", "t") +BUILTIN(__builtin_ppc_minfl, "dddd.", "t") +BUILTIN(__builtin_ppc_minfs, "ffff.", "t") BUILTIN(__builtin_ppc_get_timebase, "ULLi", "n") 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 @@ -9893,6 +9893,10 @@ "invalid use of PPC MMA type">; def err_ppc_invalid_test_data_class_type : Error< "expected a 'float' or 'double' for the first argument">; +def err_ppc_invalid_argument_type : Error< + "requires argument of %0 type (passed in %1)">; +def err_ppc_unsupported_argument_type : Error< + "unsupported argument type %0 for target %1">; def err_x86_builtin_invalid_rounding : Error< "invalid rounding argument">; def err_x86_builtin_invalid_scale : Error< diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp --- a/clang/lib/Basic/Targets/PPC.cpp +++ b/clang/lib/Basic/Targets/PPC.cpp @@ -247,6 +247,12 @@ Builder.defineMacro("__test_data_class", "__builtin_ppc_test_data_class"); Builder.defineMacro("__swdiv", "__builtin_ppc_swdiv"); Builder.defineMacro("__swdivs", "__builtin_ppc_swdivs"); + Builder.defineMacro("__builtin_maxfe", "__builtin_ppc_maxfe"); + Builder.defineMacro("__builtin_maxfl", "__builtin_ppc_maxfl"); + Builder.defineMacro("__builtin_maxfs", "__builtin_ppc_maxfs"); + Builder.defineMacro("__builtin_minfe", "__builtin_ppc_minfe"); + Builder.defineMacro("__builtin_minfl", "__builtin_ppc_minfl"); + Builder.defineMacro("__builtin_minfs", "__builtin_ppc_minfs"); } /// PPCTargetInfo::getTargetDefines - Return a set of the PowerPC-specific diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -16287,6 +16287,27 @@ return Builder.CreateCall(CGM.getIntrinsic(IntrinsicID), Ops, "test_data_class"); } + case PPC::BI__builtin_ppc_maxfe: + case PPC::BI__builtin_ppc_maxfl: + case PPC::BI__builtin_ppc_maxfs: + case PPC::BI__builtin_ppc_minfe: + case PPC::BI__builtin_ppc_minfl: + case PPC::BI__builtin_ppc_minfs: { + if (BuiltinID == PPC::BI__builtin_ppc_maxfe) + ID = Intrinsic::ppc_maxfe; + else if (BuiltinID == PPC::BI__builtin_ppc_maxfl) + ID = Intrinsic::ppc_maxfl; + else if (BuiltinID == PPC::BI__builtin_ppc_maxfs) + ID = Intrinsic::ppc_maxfs; + else if (BuiltinID == PPC::BI__builtin_ppc_minfe) + ID = Intrinsic::ppc_minfe; + else if (BuiltinID == PPC::BI__builtin_ppc_minfl) + ID = Intrinsic::ppc_minfl; + else if (BuiltinID == PPC::BI__builtin_ppc_minfs) + ID = Intrinsic::ppc_minfs; + llvm::Function *F = CGM.getIntrinsic(ID); + return Builder.CreateCall(F, Ops, ""); + } case PPC::BI__builtin_ppc_swdiv: case PPC::BI__builtin_ppc_swdivs: return Builder.CreateFDiv(Ops[0], Ops[1], "swdiv"); 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 @@ -3904,6 +3904,35 @@ diag::err_ppc_builtin_requires_vsx) || SemaBuiltinConstantArgRange(TheCall, 1, 0, 127); } + case PPC::BI__builtin_ppc_maxfe: + case PPC::BI__builtin_ppc_minfe: + case PPC::BI__builtin_ppc_maxfl: + case PPC::BI__builtin_ppc_minfl: + case PPC::BI__builtin_ppc_maxfs: + case PPC::BI__builtin_ppc_minfs: { + // FIXME: remove below check once -mlong-double-128 is supported on AIX. + if (Context.getTargetInfo().getTriple().isOSAIX() && + (BuiltinID == PPC::BI__builtin_ppc_maxfe || + BuiltinID == PPC::BI__builtin_ppc_minfe)) + return Diag(TheCall->getBeginLoc(), + diag::err_ppc_unsupported_argument_type) + << QualType(Context.LongDoubleTy) + << Context.getTargetInfo().getTriple().str(); + + // Argument type should be exact. + QualType ArgType = QualType(Context.LongDoubleTy); + if (BuiltinID == PPC::BI__builtin_ppc_maxfl || + BuiltinID == PPC::BI__builtin_ppc_minfl) + ArgType = QualType(Context.DoubleTy); + else if (BuiltinID == PPC::BI__builtin_ppc_maxfs || + BuiltinID == PPC::BI__builtin_ppc_minfs) + ArgType = QualType(Context.FloatTy); + for (unsigned I = 0, E = TheCall->getNumArgs(); I < E; ++I) + if (TheCall->getArg(I)->getType() != ArgType) + return Diag(TheCall->getBeginLoc(), diag::err_ppc_invalid_argument_type) + << ArgType << TheCall->getArg(I)->getType(); + return false; + } case PPC::BI__builtin_ppc_load8r: case PPC::BI__builtin_ppc_store8r: return SemaFeatureCheck(*this, TheCall, "isa-v206-instructions", diff --git a/clang/test/CodeGen/PowerPC/builtins-ppc.c b/clang/test/CodeGen/PowerPC/builtins-ppc.c --- a/clang/test/CodeGen/PowerPC/builtins-ppc.c +++ b/clang/test/CodeGen/PowerPC/builtins-ppc.c @@ -46,3 +46,37 @@ // CHECK: call ppc_fp128 @llvm.ppc.pack.longdouble(double %0, double %1) return __builtin_pack_longdouble(x, y); } + +void test_builtin_ppc_maxminfe(long double a, long double b, long double c, + long double d) { + volatile long double res; + // CHECK: call ppc_fp128 (ppc_fp128, ppc_fp128, ppc_fp128, ...) + // @llvm.ppc.maxfe(ppc_fp128 %0, ppc_fp128 %1, ppc_fp128 %2, ppc_fp128 %3) + res = __builtin_ppc_maxfe(a, b, c, d); + + // CHECK: call ppc_fp128 (ppc_fp128, ppc_fp128, ppc_fp128, ...) + // @llvm.ppc.minfe(ppc_fp128 %5, ppc_fp128 %6, ppc_fp128 %7, ppc_fp128 %8) + res = __builtin_ppc_minfe(a, b, c, d); +} + +void test_builtin_ppc_maxminfl(double a, double b, double c, double d) { + volatile double res; + // CHECK: call double (double, double, double, ...) @llvm.ppc.maxfl(double %0, + // double %1, double %2, double %3) + res = __builtin_ppc_maxfl(a, b, c, d); + + // CHECK: call double (double, double, double, ...) @llvm.ppc.minfl(double %5, + // double %6, double %7, double %8) + res = __builtin_ppc_minfl(a, b, c, d); +} + +void test_builtin_ppc_maxminfs(float a, float b, float c, float d) { + volatile float res; + // CHECK: call float (float, float, float, ...) @llvm.ppc.maxfs(float %0, + // float %1, float %2, float %3) + res = __builtin_ppc_maxfs(a, b, c, d); + + // CHECK: call float (float, float, float, ...) @llvm.ppc.minfs(float %5, + // float %6, float %7, float %8) + res = __builtin_ppc_minfs(a, b, c, d); +} diff --git a/clang/test/Sema/builtins-ppc.c b/clang/test/Sema/builtins-ppc.c --- a/clang/test/Sema/builtins-ppc.c +++ b/clang/test/Sema/builtins-ppc.c @@ -10,6 +10,12 @@ // RUN: -triple powerpc64le-unknown-unknown -DTEST_CRYPTO -fsyntax-only \ // RUN: -target-feature +vsx -verify %s +// RUN: %clang_cc1 -triple powerpc64le-unknown-unknown -DTEST_MAXMIN -fsyntax-only \ +// RUN: -verify %s + +// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -DTEST_MAXMINFE_AIX -fsyntax-only \ +// RUN: -verify %s + #ifdef TEST_HTM void test_htm() { __builtin_tbegin(4); // expected-error-re {{argument value {{.*}} is outside the valid range}} @@ -54,3 +60,24 @@ #endif +#ifdef TEST_MAXMIN +void test_maxmin() { + long double fe; + double fl; + float fs; + __builtin_ppc_maxfe(fl, fl, fl, fl); // expected-error-re {{requires argument of {{.*}} type (passed in {{.*}})}} + __builtin_ppc_minfe(fl, fl, fl, fl); // expected-error-re {{requires argument of {{.*}} type (passed in {{.*}})}} + __builtin_ppc_maxfl(fs, fs, fs, fs); // expected-error-re {{requires argument of {{.*}} type (passed in {{.*}})}} + __builtin_ppc_minfl(fs, fs, fs, fs); // expected-error-re {{requires argument of {{.*}} type (passed in {{.*}})}} + __builtin_ppc_maxfs(fe, fe, fe, fe); // expected-error-re {{requires argument of {{.*}} type (passed in {{.*}})}} + __builtin_ppc_minfs(fe, fe, fe, fe); // expected-error-re {{requires argument of {{.*}} type (passed in {{.*}})}} +} +#endif + +#ifdef TEST_MAXMINFE_AIX +void test_maxmin() { + long double fe; + __builtin_ppc_maxfe(fe, fe, fe, fe); // expected-error-re {{unsupported argument type 'long double' for target {{.*}}}} + __builtin_ppc_minfe(fe, fe, fe, fe); // expected-error-re {{unsupported argument type 'long double' for target {{.*}}}} +} +#endif 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 @@ -160,6 +160,36 @@ def int_ppc_fctuwz : GCCBuiltin<"__builtin_ppc_fctuwz">, Intrinsic <[llvm_double_ty], [llvm_double_ty], [IntrNoMem]>; + + // XL compatible select functions + def int_ppc_maxfe + : Intrinsic< + [llvm_ppcf128_ty], + [llvm_ppcf128_ty, llvm_ppcf128_ty, llvm_ppcf128_ty, llvm_vararg_ty], + [IntrNoMem]>; + def int_ppc_maxfl + : Intrinsic< + [llvm_double_ty], + [llvm_double_ty, llvm_double_ty, llvm_double_ty, llvm_vararg_ty], + [IntrNoMem]>; + def int_ppc_maxfs + : Intrinsic<[llvm_float_ty], + [llvm_float_ty, llvm_float_ty, llvm_float_ty, llvm_vararg_ty], + [IntrNoMem]>; + def int_ppc_minfe + : Intrinsic< + [llvm_ppcf128_ty], + [llvm_ppcf128_ty, llvm_ppcf128_ty, llvm_ppcf128_ty, llvm_vararg_ty], + [IntrNoMem]>; + def int_ppc_minfl + : Intrinsic< + [llvm_double_ty], + [llvm_double_ty, llvm_double_ty, llvm_double_ty, llvm_vararg_ty], + [IntrNoMem]>; + def int_ppc_minfs + : Intrinsic<[llvm_float_ty], + [llvm_float_ty, llvm_float_ty, llvm_float_ty, llvm_vararg_ty], + [IntrNoMem]>; } let TargetPrefix = "ppc" in { // All PPC intrinsics start with "llvm.ppc.". 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 @@ -10574,6 +10574,34 @@ dl, SDValue()); return Result.first; } + case Intrinsic::ppc_maxfe: + case Intrinsic::ppc_maxfl: + case Intrinsic::ppc_maxfs: + case Intrinsic::ppc_minfe: + case Intrinsic::ppc_minfl: + case Intrinsic::ppc_minfs: { + for (unsigned i = 4, e = Op.getNumOperands(); i < e; ++i) { + if (Op.getOperand(i).getValueType() != Op.getValueType()) + report_fatal_error("Intrinsic::ppc_[max|min]f[e|l|s] must have uniform " + "type arguments"); + } + ISD::CondCode CC = ISD::SETGT; + if (IntrinsicID == Intrinsic::ppc_minfe || + IntrinsicID == Intrinsic::ppc_minfl || + IntrinsicID == Intrinsic::ppc_minfs) + CC = ISD::SETLT; + // Below selection order follows XLC behavior: start from the last but one + // operand, move towards the first operand, end with the last operand. + unsigned I, Cnt; + I = Cnt = Op.getNumOperands() - 2; + SDValue Res = Op.getOperand(I); + for (--I; Cnt != 0; --Cnt, I = (--I == 0 ? (Op.getNumOperands() - 1) : I)) { + Res = LowerSELECT_CC( + DAG.getSelectCC(dl, Res, Op.getOperand(I), Res, Op.getOperand(I), CC), + DAG); + } + return Res; + } } // If this is a lowered altivec predicate compare, CompareOpc is set to the @@ -11234,6 +11262,8 @@ Results.push_back(DAG.getNode(ISD::BUILD_PAIR, dl, MVT::ppcf128, N->getOperand(2), N->getOperand(1))); break; + case Intrinsic::ppc_maxfe: + case Intrinsic::ppc_minfe: case Intrinsic::ppc_fnmsub: case Intrinsic::ppc_convert_f128_to_ppcf128: Results.push_back(LowerINTRINSIC_WO_CHAIN(SDValue(N, 0), DAG)); diff --git a/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-maxmin.ll b/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-maxmin.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-maxmin.ll @@ -0,0 +1,150 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mcpu=pwr9 -mtriple=powerpc64le-unknown-linux < %s | FileCheck %s + +declare ppc_fp128 @llvm.ppc.maxfe(ppc_fp128 %a, ppc_fp128 %b, ppc_fp128 %c, ...) +define ppc_fp128 @test_maxfe(ppc_fp128 %a, ppc_fp128 %b, ppc_fp128 %c, ppc_fp128 %d) { +; CHECK-LABEL: test_maxfe: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: fcmpu 0, 6, 4 +; CHECK-NEXT: fcmpu 1, 5, 3 +; CHECK-NEXT: crand 20, 6, 1 +; CHECK-NEXT: cror 20, 5, 20 +; CHECK-NEXT: bc 12, 20, .LBB0_2 +; CHECK-NEXT: # %bb.1: # %entry +; CHECK-NEXT: fmr 6, 4 +; CHECK-NEXT: .LBB0_2: # %entry +; CHECK-NEXT: fcmpu 0, 6, 2 +; CHECK-NEXT: bc 12, 20, .LBB0_4 +; CHECK-NEXT: # %bb.3: # %entry +; CHECK-NEXT: fmr 5, 3 +; CHECK-NEXT: .LBB0_4: # %entry +; CHECK-NEXT: fcmpu 1, 5, 1 +; CHECK-NEXT: crand 20, 6, 1 +; CHECK-NEXT: cror 20, 5, 20 +; CHECK-NEXT: bc 12, 20, .LBB0_6 +; CHECK-NEXT: # %bb.5: # %entry +; CHECK-NEXT: fmr 6, 2 +; CHECK-NEXT: .LBB0_6: # %entry +; CHECK-NEXT: fcmpu 0, 6, 8 +; CHECK-NEXT: bc 12, 20, .LBB0_8 +; CHECK-NEXT: # %bb.7: # %entry +; CHECK-NEXT: fmr 5, 1 +; CHECK-NEXT: .LBB0_8: # %entry +; CHECK-NEXT: fcmpu 1, 5, 7 +; CHECK-NEXT: crand 20, 6, 1 +; CHECK-NEXT: cror 20, 5, 20 +; CHECK-NEXT: bc 12, 20, .LBB0_10 +; CHECK-NEXT: # %bb.9: # %entry +; CHECK-NEXT: fmr 5, 7 +; CHECK-NEXT: .LBB0_10: # %entry +; CHECK-NEXT: bc 12, 20, .LBB0_12 +; CHECK-NEXT: # %bb.11: # %entry +; CHECK-NEXT: fmr 6, 8 +; CHECK-NEXT: .LBB0_12: # %entry +; CHECK-NEXT: fmr 1, 5 +; CHECK-NEXT: fmr 2, 6 +; CHECK-NEXT: blr +entry: + %0 = call ppc_fp128 (ppc_fp128, ppc_fp128, ppc_fp128, ...) @llvm.ppc.maxfe(ppc_fp128 %a, ppc_fp128 %b, ppc_fp128 %c, ppc_fp128 %d) + ret ppc_fp128 %0 +} + +declare double @llvm.ppc.maxfl(double %a, double %b, double %c, ...) +define double @test_maxfl(double %a, double %b, double %c, double %d) { +; CHECK-LABEL: test_maxfl: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xsmaxcdp 0, 3, 2 +; CHECK-NEXT: xsmaxcdp 0, 0, 1 +; CHECK-NEXT: xsmaxcdp 1, 0, 4 +; CHECK-NEXT: blr +entry: + %0 = call double (double, double, double, ...) @llvm.ppc.maxfl(double %a, double %b, double %c, double %d) + ret double %0 +} + +declare float @llvm.ppc.maxfs(float %a, float %b, float %c, ...) +define float @test_maxfs(float %a, float %b, float %c, float %d) { +; CHECK-LABEL: test_maxfs: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xsmaxcdp 0, 3, 2 +; CHECK-NEXT: xsmaxcdp 0, 0, 1 +; CHECK-NEXT: xsmaxcdp 1, 0, 4 +; CHECK-NEXT: blr +entry: + %0 = call float (float, float, float, ...) @llvm.ppc.maxfs(float %a, float %b, float %c, float %d) + ret float %0 +} + +declare ppc_fp128 @llvm.ppc.minfe(ppc_fp128 %a, ppc_fp128 %b, ppc_fp128 %c, ...) +define ppc_fp128 @test_minfe(ppc_fp128 %a, ppc_fp128 %b, ppc_fp128 %c, ppc_fp128 %d) { +; CHECK-LABEL: test_minfe: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: fcmpu 0, 6, 4 +; CHECK-NEXT: fcmpu 1, 5, 3 +; CHECK-NEXT: crand 20, 6, 0 +; CHECK-NEXT: cror 20, 4, 20 +; CHECK-NEXT: bc 12, 20, .LBB3_2 +; CHECK-NEXT: # %bb.1: # %entry +; CHECK-NEXT: fmr 6, 4 +; CHECK-NEXT: .LBB3_2: # %entry +; CHECK-NEXT: fcmpu 0, 6, 2 +; CHECK-NEXT: bc 12, 20, .LBB3_4 +; CHECK-NEXT: # %bb.3: # %entry +; CHECK-NEXT: fmr 5, 3 +; CHECK-NEXT: .LBB3_4: # %entry +; CHECK-NEXT: fcmpu 1, 5, 1 +; CHECK-NEXT: crand 20, 6, 0 +; CHECK-NEXT: cror 20, 4, 20 +; CHECK-NEXT: bc 12, 20, .LBB3_6 +; CHECK-NEXT: # %bb.5: # %entry +; CHECK-NEXT: fmr 6, 2 +; CHECK-NEXT: .LBB3_6: # %entry +; CHECK-NEXT: fcmpu 0, 6, 8 +; CHECK-NEXT: bc 12, 20, .LBB3_8 +; CHECK-NEXT: # %bb.7: # %entry +; CHECK-NEXT: fmr 5, 1 +; CHECK-NEXT: .LBB3_8: # %entry +; CHECK-NEXT: fcmpu 1, 5, 7 +; CHECK-NEXT: crand 20, 6, 0 +; CHECK-NEXT: cror 20, 4, 20 +; CHECK-NEXT: bc 12, 20, .LBB3_10 +; CHECK-NEXT: # %bb.9: # %entry +; CHECK-NEXT: fmr 5, 7 +; CHECK-NEXT: .LBB3_10: # %entry +; CHECK-NEXT: bc 12, 20, .LBB3_12 +; CHECK-NEXT: # %bb.11: # %entry +; CHECK-NEXT: fmr 6, 8 +; CHECK-NEXT: .LBB3_12: # %entry +; CHECK-NEXT: fmr 1, 5 +; CHECK-NEXT: fmr 2, 6 +; CHECK-NEXT: blr +entry: + %0 = call ppc_fp128 (ppc_fp128, ppc_fp128, ppc_fp128, ...) @llvm.ppc.minfe(ppc_fp128 %a, ppc_fp128 %b, ppc_fp128 %c, ppc_fp128 %d) + ret ppc_fp128 %0 +} + +declare double @llvm.ppc.minfl(double %a, double %b, double %c, ...) +define double @test_minfl(double %a, double %b, double %c, double %d) { +; CHECK-LABEL: test_minfl: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xsmincdp 0, 3, 2 +; CHECK-NEXT: xsmincdp 0, 0, 1 +; CHECK-NEXT: xsmincdp 1, 0, 4 +; CHECK-NEXT: blr +entry: + %0 = call double (double, double, double, ...) @llvm.ppc.minfl(double %a, double %b, double %c, double %d) + ret double %0 +} + +declare float @llvm.ppc.minfs(float %a, float %b, float %c, ...) +define float @test_minfs(float %a, float %b, float %c, float %d) { +; CHECK-LABEL: test_minfs: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xsmincdp 0, 3, 2 +; CHECK-NEXT: xsmincdp 0, 0, 1 +; CHECK-NEXT: xsmincdp 1, 0, 4 +; CHECK-NEXT: blr +entry: + %0 = call float (float, float, float, ...) @llvm.ppc.minfs(float %a, float %b, float %c, float %d) + ret float %0 +}