[clang] [Clang] Add __has_target_builtin macro (PR #126324)
Nick Sarnie via cfe-commits
cfe-commits at lists.llvm.org
Mon Feb 10 14:01:00 PST 2025
https://github.com/sarnex updated https://github.com/llvm/llvm-project/pull/126324
>From 46cce74568bca5a3e80e50def4348bc734448362 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/7] [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..057ad564f970bb4 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 944966a791add58..9ec75a08316a1aa 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,16 +1798,18 @@ 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:
@@ -1819,8 +1822,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 2a2a18b3d1c0220cd55b922bea4fe0694a9a668f Mon Sep 17 00:00:00 2001
From: "Sarnie, Nick" <nick.sarnie at intel.com>
Date: Mon, 10 Feb 2025 11:45:40 -0800
Subject: [PATCH 2/7] add release note, only define for offloading targets,
update test
Signed-off-by: Sarnie, Nick <nick.sarnie at intel.com>
---
clang/docs/LanguageExtensions.rst | 5 ++++-
clang/docs/ReleaseNotes.rst | 6 ++++++
clang/lib/Lex/PPMacroExpansion.cpp | 7 ++++++-
clang/test/Preprocessor/has_target_builtin.cpp | 17 +++++++++++++----
4 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 057ad564f970bb4..f284c2bfcd892cf 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -69,7 +69,8 @@ It can be used like this:
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.
+ Use ``__has_target_builtin`` to consider only the current target for an
+ offloading target.
``__has_constexpr_builtin``
---------------------------
@@ -129,6 +130,8 @@ It can be used like this:
``__has_target_builtin`` should not be used to detect support for a builtin macro;
use ``#ifdef`` instead.
+ ``__has_target_built`` is only defined for offloading targets.
+
.. _langext-__has_feature-__has_extension:
``__has_feature`` and ``__has_extension``
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 50d3bbbc97e9192..468c34266f2dabb 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -104,6 +104,12 @@ Non-comprehensive list of changes in this release
New Compiler Flags
------------------
+New Compiler Builtins
+---------------------
+
+- The new ``__has_target_builtin`` macro can be used to check if a builtin is available
+ on the current offloading target.
+
Deprecated Compiler Flags
-------------------------
diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp
index 9ec75a08316a1aa..48b4c6acb96e1e0 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -357,7 +357,12 @@ 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");
+ if (getLangOpts().OpenMPIsTargetDevice || getLangOpts().CUDAIsDevice ||
+ getLangOpts().SYCLIsDevice)
+ Ident__has_target_builtin = RegisterBuiltinMacro("__has_target_builtin");
+ else
+ Ident__has_target_builtin = nullptr;
+
Ident__has_attribute = RegisterBuiltinMacro("__has_attribute");
if (!getLangOpts().CPlusPlus)
Ident__has_c_attribute = RegisterBuiltinMacro("__has_c_attribute");
diff --git a/clang/test/Preprocessor/has_target_builtin.cpp b/clang/test/Preprocessor/has_target_builtin.cpp
index 64b2d7e1b35d9ef..e7f28a049af3bbd 100644
--- a/clang/test/Preprocessor/has_target_builtin.cpp
+++ b/clang/test/Preprocessor/has_target_builtin.cpp
@@ -1,18 +1,27 @@
// 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: -aux-triple x86_64-linux-unknown -E %s | FileCheck -implicit-check-not="{{BAD|DOESNT}}" %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: -aux-triple x86_64-linux-unknown -E %s | FileCheck -implicit-check-not="{{BAD|DOESNT}}" %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: -aux-triple x86_64-linux-unknown -E %s | FileCheck -implicit-check-not="{{BAD|DOESNT}}" %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
+// RUN: -aux-triple x86_64-linux-unknown -E %s | FileCheck -implicit-check-not="{{BAD|DOESNT}}" %s
+
+// RUN: %clang_cc1 -triple=aarch64 -E %s | FileCheck -check-prefix=CHECK-NOTOFFLOAD -implicit-check-not="{{GOOD|HAS|BAD}}" %s
// CHECK: GOOD
+
+// CHECK-NOTOFFLOAD: DOESNT
+#ifdef __has_target_builtin
+ HAS
#if __has_target_builtin(__builtin_ia32_pause)
BAD
#else
GOOD
#endif
+#else
+ DOESNT
+#endif
>From 644ea85450825e73b3c71c6e80333c90354805ea Mon Sep 17 00:00:00 2001
From: "Sarnie, Nick" <nick.sarnie at intel.com>
Date: Mon, 10 Feb 2025 12:16:18 -0800
Subject: [PATCH 3/7] doc feedback
Signed-off-by: Sarnie, Nick <nick.sarnie at intel.com>
---
clang/docs/LanguageExtensions.rst | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index f284c2bfcd892cf..34c87f9e7697f44 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -109,18 +109,19 @@ 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.
+such as 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
-
- ...
+ #ifdef __CUDA__
#if __has_target_builtin(__builtin_trap)
__builtin_trap();
+ #else
+ abort();
+ #endif
+ #else // !CUDA
+ #if __has_builtin(__builtin_trap)
+ __builtin_trap();
#else
abort();
#endif
@@ -130,7 +131,7 @@ It can be used like this:
``__has_target_builtin`` should not be used to detect support for a builtin macro;
use ``#ifdef`` instead.
- ``__has_target_built`` is only defined for offloading targets.
+ ``__has_target_builtin`` is only defined for offloading targets.
.. _langext-__has_feature-__has_extension:
>From 887de75686aaa64e0c5f81541ad9e9f9b6e00b37 Mon Sep 17 00:00:00 2001
From: "Sarnie, Nick" <nick.sarnie at intel.com>
Date: Mon, 10 Feb 2025 12:40:26 -0800
Subject: [PATCH 4/7] improve comparison doc
Signed-off-by: Sarnie, Nick <nick.sarnie at intel.com>
---
clang/docs/LanguageExtensions.rst | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 34c87f9e7697f44..541a1ca0192d231 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -108,8 +108,17 @@ 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 as when offloading to a target device.
+
+``__has_builtin`` and ``__has_target_builtin`` behave identically for normal C++ compilations.
+
+For heterogeneous compilations that see source code intended for more than one target:
+
+``__has_builtin`` returns true if the builtin is known to the compiler
+(i.e. it's available via one of the targets), but makes no promises whether it's available on the current target.
+The compiler can parse it, but not necessarily generate code for it.
+
+``__has_target_builtin`` returns true if the builtin can actually be generated for the current target.
+
It can be used like this:
.. code-block:: c++
>From 7781516792588feeb54f114f5fbc91312f9ff924 Mon Sep 17 00:00:00 2001
From: "Sarnie, Nick" <nick.sarnie at intel.com>
Date: Mon, 10 Feb 2025 12:43:25 -0800
Subject: [PATCH 5/7] space
Signed-off-by: Sarnie, Nick <nick.sarnie at intel.com>
---
clang/docs/LanguageExtensions.rst | 1 +
1 file changed, 1 insertion(+)
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 541a1ca0192d231..aa6bf488f34e9be 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -122,6 +122,7 @@ The compiler can parse it, but not necessarily generate code for it.
It can be used like this:
.. code-block:: c++
+
#ifdef __CUDA__
#if __has_target_builtin(__builtin_trap)
__builtin_trap();
>From 5d84bc5f5b10b14b333d831774f65ce02316c958 Mon Sep 17 00:00:00 2001
From: "Sarnie, Nick" <nick.sarnie at intel.com>
Date: Mon, 10 Feb 2025 12:45:18 -0800
Subject: [PATCH 6/7] spacing again
Signed-off-by: Sarnie, Nick <nick.sarnie at intel.com>
---
clang/docs/LanguageExtensions.rst | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index aa6bf488f34e9be..7c0592d576f15d2 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -127,11 +127,11 @@ It can be used like this:
#if __has_target_builtin(__builtin_trap)
__builtin_trap();
#else
- abort();
+ abort();
#endif
#else // !CUDA
#if __has_builtin(__builtin_trap)
- __builtin_trap();
+ __builtin_trap();
#else
abort();
#endif
>From 7e2dc73ba39bba27d39973de47af2f641c9cf42d Mon Sep 17 00:00:00 2001
From: "Sarnie, Nick" <nick.sarnie at intel.com>
Date: Mon, 10 Feb 2025 14:00:40 -0800
Subject: [PATCH 7/7] missed endif
Signed-off-by: Sarnie, Nick <nick.sarnie at intel.com>
---
clang/docs/LanguageExtensions.rst | 1 +
1 file changed, 1 insertion(+)
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 7c0592d576f15d2..8c642c818ee65b0 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -135,6 +135,7 @@ It can be used like this:
#else
abort();
#endif
+ #endif
...
.. note::
More information about the cfe-commits
mailing list