llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Joshua Batista (bob80905) <details> <summary>Changes</summary> RFC: https://discourse.llvm.org/t/rfc-elementwise-attribute-in-clang-front-end/76342/9 The above RFC gives the motivation for this PR. In summary, this PR adds an attribute that will simplify / obliviate the need to create separate elementwise builtins for pre-existing builtins. It will also allow users to create their own user-defined functions, and create elementwise variants of their functions. This should help accelerate the process of using tan in an elementwise way. --- Patch is 33.72 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/86175.diff 7 Files Affected: - (modified) clang/include/clang/Basic/Attr.td (+9) - (modified) clang/include/clang/Basic/AttrDocs.td (+22) - (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+2-1) - (modified) clang/lib/AST/Decl.cpp (+2) - (modified) clang/lib/Headers/hlsl/hlsl_intrinsics.h (+3-1) - (modified) clang/lib/Sema/SemaChecking.cpp (+334-298) - (modified) clang/lib/Sema/SemaDeclAttr.cpp (+32) ``````````diff diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index fd7970d0451acd..160e8ef730ef92 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -759,6 +759,15 @@ def BuiltinAlias : Attr { let Documentation = [BuiltinAliasDocs]; } +def ElementwiseBuiltinAlias : Attr { + let Spellings = [CXX11<"clang", "elementwise_builtin_alias">, + C23<"clang", "elementwise_builtin_alias">, + GNU<"clang_elementwise_builtin_alias">]; + let Args = [IdentifierArgument<"BuiltinName">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [ElementwiseBuiltinAliasDocs]; +} + def ArmBuiltinAlias : InheritableAttr, TargetSpecificAttr<TargetAnyArm> { let Spellings = [Clang<"__clang_arm_builtin_alias">]; let Args = [IdentifierArgument<"BuiltinName">]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 2c07cd09b0d5b7..7ce83bc881f064 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -5462,6 +5462,28 @@ for clang builtin functions. }]; } +def ElementwiseBuiltinAliasDocs : Documentation { + let Category = DocCatFunction; + let Heading = "clang::elementwise_builtin_alias, clang_elementwise_builtin_alias"; + let Content = [{ +This attribute is used in the implementation of the C intrinsics. +It allows the C intrinsic functions to be declared using the names defined +in target builtins, and still be recognized as clang builtins equivalent to the +underlying name. It also declares that the given C intrinsic can accept +vector arguments. For example, ``hlsl_intrinsics.h`` declares the function ``abs`` +with ``__attribute__((clang_elementwise_builtin_alias(__builtin_abs)))``. +This ensures that both functions are recognized as that clang builtin, +and in the latter case, the choice of which builtin to identify the +function as can be deferred until after overload resolution. It also enables +the ``abs`` function to take vector arguments. + +This attribute can only be used to set up the aliases for certain ARM/RISC-V +C intrinsic functions; it is intended for use only inside ``arm_*.h`` and +``riscv_*.h`` and is not a general mechanism for declaring arbitrary aliases +for clang builtin functions. + }]; +} + def PreferredNameDocs : Documentation { let Category = DocCatDecl; let Content = [{ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index c54105507753eb..1252d3804131a6 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -4412,7 +4412,8 @@ def err_attribute_preferred_name_arg_invalid : Error< "a specialization of %1">; def err_attribute_builtin_alias : Error< "%0 attribute can only be applied to a ARM, HLSL or RISC-V builtin">; - +def err_attribute_elementwise_builtin_alias : Error< + "%0 attribute can only be applied to a ARM, HLSL or RISC-V builtin">; // called-once attribute diagnostics. def err_called_once_attribute_wrong_type : Error< "'called_once' attribute only applies to function-like parameters">; diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 8626f04012f7d4..cb2c5cf6ceaf49 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -3598,6 +3598,8 @@ unsigned FunctionDecl::getBuiltinID(bool ConsiderWrapperFunctions) const { BuiltinID = ABAA->getBuiltinName()->getBuiltinID(); } else if (const auto *BAA = getAttr<BuiltinAliasAttr>()) { BuiltinID = BAA->getBuiltinName()->getBuiltinID(); + } else if (const auto *EBAA = getAttr<ElementwiseBuiltinAliasAttr>()) { + BuiltinID = EBAA->getBuiltinName()->getBuiltinID(); } else if (const auto *A = getAttr<BuiltinAttr>()) { BuiltinID = A->getID(); } diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 45f8544392584e..1c8e4073026091 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -18,6 +18,8 @@ namespace hlsl { #define _HLSL_BUILTIN_ALIAS(builtin) \ __attribute__((clang_builtin_alias(builtin))) +#define _HLSL_ELEMENTWISE_BUILTIN_ALIAS(builtin) \ + __attribute__((clang_elementwise_builtin_alias(builtin))) #define _HLSL_AVAILABILITY(environment, version) \ __attribute__((availability(environment, introduced = version))) @@ -249,7 +251,7 @@ _HLSL_BUILTIN_ALIAS(__builtin_elementwise_ceil) double2 ceil(double2); _HLSL_BUILTIN_ALIAS(__builtin_elementwise_ceil) double3 ceil(double3); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_ceil) +_HLSL_ELEMENTWISE_BUILTIN_ALIAS(__builtin_ceil) double4 ceil(double4); //===----------------------------------------------------------------------===// diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index a5f42b630c3fa2..c2621bdd2f9ce9 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2240,317 +2240,353 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, ICEArguments &= ~(1 << ArgNo); } - FPOptions FPO; - switch (BuiltinID) { - case Builtin::BI__builtin_cpu_supports: - case Builtin::BI__builtin_cpu_is: - if (SemaBuiltinCpu(*this, Context.getTargetInfo(), TheCall, - Context.getAuxTargetInfo(), BuiltinID)) - return ExprError(); - break; - case Builtin::BI__builtin_cpu_init: - if (!Context.getTargetInfo().supportsCpuInit()) { - Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported) - << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc()); - return ExprError(); + // if the call has the elementwise attribute, then + // make sure that an elementwise expr is emitted. + if (FDecl->hasAttr<ElementwiseBuiltinAliasAttr>()) { + switch (FDecl->getNumParams()) { + case 1: { + if (PrepareBuiltinElementwiseMathOneArgCall(TheCall)) + return ExprError(); + + QualType ArgTy = TheCall->getArg(0)->getType(); + if (checkFPMathBuiltinElementType( + *this, TheCall->getArg(0)->getBeginLoc(), ArgTy, 1)) + return ExprError(); + break; } - break; - case Builtin::BI__builtin___CFStringMakeConstantString: - // CFStringMakeConstantString is currently not implemented for GOFF (i.e., - // on z/OS) and for XCOFF (i.e., on AIX). Emit unsupported - if (CheckBuiltinTargetNotInUnsupported( - *this, BuiltinID, TheCall, - {llvm::Triple::GOFF, llvm::Triple::XCOFF})) - return ExprError(); - assert(TheCall->getNumArgs() == 1 && - "Wrong # arguments to builtin CFStringMakeConstantString"); - if (CheckObjCString(TheCall->getArg(0))) - return ExprError(); - break; - case Builtin::BI__builtin_ms_va_start: - case Builtin::BI__builtin_stdarg_start: - case Builtin::BI__builtin_va_start: - if (SemaBuiltinVAStart(BuiltinID, TheCall)) - return ExprError(); - break; - case Builtin::BI__va_start: { - switch (Context.getTargetInfo().getTriple().getArch()) { - case llvm::Triple::aarch64: - case llvm::Triple::arm: - case llvm::Triple::thumb: - if (SemaBuiltinVAStartARMMicrosoft(TheCall)) + case 2: { + if (SemaBuiltinElementwiseMath(TheCall)) + return ExprError(); + + QualType ArgTy = TheCall->getArg(0)->getType(); + if (checkFPMathBuiltinElementType( + *this, TheCall->getArg(0)->getBeginLoc(), ArgTy, 1) || + checkFPMathBuiltinElementType( + *this, TheCall->getArg(1)->getBeginLoc(), ArgTy, 2)) return ExprError(); break; - default: - if (SemaBuiltinVAStart(BuiltinID, TheCall)) + } + case 3: { + if (SemaBuiltinElementwiseTernaryMath(TheCall)) return ExprError(); break; } - break; + } } + FPOptions FPO; + switch (BuiltinID) { + case Builtin::BI__builtin_cpu_supports: + case Builtin::BI__builtin_cpu_is: + if (SemaBuiltinCpu(*this, Context.getTargetInfo(), TheCall, + Context.getAuxTargetInfo(), BuiltinID)) + return ExprError(); + break; + case Builtin::BI__builtin_cpu_init: + if (!Context.getTargetInfo().supportsCpuInit()) { + Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported) + << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc()); + return ExprError(); + } + break; + case Builtin::BI__builtin___CFStringMakeConstantString: + // CFStringMakeConstantString is currently not implemented for GOFF (i.e., + // on z/OS) and for XCOFF (i.e., on AIX). Emit unsupported + if (CheckBuiltinTargetNotInUnsupported( + *this, BuiltinID, TheCall, + {llvm::Triple::GOFF, llvm::Triple::XCOFF})) + return ExprError(); + assert(TheCall->getNumArgs() == 1 && + "Wrong # arguments to builtin CFStringMakeConstantString"); + if (CheckObjCString(TheCall->getArg(0))) + return ExprError(); + break; + case Builtin::BI__builtin_ms_va_start: + case Builtin::BI__builtin_stdarg_start: + case Builtin::BI__builtin_va_start: + if (SemaBuiltinVAStart(BuiltinID, TheCall)) + return ExprError(); + break; + case Builtin::BI__va_start: { + switch (Context.getTargetInfo().getTriple().getArch()) { + case llvm::Triple::aarch64: + case llvm::Triple::arm: + case llvm::Triple::thumb: + if (SemaBuiltinVAStartARMMicrosoft(TheCall)) + return ExprError(); + break; + default: + if (SemaBuiltinVAStart(BuiltinID, TheCall)) + return ExprError(); + break; + } + break; + } - // The acquire, release, and no fence variants are ARM and AArch64 only. - case Builtin::BI_interlockedbittestandset_acq: - case Builtin::BI_interlockedbittestandset_rel: - case Builtin::BI_interlockedbittestandset_nf: - case Builtin::BI_interlockedbittestandreset_acq: - case Builtin::BI_interlockedbittestandreset_rel: - case Builtin::BI_interlockedbittestandreset_nf: - if (CheckBuiltinTargetInSupported( - *this, BuiltinID, TheCall, - {llvm::Triple::arm, llvm::Triple::thumb, llvm::Triple::aarch64})) - return ExprError(); - break; + // The acquire, release, and no fence variants are ARM and AArch64 only. + case Builtin::BI_interlockedbittestandset_acq: + case Builtin::BI_interlockedbittestandset_rel: + case Builtin::BI_interlockedbittestandset_nf: + case Builtin::BI_interlockedbittestandreset_acq: + case Builtin::BI_interlockedbittestandreset_rel: + case Builtin::BI_interlockedbittestandreset_nf: + if (CheckBuiltinTargetInSupported( + *this, BuiltinID, TheCall, + {llvm::Triple::arm, llvm::Triple::thumb, llvm::Triple::aarch64})) + return ExprError(); + break; - // The 64-bit bittest variants are x64, ARM, and AArch64 only. - case Builtin::BI_bittest64: - case Builtin::BI_bittestandcomplement64: - case Builtin::BI_bittestandreset64: - case Builtin::BI_bittestandset64: - case Builtin::BI_interlockedbittestandreset64: - case Builtin::BI_interlockedbittestandset64: - if (CheckBuiltinTargetInSupported(*this, BuiltinID, TheCall, - {llvm::Triple::x86_64, llvm::Triple::arm, - llvm::Triple::thumb, - llvm::Triple::aarch64})) - return ExprError(); - break; + // The 64-bit bittest variants are x64, ARM, and AArch64 only. + case Builtin::BI_bittest64: + case Builtin::BI_bittestandcomplement64: + case Builtin::BI_bittestandreset64: + case Builtin::BI_bittestandset64: + case Builtin::BI_interlockedbittestandreset64: + case Builtin::BI_interlockedbittestandset64: + if (CheckBuiltinTargetInSupported(*this, BuiltinID, TheCall, + {llvm::Triple::x86_64, + llvm::Triple::arm, llvm::Triple::thumb, + llvm::Triple::aarch64})) + return ExprError(); + break; - case Builtin::BI__builtin_set_flt_rounds: - if (CheckBuiltinTargetInSupported(*this, BuiltinID, TheCall, - {llvm::Triple::x86, llvm::Triple::x86_64, - llvm::Triple::arm, llvm::Triple::thumb, - llvm::Triple::aarch64})) - return ExprError(); - break; + case Builtin::BI__builtin_set_flt_rounds: + if (CheckBuiltinTargetInSupported( + *this, BuiltinID, TheCall, + {llvm::Triple::x86, llvm::Triple::x86_64, llvm::Triple::arm, + llvm::Triple::thumb, llvm::Triple::aarch64})) + return ExprError(); + break; - case Builtin::BI__builtin_isgreater: - case Builtin::BI__builtin_isgreaterequal: - case Builtin::BI__builtin_isless: - case Builtin::BI__builtin_islessequal: - case Builtin::BI__builtin_islessgreater: - case Builtin::BI__builtin_isunordered: - if (SemaBuiltinUnorderedCompare(TheCall, BuiltinID)) - return ExprError(); - break; - case Builtin::BI__builtin_fpclassify: - if (SemaBuiltinFPClassification(TheCall, 6, BuiltinID)) - return ExprError(); - break; - case Builtin::BI__builtin_isfpclass: - if (SemaBuiltinFPClassification(TheCall, 2, BuiltinID)) - return ExprError(); - break; - case Builtin::BI__builtin_isfinite: - case Builtin::BI__builtin_isinf: - case Builtin::BI__builtin_isinf_sign: - case Builtin::BI__builtin_isnan: - case Builtin::BI__builtin_issignaling: - case Builtin::BI__builtin_isnormal: - case Builtin::BI__builtin_issubnormal: - case Builtin::BI__builtin_iszero: - case Builtin::BI__builtin_signbit: - case Builtin::BI__builtin_signbitf: - case Builtin::BI__builtin_signbitl: - if (SemaBuiltinFPClassification(TheCall, 1, BuiltinID)) - return ExprError(); - break; - case Builtin::BI__builtin_shufflevector: - return SemaBuiltinShuffleVector(TheCall); - // TheCall will be freed by the smart pointer here, but that's fine, since - // SemaBuiltinShuffleVector guts it, but then doesn't release it. - case Builtin::BI__builtin_prefetch: - if (SemaBuiltinPrefetch(TheCall)) - return ExprError(); - break; - case Builtin::BI__builtin_alloca_with_align: - case Builtin::BI__builtin_alloca_with_align_uninitialized: - if (SemaBuiltinAllocaWithAlign(TheCall)) - return ExprError(); - [[fallthrough]]; - case Builtin::BI__builtin_alloca: - case Builtin::BI__builtin_alloca_uninitialized: - Diag(TheCall->getBeginLoc(), diag::warn_alloca) - << TheCall->getDirectCallee(); - break; - case Builtin::BI__arithmetic_fence: - if (SemaBuiltinArithmeticFence(TheCall)) - return ExprError(); - break; - case Builtin::BI__assume: - case Builtin::BI__builtin_assume: - if (SemaBuiltinAssume(TheCall)) - return ExprError(); - break; - case Builtin::BI__builtin_assume_aligned: - if (SemaBuiltinAssumeAligned(TheCall)) - return ExprError(); - break; - case Builtin::BI__builtin_dynamic_object_size: - case Builtin::BI__builtin_object_size: - if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 3)) - return ExprError(); - break; - case Builtin::BI__builtin_longjmp: - if (SemaBuiltinLongjmp(TheCall)) - return ExprError(); - break; - case Builtin::BI__builtin_setjmp: - if (SemaBuiltinSetjmp(TheCall)) - return ExprError(); - break; - case Builtin::BI__builtin_classify_type: - if (checkArgCount(*this, TheCall, 1)) return true; - TheCall->setType(Context.IntTy); - break; - case Builtin::BI__builtin_complex: - if (SemaBuiltinComplex(TheCall)) - return ExprError(); - break; - case Builtin::BI__builtin_constant_p: { - if (checkArgCount(*this, TheCall, 1)) return true; - ExprResult Arg = DefaultFunctionArrayLvalueConversion(TheCall->getArg(0)); - if (Arg.isInvalid()) return true; - TheCall->setArg(0, Arg.get()); - TheCall->setType(Context.IntTy); - break; - } - case Builtin::BI__builtin_launder: - return SemaBuiltinLaunder(*this, TheCall); - case Builtin::BI__sync_fetch_and_add: - case Builtin::BI__sync_fetch_and_add_1: - case Builtin::BI__sync_fetch_and_add_2: - case Builtin::BI__sync_fetch_and_add_4: - case Builtin::BI__sync_fetch_and_add_8: - case Builtin::BI__sync_fetch_and_add_16: - case Builtin::BI__sync_fetch_and_sub: - case Builtin::BI__sync_fetch_and_sub_1: - case Builtin::BI__sync_fetch_and_sub_2: - case Builtin::BI__sync_fetch_and_sub_4: - case Builtin::BI__sync_fetch_and_sub_8: - case Builtin::BI__sync_fetch_and_sub_16: - case Builtin::BI__sync_fetch_and_or: - case Builtin::BI__sync_fetch_and_or_1: - case Builtin::BI__sync_fetch_and_or_2: - case Builtin::BI__sync_fetch_and_or_4: - case Builtin::BI__sync_fetch_and_or_8: - case Builtin::BI__sync_fetch_and_or_16: - case Builtin::BI__sync_fetch_and_and: - case Builtin::BI__sync_fetch_and_and_1: - case Builtin::BI__sync_fetch_and_and_2: - case Builtin::BI__sync_fetch_and_and_4: - case Builtin::BI__sync_fetch_and_and_8: - case Builtin::BI__sync_fetch_and_and_16: - case Builtin::BI__sync_fetch_and_xor: - case Builtin::BI__sync_fetch_and_xor_1: - case Builtin::BI__sync_fetch_and_xor_2: - case Builtin::BI__sync_fetch_and_xor_4: - case Builtin::BI__sync_fetch_and_xor_8: - case Builtin::BI__sync_fetch_and_xor_16: - case Builtin::BI__sync_fetch_and_nand: - case Builtin::BI__sync_fetch_and_nand_1: - case Builtin::BI__sync_fetch_and_nand_2: - case Builtin::BI__sync_fetch_and_nand_4: - case Builtin::BI__sync_fetch_and_nand_8: - case Builtin::BI__sync_fetch_and_nand_16: - case Builtin::BI__sync_add_and_fetch: - case Builtin::BI__sync_add_and_fetch_1: - case Builtin::BI__sync_add_and_fetch_2: - case Builtin::BI__sync_add_and_fetch_4: - case Builtin::BI__sync_add_and_fetch_8: - case Builtin::BI__sync_add_and_fetch_16: - case Builtin::BI__sync_sub_and_fetch: - case Builtin::BI__sync_sub_and_fetch_1: - case Builtin::BI__sync_sub_and_fetch_2: - case Builtin::BI__sync_sub_and_fetch_4: - case Builtin::BI__sync_sub_and_fetch_8: - case Builtin::BI__sync_sub_and_fetch_16: - case Builtin::BI__sync_and_and_fetch: - case Builtin::BI__sync_and_and_fetch_1: - case Builtin::BI__sync_and_and_fetch_2: - case Builtin::BI__sync_and_and_fetch_4: - case Builtin::BI__sync_and_and_fetch_8: - case Builtin::BI__sync_and_and_fetch_16: - case Builtin::BI__sync_or_and_fetch: - case Builtin::BI__sync_or_and_fetch_1: - case Builtin::BI__sync_or_and_fetch_2: - case Builtin::BI__sync_or_and_fetch_4: - case Builtin::BI__sync_or_and_fetch_8: - case Builtin::BI__sync_or_and_fetch_16: - case Builtin::BI__sync_xor_and_fetch: - case Builtin::BI__sync_xor_and_fetch_1: - case Builtin::BI__sync_xor_and_fetch_2: - case Builtin::BI__sync_xor_and_fetch_4: - case Builtin::BI__sync_xor_and_fetch_8: - case Builtin::BI__sync_xor_and_fetch_16: - case Builtin::BI__sync_nand_and_fetch: - case Builtin::BI__sync_nand_and_fetch_1: - case Builtin::BI__sync_nand_and_fetch_2: - case Builtin::BI__sync_nand_and_fetch_4: - case Builtin::BI__sync_nand_and_fetch_8: - case Builtin::BI__sync_nand_and_fetch_16: - case Builtin::BI__sync_val_compare_and_swap: - case Builtin::BI__sync_val_compare_and_swap_1: - case Builtin::BI__sync_val_compare_and_swap_2: - case Builtin::BI__sync_val_compare_and_swap_4: - case Builtin::BI__sync_val_compare_and_swap_8: - case Builtin::BI__sync_val_compare_and_swap_16: - case Builtin::BI__sync_bool_compare_and_swap: - case Builtin::BI__sync_bool_compare_and_swap_1: - case Builtin::BI__sync_bool_compare_and_swap_2: - case Builtin::BI__sync_bool_compare_and_swap_4: - case Builtin::BI__sync_bool_compare_and_swap_8: - case Builtin::BI__sync_bool_compare_and_swap_16: - case Builtin::BI__sync_lock_test_and_set: - case Builtin::BI__sync_lock_test_and_set_1: - case Builtin::BI__sync_lock_test_and_set_2: - case Builtin::BI__sync_lock_test_and_set_4: - case Builtin::BI__sync_lock_test_and_set_8: - case Builtin::BI__sync_lock_test_and_set_16: - case Builtin::BI__sync_lock_release: - case Builti... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/86175 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits