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

Vikram Hegde via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 12 22:44:53 PDT 2024


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

this is a follow up from the discussion in https://github.com/llvm/llvm-project/pull/86801 (apologies for the long delay...). 
This PR proposes a way to specify address spaces in builtin prototypes. The idea is to specify address space numbers using CXX11 attribute list syntax ([[<attr_list>]]) with following limitations,
1. The attribute [[addrspace[n]]] is strictly a "prefix" to the builtin type, i.e something as follows is not accepted,
     int* const [[addrspace[3]]] ;
2. I really wanted the syntax to be like [[addrspace(n)]] but '(' token conflicts with function signature. so current approach is to use "[[addrspace[n]]]"
3. The attribute is only valid with pointer and reference types (as per the restriction imposed by .def files)

I would like some views on this approach and alternate suggestions if any. Also please let me know if there are any parallel efforts towards this which I might not be aware of.

>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] [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 {



More information about the cfe-commits mailing list