[clang] [Clang] Add __has_target_builtin macro (PR #126324)
Nick Sarnie via cfe-commits
cfe-commits at lists.llvm.org
Fri Feb 7 15:31:33 PST 2025
https://github.com/sarnex updated https://github.com/llvm/llvm-project/pull/126324
>From fe555ce59762edf71f43d0cd61978d60f5f949ef Mon Sep 17 00:00:00 2001
From: "Sarnie, Nick" <nick.sarnie at intel.com>
Date: Fri, 7 Feb 2025 14:57:12 -0800
Subject: [PATCH 1/3] [Clang] Add __has_target_builtin macro
Signed-off-by: Sarnie, Nick <nick.sarnie at intel.com>
---
clang/docs/LanguageExtensions.rst | 33 +++++++++++++++++++
clang/include/clang/Lex/Preprocessor.h | 1 +
clang/lib/Lex/PPMacroExpansion.cpp | 17 +++++++---
.../test/Preprocessor/has_target_builtin.cpp | 18 ++++++++++
4 files changed, 64 insertions(+), 5 deletions(-)
create mode 100644 clang/test/Preprocessor/has_target_builtin.cpp
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 973cf8f9d091c30..87f7df50471e790 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -67,6 +67,10 @@ It can be used like this:
``__has_builtin`` should not be used to detect support for a builtin macro;
use ``#ifdef`` instead.
+ When using device offloading, a builtin is considered available if it is
+ available on either the host or the device targets.
+ Use ``__has_target_builtin`` to consider only the current target.
+
``__has_constexpr_builtin``
---------------------------
@@ -96,6 +100,35 @@ the ``<cmath>`` header file to conditionally make a function constexpr whenever
the constant evaluation of the corresponding builtin (for example,
``std::fmax`` calls ``__builtin_fmax``) is supported in Clang.
+``__has_target_builtin``
+-----------------
+
+This function-like macro takes a single identifier argument that is the name of
+a builtin function, a builtin pseudo-function (taking one or more type
+arguments), or a builtin template.
+It evaluates to 1 if the builtin is supported on the current target or 0 if not.
+The behavior is different than ``__has_builtin`` when there is an auxiliary target,
+such when offloading to a target device.
+It can be used like this:
+
+.. code-block:: c++
+
+ #ifndef __has_target_builtin // Optional of course.
+ #define __has_target_builtin(x) 0 // Compatibility with non-clang compilers.
+ #endif
+
+ ...
+ #if __has_target_builtin(__builtin_trap)
+ __builtin_trap();
+ #else
+ abort();
+ #endif
+ ...
+
+.. note::
+ ``__has_target_builtin`` should not be used to detect support for a builtin macro;
+ use ``#ifdef`` instead.
+
.. _langext-__has_feature-__has_extension:
``__has_feature`` and ``__has_extension``
diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
index 2bf4d1a16699430..240fe28aba93e33 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -174,6 +174,7 @@ class Preprocessor {
IdentifierInfo *Ident__has_extension; // __has_extension
IdentifierInfo *Ident__has_builtin; // __has_builtin
IdentifierInfo *Ident__has_constexpr_builtin; // __has_constexpr_builtin
+ IdentifierInfo *Ident__has_target_builtin; // __has_target_builtin
IdentifierInfo *Ident__has_attribute; // __has_attribute
IdentifierInfo *Ident__has_embed; // __has_embed
IdentifierInfo *Ident__has_include; // __has_include
diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp
index 347c13da0ad215a..b7b870e1a7fca82 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -357,6 +357,7 @@ void Preprocessor::RegisterBuiltinMacros() {
Ident__has_builtin = RegisterBuiltinMacro("__has_builtin");
Ident__has_constexpr_builtin =
RegisterBuiltinMacro("__has_constexpr_builtin");
+ Ident__has_target_builtin = RegisterBuiltinMacro("__has_target_builtin");
Ident__has_attribute = RegisterBuiltinMacro("__has_attribute");
if (!getLangOpts().CPlusPlus)
Ident__has_c_attribute = RegisterBuiltinMacro("__has_c_attribute");
@@ -1797,15 +1798,17 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
diag::err_feature_check_malformed);
return II && HasExtension(*this, II->getName());
});
- } else if (II == Ident__has_builtin) {
+ } else if (II == Ident__has_builtin || II == Ident__has_target_builtin) {
+ bool IsHasTargetBuiltin = II == Ident__has_target_builtin;
EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, false,
- [this](Token &Tok, bool &HasLexedNextToken) -> int {
+ [this, IsHasTargetBuiltin](Token &Tok, bool &HasLexedNextToken) -> int {
IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this,
diag::err_feature_check_malformed);
if (!II)
return false;
- else if (II->getBuiltinID() != 0) {
- switch (II->getBuiltinID()) {
+ auto BuiltinID = II->getBuiltinID();
+ if (BuiltinID != 0) {
+ switch (BuiltinID) {
case Builtin::BI__builtin_cpu_is:
return getTargetInfo().supportsCpuIs();
case Builtin::BI__builtin_cpu_init:
@@ -1818,8 +1821,12 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
// usual allocation and deallocation functions. Required by libc++
return 201802;
default:
+ // __has_target_builtin should return false for aux builtins.
+ if(IsHasTargetBuiltin &&
+ getBuiltinInfo().isAuxBuiltinID(BuiltinID))
+ return false;
return Builtin::evaluateRequiredTargetFeatures(
- getBuiltinInfo().getRequiredFeatures(II->getBuiltinID()),
+ getBuiltinInfo().getRequiredFeatures(BuiltinID),
getTargetInfo().getTargetOpts().FeatureMap);
}
return true;
diff --git a/clang/test/Preprocessor/has_target_builtin.cpp b/clang/test/Preprocessor/has_target_builtin.cpp
new file mode 100644
index 000000000000000..64b2d7e1b35d9ef
--- /dev/null
+++ b/clang/test/Preprocessor/has_target_builtin.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fopenmp -triple=spirv64 -fopenmp-is-target-device \
+// RUN: -aux-triple x86_64-linux-unknown -E %s | FileCheck -implicit-check-not=BAD %s
+
+// RUN: %clang_cc1 -fopenmp -triple=nvptx64 -fopenmp-is-target-device \
+// RUN: -aux-triple x86_64-linux-unknown -E %s | FileCheck -implicit-check-not=BAD %s
+
+// RUN: %clang_cc1 -fopenmp -triple=amdgcn-amd-amdhsa -fopenmp-is-target-device \
+// RUN: -aux-triple x86_64-linux-unknown -E %s | FileCheck -implicit-check-not=BAD %s
+
+// RUN: %clang_cc1 -fopenmp -triple=aarch64 -fopenmp-is-target-device \
+// RUN: -aux-triple x86_64-linux-unknown -E %s | FileCheck -implicit-check-not=BAD %s
+
+// CHECK: GOOD
+#if __has_target_builtin(__builtin_ia32_pause)
+ BAD
+#else
+ GOOD
+#endif
>From 0ca0587da63979205db6f0957811d3c17dba647d Mon Sep 17 00:00:00 2001
From: "Sarnie, Nick" <nick.sarnie at intel.com>
Date: Fri, 7 Feb 2025 15:20:14 -0800
Subject: [PATCH 2/3] clang-format
Signed-off-by: Sarnie, Nick <nick.sarnie at intel.com>
---
clang/lib/Lex/PPMacroExpansion.cpp | 109 ++++++++++++++---------------
1 file changed, 54 insertions(+), 55 deletions(-)
diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp
index b7b870e1a7fca82..23a693b105fca3a 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -1800,59 +1800,60 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
});
} else if (II == Ident__has_builtin || II == Ident__has_target_builtin) {
bool IsHasTargetBuiltin = II == Ident__has_target_builtin;
- EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, false,
- [this, IsHasTargetBuiltin](Token &Tok, bool &HasLexedNextToken) -> int {
- IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this,
- diag::err_feature_check_malformed);
- if (!II)
- return false;
- auto BuiltinID = II->getBuiltinID();
- if (BuiltinID != 0) {
- switch (BuiltinID) {
- case Builtin::BI__builtin_cpu_is:
- return getTargetInfo().supportsCpuIs();
- case Builtin::BI__builtin_cpu_init:
- return getTargetInfo().supportsCpuInit();
- case Builtin::BI__builtin_cpu_supports:
- return getTargetInfo().supportsCpuSupports();
- case Builtin::BI__builtin_operator_new:
- case Builtin::BI__builtin_operator_delete:
- // denotes date of behavior change to support calling arbitrary
- // usual allocation and deallocation functions. Required by libc++
- return 201802;
- default:
- // __has_target_builtin should return false for aux builtins.
- if(IsHasTargetBuiltin &&
- getBuiltinInfo().isAuxBuiltinID(BuiltinID))
+ EvaluateFeatureLikeBuiltinMacro(
+ OS, Tok, II, *this, false,
+ [this, IsHasTargetBuiltin](Token &Tok, bool &HasLexedNextToken) -> int {
+ IdentifierInfo *II = ExpectFeatureIdentifierInfo(
+ Tok, *this, diag::err_feature_check_malformed);
+ if (!II)
+ return false;
+ auto BuiltinID = II->getBuiltinID();
+ if (BuiltinID != 0) {
+ switch (BuiltinID) {
+ case Builtin::BI__builtin_cpu_is:
+ return getTargetInfo().supportsCpuIs();
+ case Builtin::BI__builtin_cpu_init:
+ return getTargetInfo().supportsCpuInit();
+ case Builtin::BI__builtin_cpu_supports:
+ return getTargetInfo().supportsCpuSupports();
+ case Builtin::BI__builtin_operator_new:
+ case Builtin::BI__builtin_operator_delete:
+ // denotes date of behavior change to support calling arbitrary
+ // usual allocation and deallocation functions. Required by libc++
+ return 201802;
+ default:
+ // __has_target_builtin should return false for aux builtins.
+ if (IsHasTargetBuiltin &&
+ getBuiltinInfo().isAuxBuiltinID(BuiltinID))
return false;
- return Builtin::evaluateRequiredTargetFeatures(
- getBuiltinInfo().getRequiredFeatures(BuiltinID),
- getTargetInfo().getTargetOpts().FeatureMap);
+ return Builtin::evaluateRequiredTargetFeatures(
+ getBuiltinInfo().getRequiredFeatures(BuiltinID),
+ getTargetInfo().getTargetOpts().FeatureMap);
+ }
+ return true;
+ } else if (IsBuiltinTrait(Tok)) {
+ return true;
+ } else if (II->getTokenID() != tok::identifier &&
+ II->getName().starts_with("__builtin_")) {
+ return true;
+ } else {
+ return llvm::StringSwitch<bool>(II->getName())
+ // Report builtin templates as being builtins.
+ .Case("__make_integer_seq", getLangOpts().CPlusPlus)
+ .Case("__type_pack_element", getLangOpts().CPlusPlus)
+ .Case("__builtin_common_type", getLangOpts().CPlusPlus)
+ // Likewise for some builtin preprocessor macros.
+ // FIXME: This is inconsistent; we usually suggest detecting
+ // builtin macros via #ifdef. Don't add more cases here.
+ .Case("__is_target_arch", true)
+ .Case("__is_target_vendor", true)
+ .Case("__is_target_os", true)
+ .Case("__is_target_environment", true)
+ .Case("__is_target_variant_os", true)
+ .Case("__is_target_variant_environment", true)
+ .Default(false);
}
- return true;
- } else if (IsBuiltinTrait(Tok)) {
- return true;
- } else if (II->getTokenID() != tok::identifier &&
- II->getName().starts_with("__builtin_")) {
- return true;
- } else {
- return llvm::StringSwitch<bool>(II->getName())
- // Report builtin templates as being builtins.
- .Case("__make_integer_seq", getLangOpts().CPlusPlus)
- .Case("__type_pack_element", getLangOpts().CPlusPlus)
- .Case("__builtin_common_type", getLangOpts().CPlusPlus)
- // Likewise for some builtin preprocessor macros.
- // FIXME: This is inconsistent; we usually suggest detecting
- // builtin macros via #ifdef. Don't add more cases here.
- .Case("__is_target_arch", true)
- .Case("__is_target_vendor", true)
- .Case("__is_target_os", true)
- .Case("__is_target_environment", true)
- .Case("__is_target_variant_os", true)
- .Case("__is_target_variant_environment", true)
- .Default(false);
- }
- });
+ });
} else if (II == Ident__has_constexpr_builtin) {
EvaluateFeatureLikeBuiltinMacro(
OS, Tok, II, *this, false,
@@ -1893,8 +1894,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
return false;
});
- } else if (II == Ident__has_cpp_attribute ||
- II == Ident__has_c_attribute) {
+ } else if (II == Ident__has_cpp_attribute || II == Ident__has_c_attribute) {
bool IsCXX = II == Ident__has_cpp_attribute;
EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, true,
[&](Token &Tok, bool &HasLexedNextToken) -> int {
@@ -1924,8 +1924,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
getLangOpts())
: 0;
});
- } else if (II == Ident__has_include ||
- II == Ident__has_include_next) {
+ } else if (II == Ident__has_include || II == Ident__has_include_next) {
// The argument to these two builtins should be a parenthesized
// file name string literal using angle brackets (<>) or
// double-quotes ("").
>From e44e8064d7213e253026fe0bee0cd549d620efb8 Mon Sep 17 00:00:00 2001
From: "Sarnie, Nick" <nick.sarnie at intel.com>
Date: Fri, 7 Feb 2025 15:31:22 -0800
Subject: [PATCH 3/3] doc warning
Signed-off-by: Sarnie, Nick <nick.sarnie at intel.com>
---
clang/docs/LanguageExtensions.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 87f7df50471e790..057ad564f970bb4 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -101,7 +101,7 @@ the constant evaluation of the corresponding builtin (for example,
``std::fmax`` calls ``__builtin_fmax``) is supported in Clang.
``__has_target_builtin``
------------------
+------------------------
This function-like macro takes a single identifier argument that is the name of
a builtin function, a builtin pseudo-function (taking one or more type
More information about the cfe-commits
mailing list