https://github.com/sarnex created 
https://github.com/llvm/llvm-project/pull/121839

Currently, `__has_builtin` will return true when passed a builtin that is only 
supported on the aux target. I found this when  `__has_builtin` was called with 
an X86 builtin but the current target was SPIR-V.

If we know for sure the builtin can't be supported on the current target, the 
function should return false.

We can't simply check if it's an aux builtin, see the test mentioned in the 
comment.

>From 997373350540448d91f9884b98cbdc0df058a7a3 Mon Sep 17 00:00:00 2001
From: "Sarnie, Nick" <nick.sar...@intel.com>
Date: Mon, 6 Jan 2025 11:48:07 -0800
Subject: [PATCH] [Clang] __has_builtin should return false for aux triple
 builtins

Signed-off-by: Sarnie, Nick <nick.sar...@intel.com>
---
 clang/include/clang/Basic/Builtins.h         |  5 +++++
 clang/lib/Basic/Builtins.cpp                 | 19 +++++++++++++++++++
 clang/lib/Lex/PPMacroExpansion.cpp           | 20 +++++++++++++++++---
 clang/test/Preprocessor/builtin_aux_info.cpp | 12 ++++++++++++
 4 files changed, 53 insertions(+), 3 deletions(-)
 create mode 100644 clang/test/Preprocessor/builtin_aux_info.cpp

diff --git a/clang/include/clang/Basic/Builtins.h 
b/clang/include/clang/Basic/Builtins.h
index 63559d977ce6b6..0939f95b0922c1 100644
--- a/clang/include/clang/Basic/Builtins.h
+++ b/clang/include/clang/Basic/Builtins.h
@@ -74,6 +74,7 @@ struct Info {
   const char *Features;
   HeaderDesc Header;
   LanguageID Langs;
+  bool operator==(const Info &Other) const;
 };
 
 /// Holds information about both target-independent and
@@ -268,6 +269,10 @@ class Context {
   /// for AuxTarget).
   unsigned getAuxBuiltinID(unsigned ID) const { return ID - TSRecords.size(); }
 
+  // Return true if the AuxBuiltin ID represents a target-specific builtin that
+  // is always unsupported on the default target.
+  bool isAuxBuiltinIDAlwaysUnsupportedOnDefaultTarget(unsigned ID) const;
+
   /// Returns true if this is a libc/libm function without the '__builtin_'
   /// prefix.
   static bool isBuiltinFunc(llvm::StringRef Name);
diff --git a/clang/lib/Basic/Builtins.cpp b/clang/lib/Basic/Builtins.cpp
index 588183788de322..c6e54b89e848cc 100644
--- a/clang/lib/Basic/Builtins.cpp
+++ b/clang/lib/Basic/Builtins.cpp
@@ -41,6 +41,14 @@ static constexpr Builtin::Info BuiltinInfo[] = {
 #include "clang/Basic/Builtins.inc"
 };
 
+bool Builtin::Info::operator==(const Builtin::Info &Other) const {
+  auto StrCompare = [](StringRef A, StringRef B) { return A == B; };
+  return Name == Other.Name && StrCompare(Type, Other.Type) &&
+         StrCompare(Attributes, Other.Attributes) &&
+         StrCompare(Features, Other.Features) && Header.ID == Other.Header.ID 
&&
+         Langs == Other.Langs;
+}
+
 const Builtin::Info &Builtin::Context::getRecord(unsigned ID) const {
   if (ID < Builtin::FirstTSBuiltin)
     return BuiltinInfo[ID];
@@ -183,6 +191,17 @@ unsigned Builtin::Context::getRequiredVectorWidth(unsigned 
ID) const {
   return Width;
 }
 
+bool Builtin::Context::isAuxBuiltinIDAlwaysUnsupportedOnDefaultTarget(
+    unsigned ID) const {
+  assert(isAuxTargetBuiltinID(ID) && "Expected aux target builtin ID");
+  const auto &Record = getRecord(ID);
+  for (const auto &MainTargetBuiltin : TSRecords)
+    if (Record == MainTargetBuiltin)
+      return false;
+
+  return true;
+}
+
 bool Builtin::Context::isLike(unsigned ID, unsigned &FormatIdx,
                               bool &HasVAListArg, const char *Fmt) const {
   assert(Fmt && "Not passed a format string");
diff --git a/clang/lib/Lex/PPMacroExpansion.cpp 
b/clang/lib/Lex/PPMacroExpansion.cpp
index 347c13da0ad215..13d9a0094a5827 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -1804,8 +1804,9 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
                                            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 +1819,21 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
             // usual allocation and deallocation functions. Required by libc++
             return 201802;
           default:
+            // We may get here because of aux builtins which may not be
+            // supported on the default target, for example if we have an X86
+            // specific builtin and the current target is SPIR-V. Sometimes we
+            // rely on __has_builtin returning true when passed a builtin that
+            // is not supported on the default target due to LangOpts but is
+            // supported on the aux target. See
+            // test/Headers/__cpuidex_conflict.c for an example. If the builtin
+            // is an aux builtin and it can never be supported on the default
+            // target, __has_builtin should return false.
+            if (getBuiltinInfo().isAuxBuiltinID(BuiltinID) &&
+                
getBuiltinInfo().isAuxBuiltinIDAlwaysUnsupportedOnDefaultTarget(
+                    BuiltinID))
+              return false;
             return Builtin::evaluateRequiredTargetFeatures(
-                getBuiltinInfo().getRequiredFeatures(II->getBuiltinID()),
+                getBuiltinInfo().getRequiredFeatures(BuiltinID),
                 getTargetInfo().getTargetOpts().FeatureMap);
           }
           return true;
diff --git a/clang/test/Preprocessor/builtin_aux_info.cpp 
b/clang/test/Preprocessor/builtin_aux_info.cpp
new file mode 100644
index 00000000000000..041c7edfdcadac
--- /dev/null
+++ b/clang/test/Preprocessor/builtin_aux_info.cpp
@@ -0,0 +1,12 @@
+// REQUIRES: spirv-registered-target
+// REQUIRES: x86-registered-target
+
+// 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
+
+// CHECK: GOOD
+#if __has_builtin(__builtin_ia32_pause)
+  BAD
+#else
+  GOOD
+#endif

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to