Index: flang/include/flang/Evaluate/target.h =================================================================== --- flang/include/flang/Evaluate/target.h +++ flang/include/flang/Evaluate/target.h @@ -40,6 +40,9 @@ bool isBigEndian() const { return isBigEndian_; } void set_isBigEndian(bool isBig = true); + bool isPPC() const { return isPPC_; } + void set_isPPC(bool isPPC = false); + bool areSubnormalsFlushedToZero() const { return areSubnormalsFlushedToZero_; } @@ -91,8 +94,8 @@ return *this; } - bool isPPC() const { return isPPC_; } - void set_isPPC(bool isPPC = false); + const std::string &cpu() const { return cpu_; }; + void set_cpu(std::string x) { cpu_ = x; } private: static constexpr int maxKind{32}; @@ -109,6 +112,7 @@ std::size_t maxAlignment_{8 /*at least*/}; std::string compilerOptionsString_; std::string compilerVersionString_; + std::string cpu_; }; } // namespace Fortran::evaluate Index: flang/include/flang/Semantics/expression.h =================================================================== --- flang/include/flang/Semantics/expression.h +++ flang/include/flang/Semantics/expression.h @@ -352,7 +352,6 @@ const parser::ProcComponentRef &, ActualArguments &&, bool isSubroutine); std::optional CheckCall( parser::CharBlock, const ProcedureDesignator &, ActualArguments &); - bool CheckPPCIntrinsic(const ProcedureDesignator &, ActualArguments &); using AdjustActuals = std::optional>; bool ResolveForward(const Symbol &); Index: flang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- flang/lib/Frontend/CompilerInvocation.cpp +++ flang/lib/Frontend/CompilerInvocation.cpp @@ -1137,6 +1137,8 @@ if (targetTriple.isPPC()) semanticsContext->targetCharacteristics().set_isPPC(true); + + semanticsContext->targetCharacteristics().set_cpu(this->targetOpts.cpu); } /// Set \p loweringOptions controlling lowering behavior based Index: flang/lib/Optimizer/Builder/PPCIntrinsicCall.cpp =================================================================== --- flang/lib/Optimizer/Builder/PPCIntrinsicCall.cpp +++ flang/lib/Optimizer/Builder/PPCIntrinsicCall.cpp @@ -214,6 +214,10 @@ genLibCall}, {"__ppc_frsqrtes", "llvm.ppc.frsqrtes", genFuncType, Ty::Real<4>>, genLibCall}, + {"__ppc_vec_cvbf16spn", "llvm.ppc.vsx.xvcvbf16spn", + genFuncType, Ty::UnsignedVector<1>>, genLibCall}, + {"__ppc_vec_cvspbf16_", "llvm.ppc.vsx.xvcvspbf16", + genFuncType, Ty::UnsignedVector<1>>, genLibCall}, {"__ppc_vec_madd", "llvm.fma.v4f32", genFuncType, Ty::RealVector<4>, Ty::RealVector<4>, Ty::RealVector<4>>, Index: flang/lib/Semantics/check-call.h =================================================================== --- flang/lib/Semantics/check-call.h +++ flang/lib/Semantics/check-call.h @@ -38,9 +38,14 @@ bool treatingExternalAsImplicit, const evaluate::SpecificIntrinsic *intrinsic); -bool CheckPPCIntrinsic(const Symbol &generic, const Symbol &specific, +void CheckPPCIntrinsic(const Symbol &specific, const evaluate::ActualArguments &actuals, evaluate::FoldingContext &context); +bool CheckPPCIntrinsicArgRng(const Symbol &specific, + const evaluate::ActualArguments &actuals, evaluate::FoldingContext &context, + parser::ContextualMessages &messages); +bool CheckPPCIntrinsicCPU(const Symbol &specific, + evaluate::FoldingContext &context, parser::ContextualMessages &messages); bool CheckArgumentIsConstantExprInRange( const evaluate::ActualArguments &actuals, int index, int lowerBound, int upperBound, parser::ContextualMessages &messages); Index: flang/lib/Semantics/check-call.cpp =================================================================== --- flang/lib/Semantics/check-call.cpp +++ flang/lib/Semantics/check-call.cpp @@ -1391,10 +1391,19 @@ return true; } -bool CheckPPCIntrinsic(const Symbol &generic, const Symbol &specific, +void CheckPPCIntrinsic(const Symbol &specific, const evaluate::ActualArguments &actuals, evaluate::FoldingContext &context) { parser::ContextualMessages &messages{context.messages()}; + CheckPPCIntrinsicArgRng(specific, actuals, context, messages); + CheckPPCIntrinsicCPU(specific, context, messages); +} + +bool CheckPPCIntrinsicArgRng(const Symbol &specific, + const evaluate::ActualArguments &actuals, evaluate::FoldingContext &context, + parser::ContextualMessages &messages) { + if (specific.name().ToString().rfind("__ppc_", 0) != 0) + return true; if (specific.name() == "__ppc_mtfsf") { return CheckArgumentIsConstantExprInRange(actuals, 0, 0, 7, messages); @@ -1415,6 +1424,22 @@ return false; } +bool CheckPPCIntrinsicCPU(const Symbol &specific, + evaluate::FoldingContext &context, parser::ContextualMessages &messages) { + if (specific.name().ToString().rfind("mma$mma$__ppc_mma_", 0) == 0 || + specific.name().ToString().rfind("__ppc_vec_cvspbf16", 0) == 0 || + specific.name().ToString().rfind("__ppc_vec_cvbf16spn", 0) == 0) { + + if (context.targetCharacteristics().cpu().compare(0, 5, "pwr10") != 0 && + context.targetCharacteristics().cpu().compare(0, 7, "power10") != 0) { + messages.Say( + "This PowerPC intrinsic is supported on POWER10 only"_err_en_US); + return false; + } + } + return true; +} + bool CheckArguments(const characteristics::Procedure &proc, evaluate::ActualArguments &actuals, SemanticsContext &context, const Scope &scope, bool treatingExternalAsImplicit, Index: flang/lib/Semantics/expression.cpp =================================================================== --- flang/lib/Semantics/expression.cpp +++ flang/lib/Semantics/expression.cpp @@ -2590,10 +2590,9 @@ resolution = pair.first; dueToAmbiguity = pair.second; if (resolution) { - if (context_.GetPPCBuiltinsScope() && - resolution->name().ToString().rfind("__ppc_", 0) == 0) { - semantics::CheckPPCIntrinsic( - *symbol, *resolution, arguments, GetFoldingContext()); + auto context{GetFoldingContext()}; + if (context.targetCharacteristics().isPPC()) { + semantics::CheckPPCIntrinsic(*resolution, arguments, context); } // re-resolve name to the specific procedure name.symbol = const_cast(resolution); Index: flang/module/__ppc_intrinsics.f90 =================================================================== --- flang/module/__ppc_intrinsics.f90 +++ flang/module/__ppc_intrinsics.f90 @@ -29,6 +29,12 @@ vector(integer(VKIND)), intent(in) :: arg1; \ end function ; +! vector(u) function f(vector(u)) +#define ELEM_FUNC_VUVU(VKIND) \ + vector(unsigned(VKIND)) function elem_func_vu##VKIND##vu##VKIND(arg1); \ + vector(unsigned(VKIND)), intent(in) :: arg1; \ + end function ; + ! vector(r) function f(vector(r)) #define ELEM_FUNC_VRVR_2(VKIND1, VKIND2) \ elemental vector(real(VKIND1)) function elem_func_vr##VKIND1##vr##VKIND2(arg1); \ @@ -37,11 +43,13 @@ #define ELEM_FUNC_VRVR(VKIND) ELEM_FUNC_VRVR_2(VKIND, VKIND) ELEM_FUNC_VIVI(1) ELEM_FUNC_VIVI(2) ELEM_FUNC_VIVI(4) ELEM_FUNC_VIVI(8) + ELEM_FUNC_VUVU(1) ELEM_FUNC_VRVR_2(4,8) ELEM_FUNC_VRVR_2(8,4) ELEM_FUNC_VRVR(4) ELEM_FUNC_VRVR(8) #undef ELEM_FUNC_VRVR #undef ELEM_FUNC_VRVR_2 +#undef ELEM_FUNC_VUVU #undef ELEM_FUNC_VIVI !! ================ 2 arguments function interface ================ @@ -427,11 +435,14 @@ ! vector function(vector) !------------------------- #define VI_VI(NAME, VKIND) __ppc_##NAME##_vi##VKIND##vi##VKIND +#define VU_VU(NAME, VKIND) __ppc_##NAME##_vu##VKIND##vu##VKIND #define VR_VR_2(NAME, VKIND1, VKIND2) __ppc_##NAME##_vr##VKIND1##vr##VKIND2 #define VR_VR(NAME, VKIND) VR_VR_2(NAME, VKIND, VKIND) #define VEC_VI_VI(NAME, VKIND) \ procedure(elem_func_vi##VKIND##vi##VKIND) :: VI_VI(NAME, VKIND); +#define VEC_VU_VU(NAME, VKIND) \ + procedure(elem_func_vu##VKIND##vu##VKIND) :: VU_VU(NAME, VKIND); #define VEC_VR_VR_2(NAME, VKIND1, VKIND2) \ procedure(elem_func_vr##VKIND1##vr##VKIND2) :: VR_VR_2(NAME, VKIND1, VKIND2); #define VEC_VR_VR(NAME, VKIND) VEC_VR_VR_2(NAME, VKIND, VKIND) @@ -452,11 +463,27 @@ end interface vec_cvf public :: vec_cvf +! vec_cvspbf16 + VEC_VU_VU(vec_cvspbf16_,1) + interface vec_cvspbf16 + procedure :: VU_VU(vec_cvspbf16_,1) + end interface + public vec_cvspbf16 + +! vec_cvbf16spn + VEC_VU_VU(vec_cvbf16spn,1) + interface vec_cvbf16spn + procedure :: VU_VU(vec_cvbf16spn,1) + end interface + public vec_cvbf16spn + #undef VEC_VR_VR #undef VEC_VR_VR_2 +#undef VEC_VU_VU #undef VEC_VI_VI #undef VR_VR #undef VR_VR_2 +#undef VU_VU #undef VI_VI !--------------------------------- Index: flang/test/Lower/PowerPC/ppc-pwr10-vec-intrinsics.f90 =================================================================== --- /dev/null +++ flang/test/Lower/PowerPC/ppc-pwr10-vec-intrinsics.f90 @@ -0,0 +1,27 @@ +! RUN: %flang --target=powerpc64le-unknown-linux-gnu -mcpu=pwr10 -emit-llvm -S %s -o - | FileCheck --check-prefixes="CHECK" %s +! REQUIRES: target=powerpc{{.*}} + subroutine test_cvspbf16() + implicit none + vector(unsigned(1)) :: v1, v2 + v1 = vec_cvspbf16(v2) + end subroutine test_cvspbf16 + +!CHECK-LABEL: @test_cvspbf16_ +!CHECK: %1 = alloca <16 x i8>, i64 1, align 16 +!CHECK: %2 = alloca <16 x i8>, i64 1, align 16 +!CHECK: %3 = load <16 x i8>, ptr %2, align 16 +!CHECK: %4 = call <16 x i8> @llvm.ppc.vsx.xvcvspbf16(<16 x i8> %3) +!CHECK: store <16 x i8> %4, ptr %1, align 16 + + subroutine test_cvbf16spn() + implicit none + vector(unsigned(1)) :: v1, v2 + v1 = vec_cvbf16spn(v2) + end subroutine test_cvbf16spn + +!CHECK-LABEL: @test_cvbf16spn_ +!CHECK: %1 = alloca <16 x i8>, i64 1, align 16 +!CHECK: %2 = alloca <16 x i8>, i64 1, align 16 +!CHECK: %3 = load <16 x i8>, ptr %2, align 16 +!CHECK: %4 = call <16 x i8> @llvm.ppc.vsx.xvcvbf16spn(<16 x i8> %3) +!CHECK: store <16 x i8> %4, ptr %1, align 16 Index: flang/test/Semantics/PowerPC/ppc-intrinsic-cpu-check.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/PowerPC/ppc-intrinsic-cpu-check.f90 @@ -0,0 +1,20 @@ +! RUN: %S/../test_errors.py %s %flang -mcpu=pwr9 +! REQUIRES: target=powerpc{{.*}} + +! vec_cvspbf16 +subroutine test_vec_cvspbf16 + implicit none + vector(unsigned(1)) :: v1, v2 + +!ERROR: This PowerPC intrinsic is supported on POWER10 only + v1 = vec_cvspbf16(v2) +end subroutine + +! vec_cvbf16spn +subroutine test_vec_cvbf16spn + implicit none + vector(unsigned(1)) :: v1, v2 + +!ERROR: This PowerPC intrinsic is supported on POWER10 only + v1 = vec_cvbf16spn(v2) +end subroutine