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.sar...@intel.com> Date: Fri, 7 Feb 2025 14:57:12 -0800 Subject: [PATCH 1/9] [Clang] Add __has_target_builtin macro Signed-off-by: Sarnie, Nick <nick.sar...@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 973cf8f9d091c..057ad564f970b 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 2bf4d1a166994..240fe28aba93e 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 944966a791add..9ec75a08316a1 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 0000000000000..64b2d7e1b35d9 --- /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.sar...@intel.com> Date: Mon, 10 Feb 2025 11:45:40 -0800 Subject: [PATCH 2/9] add release note, only define for offloading targets, update test Signed-off-by: Sarnie, Nick <nick.sar...@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 057ad564f970b..f284c2bfcd892 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 50d3bbbc97e91..468c34266f2da 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 9ec75a08316a1..48b4c6acb96e1 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 64b2d7e1b35d9..e7f28a049af3b 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.sar...@intel.com> Date: Mon, 10 Feb 2025 12:16:18 -0800 Subject: [PATCH 3/9] doc feedback Signed-off-by: Sarnie, Nick <nick.sar...@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 f284c2bfcd892..34c87f9e7697f 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.sar...@intel.com> Date: Mon, 10 Feb 2025 12:40:26 -0800 Subject: [PATCH 4/9] improve comparison doc Signed-off-by: Sarnie, Nick <nick.sar...@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 34c87f9e7697f..541a1ca0192d2 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.sar...@intel.com> Date: Mon, 10 Feb 2025 12:43:25 -0800 Subject: [PATCH 5/9] space Signed-off-by: Sarnie, Nick <nick.sar...@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 541a1ca0192d2..aa6bf488f34e9 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.sar...@intel.com> Date: Mon, 10 Feb 2025 12:45:18 -0800 Subject: [PATCH 6/9] spacing again Signed-off-by: Sarnie, Nick <nick.sar...@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 aa6bf488f34e9..7c0592d576f15 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.sar...@intel.com> Date: Mon, 10 Feb 2025 14:00:40 -0800 Subject: [PATCH 7/9] missed endif Signed-off-by: Sarnie, Nick <nick.sar...@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 7c0592d576f15..8c642c818ee65 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:: >From 2668404f9a46155a897030aca29e117f4319f9a5 Mon Sep 17 00:00:00 2001 From: "Sarnie, Nick" <nick.sar...@intel.com> Date: Tue, 11 Feb 2025 07:02:49 -0800 Subject: [PATCH 8/9] make macro defined on all targets, address aarons feedback Signed-off-by: Sarnie, Nick <nick.sar...@intel.com> --- clang/docs/LanguageExtensions.rst | 5 +--- clang/docs/ReleaseNotes.rst | 2 +- clang/lib/Lex/PPMacroExpansion.cpp | 9 ++----- .../test/Preprocessor/has_target_builtin.cpp | 25 ++++++++----------- 4 files changed, 15 insertions(+), 26 deletions(-) diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 8c642c818ee65..96e7df210db48 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -69,8 +69,7 @@ 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 for an - offloading target. + Use ``__has_target_builtin`` to consider only the current target. ``__has_constexpr_builtin`` --------------------------- @@ -142,8 +141,6 @@ 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_builtin`` 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 468c34266f2da..d588c3727997e 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -108,7 +108,7 @@ New Compiler Builtins --------------------- - The new ``__has_target_builtin`` macro can be used to check if a builtin is available - on the current offloading target. + on the current target. Deprecated Compiler Flags ------------------------- diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 48b4c6acb96e1..8be4d06c4887d 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -357,12 +357,7 @@ void Preprocessor::RegisterBuiltinMacros() { Ident__has_builtin = RegisterBuiltinMacro("__has_builtin"); Ident__has_constexpr_builtin = RegisterBuiltinMacro("__has_constexpr_builtin"); - if (getLangOpts().OpenMPIsTargetDevice || getLangOpts().CUDAIsDevice || - getLangOpts().SYCLIsDevice) - Ident__has_target_builtin = RegisterBuiltinMacro("__has_target_builtin"); - else - Ident__has_target_builtin = nullptr; - + 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"); @@ -1812,7 +1807,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { Tok, *this, diag::err_feature_check_malformed); if (!II) return false; - auto BuiltinID = II->getBuiltinID(); + unsigned BuiltinID = II->getBuiltinID(); if (BuiltinID != 0) { switch (BuiltinID) { case Builtin::BI__builtin_cpu_is: diff --git a/clang/test/Preprocessor/has_target_builtin.cpp b/clang/test/Preprocessor/has_target_builtin.cpp index e7f28a049af3b..f11f7ae0e28c0 100644 --- a/clang/test/Preprocessor/has_target_builtin.cpp +++ b/clang/test/Preprocessor/has_target_builtin.cpp @@ -1,27 +1,24 @@ // RUN: %clang_cc1 -fopenmp -triple=spirv64 -fopenmp-is-target-device \ -// RUN: -aux-triple x86_64-linux-unknown -E %s | FileCheck -implicit-check-not="{{BAD|DOESNT}}" %s +// RUN: -aux-triple x86_64-linux-unknown -E %s | FileCheck -implicit-check-not=HAS %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|DOESNT}}" %s +// RUN: -aux-triple x86_64-linux-unknown -E %s | FileCheck -implicit-check-not=HAS %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|DOESNT}}" %s +// RUN: -aux-triple x86_64-linux-unknown -E %s | FileCheck -implicit-check-not=HAS %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|DOESNT}}" %s +// RUN: -aux-triple x86_64-linux-unknown -E %s | FileCheck -implicit-check-not=HAS %s -// RUN: %clang_cc1 -triple=aarch64 -E %s | FileCheck -check-prefix=CHECK-NOTOFFLOAD -implicit-check-not="{{GOOD|HAS|BAD}}" %s +// RUN: %clang_cc1 -triple=aarch64 -E %s | FileCheck -implicit-check-not=HAS %s -// CHECK: GOOD +// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -E %s | \ +// RUN: FileCheck -check-prefix=CHECK-NO-OFFLOAD-HAS-BUILTIN -implicit-check-not=DOESNT %s -// CHECK-NOTOFFLOAD: DOESNT -#ifdef __has_target_builtin - HAS +// CHECK: DOESNT +// CHECK-NO-OFFLOAD-HAS-BUILTIN: HAS #if __has_target_builtin(__builtin_ia32_pause) - BAD + HAS #else - GOOD -#endif -#else - DOESNT + DOESNT #endif >From 71433893b44a6d8eae019522c84b7f717c4c575a Mon Sep 17 00:00:00 2001 From: "Sarnie, Nick" <nick.sar...@intel.com> Date: Wed, 12 Feb 2025 11:19:15 -0800 Subject: [PATCH 9/9] improve example Signed-off-by: Sarnie, Nick <nick.sar...@intel.com> --- clang/docs/LanguageExtensions.rst | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 96e7df210db48..be767af694519 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -118,24 +118,32 @@ 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: +As a motivating example, let's try to guard a builtin call using ``__has_builtin`` in a heterogeneous compilation, +such as OpenMP Offloading, with the host being x86-64 and the offloading device being AMDGPU. .. code-block:: c++ - #ifdef __CUDA__ - #if __has_target_builtin(__builtin_trap) - __builtin_trap(); + #if __has_builtin(__builtin_ia32_pause) + __builtin_ia32_pause(); #else abort(); #endif - #else // !CUDA - #if __has_builtin(__builtin_trap) - __builtin_trap(); + +Compilation of this code results in a compiler error because ``__builtin_ia32_pause`` is known to the compiler because +it is a builtin supported by the host x86-64 compilation so ``__has_builtin`` returns true. However, code cannot +be generated for ``__builtin_ia32_pause`` during the offload AMDGPU compilation as it is not supported on that target. + +To guard uses of builtins in heterogeneous compilations such as this, +``__has_target_builtin`` can be used as per the below example to verify code can be generated +for the referenced builtin on the current target being compiled. + +.. code-block:: c++ + + #if __has_target_builtin(__builtin_ia32_pause) + __builtin_ia32_pause(); #else abort(); #endif - #endif - ... .. note:: ``__has_target_builtin`` should not be used to detect support for a builtin macro; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits