[clang] [Clang][TableGen] Support specifying address space in clang builtin prototypes (PR #108497)

Vikram Hegde via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 27 02:22:02 PDT 2024


https://github.com/vikramRH updated https://github.com/llvm/llvm-project/pull/108497

>From 6afc2e91d8877cc330f6e317a404a74990d9c607 Mon Sep 17 00:00:00 2001
From: vikhegde <vikhegde at amd.com>
Date: Wed, 4 Sep 2024 10:34:54 +0000
Subject: [PATCH 1/2] [clang][TableGen] Support specifying address space in
 clang builtin prototypes

---
 .../target-builtins-prototype-parser.td       | 71 +++++++++++++++++++
 clang/utils/TableGen/ClangBuiltinsEmitter.cpp | 52 ++++++++++++--
 2 files changed, 119 insertions(+), 4 deletions(-)

diff --git a/clang/test/TableGen/target-builtins-prototype-parser.td b/clang/test/TableGen/target-builtins-prototype-parser.td
index 555aebb3ccfb1f..dcff11046603ef 100644
--- a/clang/test/TableGen/target-builtins-prototype-parser.td
+++ b/clang/test/TableGen/target-builtins-prototype-parser.td
@@ -6,6 +6,12 @@
 // RUN: not clang-tblgen -I %p/../../include/ %s --gen-clang-builtins -DERROR_EXPECTED_B 2>&1 | FileCheck %s --check-prefix=ERROR_EXPECTED_B
 // RUN: not clang-tblgen -I %p/../../include/ %s --gen-clang-builtins -DERROR_EXPECTED_C 2>&1 | FileCheck %s --check-prefix=ERROR_EXPECTED_C
 // RUN: not clang-tblgen -I %p/../../include/ %s --gen-clang-builtins -DERROR_EXPECTED_D 2>&1 | FileCheck %s --check-prefix=ERROR_EXPECTED_D
+// RUN: not clang-tblgen -I %p/../../include/ %s --gen-clang-builtins -DERROR_EXPECTED_E 2>&1 | FileCheck %s --check-prefix=ERROR_EXPECTED_E
+// RUN: not clang-tblgen -I %p/../../include/ %s --gen-clang-builtins -DERROR_EXPECTED_F 2>&1 | FileCheck %s --check-prefix=ERROR_EXPECTED_F
+// RUN: not clang-tblgen -I %p/../../include/ %s --gen-clang-builtins -DERROR_EXPECTED_G 2>&1 | FileCheck %s --check-prefix=ERROR_EXPECTED_G
+// RUN: not clang-tblgen -I %p/../../include/ %s --gen-clang-builtins -DERROR_EXPECTED_H 2>&1 | FileCheck %s --check-prefix=ERROR_EXPECTED_H
+// RUN: not clang-tblgen -I %p/../../include/ %s --gen-clang-builtins -DERROR_EXPECTED_I 2>&1 | FileCheck %s --check-prefix=ERROR_EXPECTED_I
+// RUN: not clang-tblgen -I %p/../../include/ %s --gen-clang-builtins -DERROR_EXPECTED_J 2>&1 | FileCheck %s --check-prefix=ERROR_EXPECTED_J
 
 include "clang/Basic/BuiltinsBase.td"
 
@@ -113,3 +119,68 @@ def : Builtin {
 }
 #endif
 
+def : Builtin {
+// CHECK: BUILTIN(__builtin_test_addrspace_attribute_01, "di*3", "")
+  let Prototype = "double( [[addrspace[3]]] int*)";
+  let Spellings = ["__builtin_test_addrspace_attribute_01"];
+}
+
+def : Builtin {
+// CHECK: BUILTIN(__builtin_test_addrspace_attribute_02, "Ii*5i*d", "")
+  let Prototype = "_Constant [[addrspace[5]]] int* (int*, double)";
+  let Spellings = ["__builtin_test_addrspace_attribute_02"];
+}
+
+def : Builtin {
+// CHECK: BUILTIN(__builtin_test_addrspace_attribute_04, "Ii&4id*7", "")
+  let Prototype = "_Constant [[addrspace[4]]] int& (int , [[addrspace[7]]] double*)";
+  let Spellings = ["__builtin_test_addrspace_attribute_04"];
+}
+
+#ifdef ERROR_EXPECTED_E
+def : Builtin {
+// ERROR_EXPECTED_E: :[[# @LINE + 1]]:7: error: Expected opening bracket '[' after 'addrspace'
+  let Prototype = "_Constant [[addrspace]] int& (int , double*)";
+  let Spellings = ["__builtin_test_addrspace_attribute_04"];
+}
+#endif
+
+#ifdef ERROR_EXPECTED_F
+def : Builtin {
+// ERROR_EXPECTED_F: :[[# @LINE + 1]]:7: error: Address space attribute can only be specified with a pointer or reference type
+  let Prototype = "_Constant [[addrspace[4]]] int (int , double*)";
+  let Spellings = ["__builtin_test_addrspace_attribute_04"];
+}
+#endif
+
+#ifdef ERROR_EXPECTED_G
+def : Builtin {
+// ERROR_EXPECTED_G: :[[# @LINE + 1]]:7: error: Expecetd valid integer for 'addrspace' attribute
+  let Prototype = "_Constant [[addrspace[k]]] int* (int , double*)";
+  let Spellings = ["__builtin_test_addrspace_attribute_04"];
+}
+#endif
+
+#ifdef ERROR_EXPECTED_H
+def : Builtin {
+// ERROR_EXPECTED_H: :[[# @LINE + 1]]:7: error: Expected closing bracket ']' after address space specification
+  let Prototype = "_Constant [[addrspace[6 int* (int , double*)";
+  let Spellings = ["__builtin_test_addrspace_attribute_04"];
+}
+#endif
+
+#ifdef ERROR_EXPECTED_I
+def : Builtin {
+// ERROR_EXPECTED_I: :[[# @LINE + 1]]:7: error: Expected closing brackets ']]' for attribute list
+  let Prototype = "_Constant [[addrspace[6] int* (int , double*)";
+  let Spellings = ["__builtin_test_addrspace_attribute_04"];
+}
+#endif
+
+#ifdef ERROR_EXPECTED_J
+def : Builtin {
+// ERROR_EXPECTED_J: :[[# @LINE + 1]]:7: error: Unknown attribute name specified
+  let Prototype = "_Constant [[invalid]] int* (int , double*)";
+  let Spellings = ["__builtin_test_addrspace_attribute_04"];
+}
+#endif
diff --git a/clang/utils/TableGen/ClangBuiltinsEmitter.cpp b/clang/utils/TableGen/ClangBuiltinsEmitter.cpp
index 4ae7600a392b8f..c088806795079c 100644
--- a/clang/utils/TableGen/ClangBuiltinsEmitter.cpp
+++ b/clang/utils/TableGen/ClangBuiltinsEmitter.cpp
@@ -40,9 +40,31 @@ class PrototypeParser {
     ParseTypes(Prototype);
   }
 
+  void ParseTypeAttributeList(StringRef &T, SMLoc Loc) {
+    if (T.consume_front("addrspace")) {
+      unsigned long long AS = 0;
+      if (!T.consume_front("["))
+        PrintFatalError(Loc, "Expected opening bracket '[' after 'addrspace'");
+
+      if (llvm::consumeUnsignedInteger(T, 10, AS))
+        PrintFatalError(Loc,
+                        "Expecetd valid integer for 'addrspace' attribute");
+
+      if (!T.consume_front("]"))
+        PrintFatalError(
+            Loc,
+            "Expected closing bracket ']' after address space specification");
+      AddrSpace = AS;
+    } else
+      PrintFatalError(Loc, "Unknown attribute name specified");
+
+    if (!T.consume_front("]]"))
+      PrintFatalError(Loc, "Expected closing brackets ']]' for attribute list");
+  }
+
   void ParseTypes(StringRef &Prototype) {
     auto ReturnType = Prototype.take_until([](char c) { return c == '('; });
-    ParseType(ReturnType);
+    ParseTypeAndValidateAttributes(ReturnType);
     Prototype = Prototype.drop_front(ReturnType.size() + 1);
     if (!Prototype.ends_with(")"))
       PrintFatalError(Loc, "Expected closing brace at end of prototype");
@@ -66,7 +88,7 @@ class PrototypeParser {
       // we cannot have nested _ExtVector.
       if (Current.starts_with("_ExtVector<")) {
         const size_t EndTemplate = Current.find('>', 0);
-        ParseType(Current.substr(0, EndTemplate + 1));
+        ParseTypeAndValidateAttributes(Current.substr(0, EndTemplate + 1));
         // Move the prototype beyond _ExtVector<...>
         I += EndTemplate + 1;
         continue;
@@ -77,7 +99,7 @@ class PrototypeParser {
       if (size_t CommaPos = Current.find(',', 0)) {
         if (CommaPos != StringRef::npos) {
           StringRef T = Current.substr(0, CommaPos);
-          ParseType(T);
+          ParseTypeAndValidateAttributes(T);
           // Move the prototype beyond the comma.
           I += CommaPos + 1;
           continue;
@@ -85,16 +107,30 @@ class PrototypeParser {
       }
 
       // No more commas, parse final parameter.
-      ParseType(Current);
+      ParseTypeAndValidateAttributes(Current);
       I = end;
     }
   }
 
+  void ParseTypeAndValidateAttributes(StringRef T) {
+    ParseType(T);
+    if (!IsPointerOrReference && AddrSpace)
+      PrintFatalError(
+          Loc, "Address space attribute can only be specified with a pointer"
+               " or reference type");
+
+    IsPointerOrReference = false;
+    AddrSpace = std::nullopt;
+  }
+
   void ParseType(StringRef T) {
     T = T.trim();
     if (T.consume_back("*")) {
       ParseType(T);
       Type += "*";
+      IsPointerOrReference = true;
+      if (AddrSpace)
+        Type += std::to_string(*AddrSpace);
     } else if (T.consume_back("const")) {
       ParseType(T);
       Type += "C";
@@ -107,6 +143,12 @@ class PrototypeParser {
     } else if (T.consume_back("&")) {
       ParseType(T);
       Type += "&";
+      IsPointerOrReference = true;
+      if (AddrSpace)
+        Type += std::to_string(*AddrSpace);
+    } else if (T.consume_front("[[")) {
+      ParseTypeAttributeList(T, Loc);
+      ParseType(T);
     } else if (T.consume_front("long")) {
       Type += "L";
       ParseType(T);
@@ -193,6 +235,8 @@ class PrototypeParser {
   SMLoc Loc;
   StringRef Substitution;
   std::string Type;
+  std::optional<unsigned long long> AddrSpace;
+  bool IsPointerOrReference = false;
 };
 
 class HeaderNameParser {

>From 5ab4003804653cdf3d87048c43bd839ef84b18a9 Mon Sep 17 00:00:00 2001
From: vikhegde <vikhegde at amd.com>
Date: Tue, 24 Sep 2024 10:39:31 +0000
Subject: [PATCH 2/2] design changes according to review comments

---
 clang/include/clang/Basic/BuiltinsBase.td     |  7 +++
 .../target-builtins-prototype-parser.td       | 57 ++++-------------
 clang/utils/TableGen/ClangBuiltinsEmitter.cpp | 63 +++++++++----------
 3 files changed, 51 insertions(+), 76 deletions(-)

diff --git a/clang/include/clang/Basic/BuiltinsBase.td b/clang/include/clang/Basic/BuiltinsBase.td
index 58dee22fc0a450..e7629e944c143c 100644
--- a/clang/include/clang/Basic/BuiltinsBase.td
+++ b/clang/include/clang/Basic/BuiltinsBase.td
@@ -73,6 +73,13 @@ def Constexpr : Attribute<"E">;
 // Builtin is immediate and must be constant evaluated. Implies Constexpr, and will only be supported in C++20 mode.
 def Consteval : Attribute<"EG">;
 
+// Address space attribute, only valid for pointer or reference arguments.
+// ArgIdx - argument to which the attribute refers. value 0 is for return type.
+// AddrSpaceNum - Address space number for the argument.
+class AddressSpace<int ArgIdx, int AddrSpaceNum> : IndexedAttribute<"", ArgIdx> {
+  int SpaceNum = AddrSpaceNum;
+}
+
 // Builtin kinds
 // =============
 
diff --git a/clang/test/TableGen/target-builtins-prototype-parser.td b/clang/test/TableGen/target-builtins-prototype-parser.td
index dcff11046603ef..0c4494a02b546c 100644
--- a/clang/test/TableGen/target-builtins-prototype-parser.td
+++ b/clang/test/TableGen/target-builtins-prototype-parser.td
@@ -8,10 +8,6 @@
 // RUN: not clang-tblgen -I %p/../../include/ %s --gen-clang-builtins -DERROR_EXPECTED_D 2>&1 | FileCheck %s --check-prefix=ERROR_EXPECTED_D
 // RUN: not clang-tblgen -I %p/../../include/ %s --gen-clang-builtins -DERROR_EXPECTED_E 2>&1 | FileCheck %s --check-prefix=ERROR_EXPECTED_E
 // RUN: not clang-tblgen -I %p/../../include/ %s --gen-clang-builtins -DERROR_EXPECTED_F 2>&1 | FileCheck %s --check-prefix=ERROR_EXPECTED_F
-// RUN: not clang-tblgen -I %p/../../include/ %s --gen-clang-builtins -DERROR_EXPECTED_G 2>&1 | FileCheck %s --check-prefix=ERROR_EXPECTED_G
-// RUN: not clang-tblgen -I %p/../../include/ %s --gen-clang-builtins -DERROR_EXPECTED_H 2>&1 | FileCheck %s --check-prefix=ERROR_EXPECTED_H
-// RUN: not clang-tblgen -I %p/../../include/ %s --gen-clang-builtins -DERROR_EXPECTED_I 2>&1 | FileCheck %s --check-prefix=ERROR_EXPECTED_I
-// RUN: not clang-tblgen -I %p/../../include/ %s --gen-clang-builtins -DERROR_EXPECTED_J 2>&1 | FileCheck %s --check-prefix=ERROR_EXPECTED_J
 
 include "clang/Basic/BuiltinsBase.td"
 
@@ -121,66 +117,39 @@ def : Builtin {
 
 def : Builtin {
 // CHECK: BUILTIN(__builtin_test_addrspace_attribute_01, "di*3", "")
-  let Prototype = "double( [[addrspace[3]]] int*)";
+  let Prototype = "double(int*)";
   let Spellings = ["__builtin_test_addrspace_attribute_01"];
+  let Attributes = [AddressSpace<1, 3>];
 }
 
 def : Builtin {
-// CHECK: BUILTIN(__builtin_test_addrspace_attribute_02, "Ii*5i*d", "")
-  let Prototype = "_Constant [[addrspace[5]]] int* (int*, double)";
+// CHECK: BUILTIN(__builtin_test_addrspace_attribute_02, "Ii*5i*d", "n")
+  let Prototype = "_Constant int* (int*, double)";
   let Spellings = ["__builtin_test_addrspace_attribute_02"];
+  let Attributes = [AddressSpace<0, 5>, NoThrow];
 }
 
 def : Builtin {
-// CHECK: BUILTIN(__builtin_test_addrspace_attribute_04, "Ii&4id*7", "")
-  let Prototype = "_Constant [[addrspace[4]]] int& (int , [[addrspace[7]]] double*)";
+// CHECK: BUILTIN(__builtin_test_addrspace_attribute_04, "Ii&4id*7", "En")
+  let Prototype = "_Constant int& (int , double*)";
   let Spellings = ["__builtin_test_addrspace_attribute_04"];
+  let Attributes = [AddressSpace<0, 4>, Constexpr, AddressSpace<2, 7>, NoThrow];
 }
 
 #ifdef ERROR_EXPECTED_E
 def : Builtin {
-// ERROR_EXPECTED_E: :[[# @LINE + 1]]:7: error: Expected opening bracket '[' after 'addrspace'
-  let Prototype = "_Constant [[addrspace]] int& (int , double*)";
+// ERROR_EXPECTED_E: :[[# @LINE + 1]]:7: error: Address space attribute for argument 2 repeated
+  let Prototype = "_Constant int& (int , double*)";
   let Spellings = ["__builtin_test_addrspace_attribute_04"];
+  let Attributes = [AddressSpace<2, 4>, AddressSpace<2, 7>];
 }
 #endif
 
 #ifdef ERROR_EXPECTED_F
 def : Builtin {
 // ERROR_EXPECTED_F: :[[# @LINE + 1]]:7: error: Address space attribute can only be specified with a pointer or reference type
-  let Prototype = "_Constant [[addrspace[4]]] int (int , double*)";
-  let Spellings = ["__builtin_test_addrspace_attribute_04"];
-}
-#endif
-
-#ifdef ERROR_EXPECTED_G
-def : Builtin {
-// ERROR_EXPECTED_G: :[[# @LINE + 1]]:7: error: Expecetd valid integer for 'addrspace' attribute
-  let Prototype = "_Constant [[addrspace[k]]] int* (int , double*)";
-  let Spellings = ["__builtin_test_addrspace_attribute_04"];
-}
-#endif
-
-#ifdef ERROR_EXPECTED_H
-def : Builtin {
-// ERROR_EXPECTED_H: :[[# @LINE + 1]]:7: error: Expected closing bracket ']' after address space specification
-  let Prototype = "_Constant [[addrspace[6 int* (int , double*)";
-  let Spellings = ["__builtin_test_addrspace_attribute_04"];
-}
-#endif
-
-#ifdef ERROR_EXPECTED_I
-def : Builtin {
-// ERROR_EXPECTED_I: :[[# @LINE + 1]]:7: error: Expected closing brackets ']]' for attribute list
-  let Prototype = "_Constant [[addrspace[6] int* (int , double*)";
-  let Spellings = ["__builtin_test_addrspace_attribute_04"];
-}
-#endif
-
-#ifdef ERROR_EXPECTED_J
-def : Builtin {
-// ERROR_EXPECTED_J: :[[# @LINE + 1]]:7: error: Unknown attribute name specified
-  let Prototype = "_Constant [[invalid]] int* (int , double*)";
+  let Prototype = "_Constant int (int , double*)";
   let Spellings = ["__builtin_test_addrspace_attribute_04"];
+  let Attributes = [AddressSpace<1, 7>];
 }
 #endif
diff --git a/clang/utils/TableGen/ClangBuiltinsEmitter.cpp b/clang/utils/TableGen/ClangBuiltinsEmitter.cpp
index c088806795079c..3d5a6f7adc7a09 100644
--- a/clang/utils/TableGen/ClangBuiltinsEmitter.cpp
+++ b/clang/utils/TableGen/ClangBuiltinsEmitter.cpp
@@ -31,6 +31,7 @@ class PrototypeParser {
 public:
   PrototypeParser(StringRef Substitution, const Record *Builtin)
       : Loc(Builtin->getFieldLoc("Prototype")), Substitution(Substitution) {
+    populateAddrSpaceAttrMap(Builtin);
     ParsePrototype(Builtin->getValueAsString("Prototype"));
   }
 
@@ -40,31 +41,22 @@ class PrototypeParser {
     ParseTypes(Prototype);
   }
 
-  void ParseTypeAttributeList(StringRef &T, SMLoc Loc) {
-    if (T.consume_front("addrspace")) {
-      unsigned long long AS = 0;
-      if (!T.consume_front("["))
-        PrintFatalError(Loc, "Expected opening bracket '[' after 'addrspace'");
-
-      if (llvm::consumeUnsignedInteger(T, 10, AS))
-        PrintFatalError(Loc,
-                        "Expecetd valid integer for 'addrspace' attribute");
-
-      if (!T.consume_front("]"))
-        PrintFatalError(
-            Loc,
-            "Expected closing bracket ']' after address space specification");
-      AddrSpace = AS;
-    } else
-      PrintFatalError(Loc, "Unknown attribute name specified");
-
-    if (!T.consume_front("]]"))
-      PrintFatalError(Loc, "Expected closing brackets ']]' for attribute list");
+  void populateAddrSpaceAttrMap(const Record *Builtin) {
+    for (const auto *Attr : Builtin->getValueAsListOfDefs("Attributes")) {
+      if (Attr->isSubClassOf("AddressSpace")) {
+        uint32_t ArgIdx = Attr->getValueAsInt("Index");
+        uint32_t ASpaceNum = Attr->getValueAsInt("SpaceNum");
+        if (ArgToAddrSpaceMap.find(ArgIdx) != ArgToAddrSpaceMap.end())
+          PrintFatalError(Loc, "Address space attribute for argument " +
+                                   std::to_string(ArgIdx) + " repeated");
+        ArgToAddrSpaceMap[ArgIdx] = ASpaceNum;
+      }
+    }
   }
 
   void ParseTypes(StringRef &Prototype) {
     auto ReturnType = Prototype.take_until([](char c) { return c == '('; });
-    ParseTypeAndValidateAttributes(ReturnType);
+    ParseTypeAndValidateAttributes(ReturnType, /*Return type ID*/ 0);
     Prototype = Prototype.drop_front(ReturnType.size() + 1);
     if (!Prototype.ends_with(")"))
       PrintFatalError(Loc, "Expected closing brace at end of prototype");
@@ -72,7 +64,7 @@ class PrototypeParser {
 
     // Look through the input parameters.
     const size_t end = Prototype.size();
-    for (size_t I = 0; I != end;) {
+    for (size_t I = 0, CurArgIdx = 1; I != end;) {
       const StringRef Current = Prototype.substr(I, end);
       // Skip any leading space or commas
       if (Current.starts_with(" ") || Current.starts_with(",")) {
@@ -88,9 +80,11 @@ class PrototypeParser {
       // we cannot have nested _ExtVector.
       if (Current.starts_with("_ExtVector<")) {
         const size_t EndTemplate = Current.find('>', 0);
-        ParseTypeAndValidateAttributes(Current.substr(0, EndTemplate + 1));
+        ParseTypeAndValidateAttributes(Current.substr(0, EndTemplate + 1),
+                                       CurArgIdx);
         // Move the prototype beyond _ExtVector<...>
         I += EndTemplate + 1;
+        CurArgIdx++;
         continue;
       }
 
@@ -99,28 +93,31 @@ class PrototypeParser {
       if (size_t CommaPos = Current.find(',', 0)) {
         if (CommaPos != StringRef::npos) {
           StringRef T = Current.substr(0, CommaPos);
-          ParseTypeAndValidateAttributes(T);
+          ParseTypeAndValidateAttributes(T, CurArgIdx);
           // Move the prototype beyond the comma.
           I += CommaPos + 1;
+          CurArgIdx++;
           continue;
         }
       }
 
       // No more commas, parse final parameter.
-      ParseTypeAndValidateAttributes(Current);
+      ParseTypeAndValidateAttributes(Current, CurArgIdx);
       I = end;
     }
   }
 
-  void ParseTypeAndValidateAttributes(StringRef T) {
+  void ParseTypeAndValidateAttributes(StringRef T, uint32_t ArgIdx) {
+    if (ArgToAddrSpaceMap.find(ArgIdx) != ArgToAddrSpaceMap.end())
+      AddrSpace = ArgToAddrSpaceMap[ArgIdx];
     ParseType(T);
     if (!IsPointerOrReference && AddrSpace)
       PrintFatalError(
           Loc, "Address space attribute can only be specified with a pointer"
                " or reference type");
 
-    IsPointerOrReference = false;
     AddrSpace = std::nullopt;
+    IsPointerOrReference = false;
   }
 
   void ParseType(StringRef T) {
@@ -146,9 +143,6 @@ class PrototypeParser {
       IsPointerOrReference = true;
       if (AddrSpace)
         Type += std::to_string(*AddrSpace);
-    } else if (T.consume_front("[[")) {
-      ParseTypeAttributeList(T, Loc);
-      ParseType(T);
     } else if (T.consume_front("long")) {
       Type += "L";
       ParseType(T);
@@ -235,7 +229,8 @@ class PrototypeParser {
   SMLoc Loc;
   StringRef Substitution;
   std::string Type;
-  std::optional<unsigned long long> AddrSpace;
+  std::unordered_map<uint32_t, uint32_t> ArgToAddrSpaceMap;
+  std::optional<uint32_t> AddrSpace;
   bool IsPointerOrReference = false;
 };
 
@@ -279,8 +274,12 @@ void PrintAttributes(const Record *Builtin, BuiltinType BT,
 
   for (const auto *Attr : Builtin->getValueAsListOfDefs("Attributes")) {
     OS << Attr->getValueAsString("Mangling");
-    if (Attr->isSubClassOf("IndexedAttribute"))
+    if (Attr->isSubClassOf("IndexedAttribute")) {
+      // Address space attributes are already processed
+      if (Attr->isSubClassOf("AddressSpace"))
+        continue;
       OS << ':' << Attr->getValueAsInt("Index") << ':';
+    }
   }
   OS << '\"';
 }



More information about the cfe-commits mailing list