Skip to content

Commit 46cce74

Browse files
committed
[Clang] Add __has_target_builtin macro
Signed-off-by: Sarnie, Nick <[email protected]>
1 parent 196a1ac commit 46cce74

File tree

4 files changed

+64
-5
lines changed

4 files changed

+64
-5
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ It can be used like this:
6767
``__has_builtin`` should not be used to detect support for a builtin macro;
6868
use ``#ifdef`` instead.
6969

70+
When using device offloading, a builtin is considered available if it is
71+
available on either the host or the device targets.
72+
Use ``__has_target_builtin`` to consider only the current target.
73+
7074
``__has_constexpr_builtin``
7175
---------------------------
7276

@@ -96,6 +100,35 @@ the ``<cmath>`` header file to conditionally make a function constexpr whenever
96100
the constant evaluation of the corresponding builtin (for example,
97101
``std::fmax`` calls ``__builtin_fmax``) is supported in Clang.
98102

103+
``__has_target_builtin``
104+
------------------------
105+
106+
This function-like macro takes a single identifier argument that is the name of
107+
a builtin function, a builtin pseudo-function (taking one or more type
108+
arguments), or a builtin template.
109+
It evaluates to 1 if the builtin is supported on the current target or 0 if not.
110+
The behavior is different than ``__has_builtin`` when there is an auxiliary target,
111+
such when offloading to a target device.
112+
It can be used like this:
113+
114+
.. code-block:: c++
115+
116+
#ifndef __has_target_builtin // Optional of course.
117+
#define __has_target_builtin(x) 0 // Compatibility with non-clang compilers.
118+
#endif
119+
120+
...
121+
#if __has_target_builtin(__builtin_trap)
122+
__builtin_trap();
123+
#else
124+
abort();
125+
#endif
126+
...
127+
128+
.. note::
129+
``__has_target_builtin`` should not be used to detect support for a builtin macro;
130+
use ``#ifdef`` instead.
131+
99132
.. _langext-__has_feature-__has_extension:
100133

101134
``__has_feature`` and ``__has_extension``

clang/include/clang/Lex/Preprocessor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ class Preprocessor {
174174
IdentifierInfo *Ident__has_extension; // __has_extension
175175
IdentifierInfo *Ident__has_builtin; // __has_builtin
176176
IdentifierInfo *Ident__has_constexpr_builtin; // __has_constexpr_builtin
177+
IdentifierInfo *Ident__has_target_builtin; // __has_target_builtin
177178
IdentifierInfo *Ident__has_attribute; // __has_attribute
178179
IdentifierInfo *Ident__has_embed; // __has_embed
179180
IdentifierInfo *Ident__has_include; // __has_include

clang/lib/Lex/PPMacroExpansion.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ void Preprocessor::RegisterBuiltinMacros() {
357357
Ident__has_builtin = RegisterBuiltinMacro("__has_builtin");
358358
Ident__has_constexpr_builtin =
359359
RegisterBuiltinMacro("__has_constexpr_builtin");
360+
Ident__has_target_builtin = RegisterBuiltinMacro("__has_target_builtin");
360361
Ident__has_attribute = RegisterBuiltinMacro("__has_attribute");
361362
if (!getLangOpts().CPlusPlus)
362363
Ident__has_c_attribute = RegisterBuiltinMacro("__has_c_attribute");
@@ -1797,16 +1798,18 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
17971798
diag::err_feature_check_malformed);
17981799
return II && HasExtension(*this, II->getName());
17991800
});
1800-
} else if (II == Ident__has_builtin) {
1801+
} else if (II == Ident__has_builtin || II == Ident__has_target_builtin) {
1802+
bool IsHasTargetBuiltin = II == Ident__has_target_builtin;
18011803
EvaluateFeatureLikeBuiltinMacro(
18021804
OS, Tok, II, *this, false,
1803-
[this](Token &Tok, bool &HasLexedNextToken) -> int {
1805+
[this, IsHasTargetBuiltin](Token &Tok, bool &HasLexedNextToken) -> int {
18041806
IdentifierInfo *II = ExpectFeatureIdentifierInfo(
18051807
Tok, *this, diag::err_feature_check_malformed);
18061808
if (!II)
18071809
return false;
1808-
else if (II->getBuiltinID() != 0) {
1809-
switch (II->getBuiltinID()) {
1810+
auto BuiltinID = II->getBuiltinID();
1811+
if (BuiltinID != 0) {
1812+
switch (BuiltinID) {
18101813
case Builtin::BI__builtin_cpu_is:
18111814
return getTargetInfo().supportsCpuIs();
18121815
case Builtin::BI__builtin_cpu_init:
@@ -1819,8 +1822,12 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
18191822
// usual allocation and deallocation functions. Required by libc++
18201823
return 201802;
18211824
default:
1825+
// __has_target_builtin should return false for aux builtins.
1826+
if (IsHasTargetBuiltin &&
1827+
getBuiltinInfo().isAuxBuiltinID(BuiltinID))
1828+
return false;
18221829
return Builtin::evaluateRequiredTargetFeatures(
1823-
getBuiltinInfo().getRequiredFeatures(II->getBuiltinID()),
1830+
getBuiltinInfo().getRequiredFeatures(BuiltinID),
18241831
getTargetInfo().getTargetOpts().FeatureMap);
18251832
}
18261833
return true;
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %clang_cc1 -fopenmp -triple=spirv64 -fopenmp-is-target-device \
2+
// RUN: -aux-triple x86_64-linux-unknown -E %s | FileCheck -implicit-check-not=BAD %s
3+
4+
// RUN: %clang_cc1 -fopenmp -triple=nvptx64 -fopenmp-is-target-device \
5+
// RUN: -aux-triple x86_64-linux-unknown -E %s | FileCheck -implicit-check-not=BAD %s
6+
7+
// RUN: %clang_cc1 -fopenmp -triple=amdgcn-amd-amdhsa -fopenmp-is-target-device \
8+
// RUN: -aux-triple x86_64-linux-unknown -E %s | FileCheck -implicit-check-not=BAD %s
9+
10+
// RUN: %clang_cc1 -fopenmp -triple=aarch64 -fopenmp-is-target-device \
11+
// RUN: -aux-triple x86_64-linux-unknown -E %s | FileCheck -implicit-check-not=BAD %s
12+
13+
// CHECK: GOOD
14+
#if __has_target_builtin(__builtin_ia32_pause)
15+
BAD
16+
#else
17+
GOOD
18+
#endif

0 commit comments

Comments
 (0)