Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/BuiltinsBase.td
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of taking an int for the second argument, I think it would make more sense to do:

class AddressSpace<int AddrSpaceValue> {
  int SpaceNum = AddrSpaceValue;
}

// Use whatever the correct values are, I just used random numbers
def Global : AddressSpace<12>;
def Constant : AddressSpace<1002>;

class ArgWithAddressSpace<int ArgIdx, AddressSpace Num> : IndexedAttribute<"", ArgIdx< {
  AddressSpace AddrSpace = Num;
}
...
let Attributes = [ArgWithAddressSpace<0, Global>, NoThrow];

WDYT?

int SpaceNum = AddrSpaceNum;
}

// Builtin kinds
// =============

Expand Down
40 changes: 40 additions & 0 deletions clang/test/TableGen/target-builtins-prototype-parser.td
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
// 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

include "clang/Basic/BuiltinsBase.td"

Expand Down Expand Up @@ -113,3 +115,41 @@ def : Builtin {
}
#endif

def : Builtin {
// CHECK: BUILTIN(__builtin_test_addrspace_attribute_01, "di*3", "")
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", "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", "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: 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 int (int , double*)";
let Spellings = ["__builtin_test_addrspace_attribute_04"];
let Attributes = [AddressSpace<1, 7>];
}
#endif
55 changes: 49 additions & 6 deletions clang/utils/TableGen/ClangBuiltinsEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
}

Expand All @@ -40,17 +41,30 @@ class PrototypeParser {
ParseTypes(Prototype);
}

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 == '('; });
ParseType(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");
Prototype = Prototype.drop_back();

// 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(",")) {
Expand All @@ -66,9 +80,11 @@ 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),
CurArgIdx);
// Move the prototype beyond _ExtVector<...>
I += EndTemplate + 1;
CurArgIdx++;
continue;
}

Expand All @@ -77,24 +93,41 @@ class PrototypeParser {
if (size_t CommaPos = Current.find(',', 0)) {
if (CommaPos != StringRef::npos) {
StringRef T = Current.substr(0, CommaPos);
ParseType(T);
ParseTypeAndValidateAttributes(T, CurArgIdx);
// Move the prototype beyond the comma.
I += CommaPos + 1;
CurArgIdx++;
continue;
}
}

// No more commas, parse final parameter.
ParseType(Current);
ParseTypeAndValidateAttributes(Current, CurArgIdx);
I = end;
}
}

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");

AddrSpace = std::nullopt;
IsPointerOrReference = false;
}

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";
Expand All @@ -107,6 +140,9 @@ class PrototypeParser {
} else if (T.consume_back("&")) {
ParseType(T);
Type += "&";
IsPointerOrReference = true;
if (AddrSpace)
Type += std::to_string(*AddrSpace);
} else if (T.consume_front("long")) {
Type += "L";
ParseType(T);
Expand Down Expand Up @@ -193,6 +229,9 @@ class PrototypeParser {
SMLoc Loc;
StringRef Substitution;
std::string Type;
std::unordered_map<uint32_t, uint32_t> ArgToAddrSpaceMap;
std::optional<uint32_t> AddrSpace;
bool IsPointerOrReference = false;
};

class HeaderNameParser {
Expand Down Expand Up @@ -234,8 +273,12 @@ void PrintAttributes(const Record *Builtin, BuiltinType BT, raw_ostream &OS) {

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 << '\"';
}
Expand Down