Skip to content

[clang][Builtins] Parse clang extended vectors types. #83584

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

Merged
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
115 changes: 115 additions & 0 deletions clang/test/TableGen/target-builtins-prototype-parser.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// RUN: clang-tblgen -I %p/../../../clang/include/ %s --gen-clang-builtins | FileCheck %s
// RUN: not clang-tblgen -I %p/../../../clang/include/ %s --gen-clang-builtins -DERROR_EXPECTED_LANES 2>&1 | FileCheck %s --check-prefix=ERROR_EXPECTED_LANES
// RUN: not clang-tblgen -I %p/../../../clang/include/ %s --gen-clang-builtins -DERROR_EXPECTED_COMMA 2>&1 | FileCheck %s --check-prefix=ERROR_EXPECTED_COMMA
// RUN: not clang-tblgen -I %p/../../../clang/include/ %s --gen-clang-builtins -DERROR_EXPECTED_TYPE 2>&1 | FileCheck %s --check-prefix=ERROR_EXPECTED_TYPE
// RUN: not clang-tblgen -I %p/../../../clang/include/ %s --gen-clang-builtins -DERROR_EXPECTED_A 2>&1 | FileCheck %s --check-prefix=ERROR_EXPECTED_A
// RUN: not clang-tblgen -I %p/../../../clang/include/ %s --gen-clang-builtins -DERROR_EXPECTED_B 2>&1 | FileCheck %s --check-prefix=ERROR_EXPECTED_B
// RUN: not clang-tblgen -I %p/../../../clang/include/ %s --gen-clang-builtins -DERROR_EXPECTED_C 2>&1 | FileCheck %s --check-prefix=ERROR_EXPECTED_C
// RUN: not clang-tblgen -I %p/../../../clang/include/ %s --gen-clang-builtins -DERROR_EXPECTED_D 2>&1 | FileCheck %s --check-prefix=ERROR_EXPECTED_D

include "clang/Basic/BuiltinsBase.td"

def : Builtin {
// CHECK: BUILTIN(__builtin_01, "E8idE4b", "")
let Prototype = "_ExtVector<8,int>(double, _ExtVector<4, bool>)";
let Spellings = ["__builtin_01"];
}

def : Builtin {
// CHECK: BUILTIN(__builtin_02, "E8UiE4s", "")
let Prototype = "_ExtVector<8,unsigned int>(_ExtVector<4, short>)";
let Spellings = ["__builtin_02"];
}

def : Builtin {
// CHECK: BUILTIN(__builtin_03, "di", "")
let Prototype = "double(int)";
let Spellings = ["__builtin_03"];
}

def : Builtin {
// CHECK: BUILTIN(__builtin_04, "diIUi", "")
let Prototype = "double(int, _Constant unsigned int)";
let Spellings = ["__builtin_04"];
}

def : Builtin {
// CHECK: BUILTIN(__builtin_05, "v&v&", "")
let Prototype = "void&(void&)";
let Spellings = ["__builtin_05"];
}

def : Builtin {
// CHECK: BUILTIN(__builtin_06, "v*v*cC*.", "")
let Prototype = "void*(void*, char const*, ...)";
let Spellings = ["__builtin_06"];
}

def : Builtin {
// CHECK: BUILTIN(__builtin_07, "E8iE4dE4b.", "")
let Prototype = "_ExtVector<8, int>(_ExtVector<4,double>, _ExtVector<4, bool>, ...)";
let Spellings = ["__builtin_07"];
}

def : Builtin {
// CHECK: BUILTIN(__builtin_08, "di*R", "")
let Prototype = "double(int * restrict)";
let Spellings = ["__builtin_08"];
}

#ifdef ERROR_EXPECTED_LANES
def : Builtin {
// ERROR_EXPECTED_LANES: :[[# @LINE + 1]]:7: error: Expected number of lanes after '_ExtVector<'
let Prototype = "_ExtVector<int>(double)";
let Spellings = ["__builtin_test_use_clang_extended_vectors"];
}
#endif

#ifdef ERROR_EXPECTED_COMMA
def : Builtin {
// ERROR_EXPECTED_COMMA: :[[# @LINE + 1]]:7: error: Expected ',' after number of lanes in '_ExtVector<'
let Prototype = "_ExtVector<8 int>(double)";
let Spellings = ["__builtin_test_use_clang_extended_vectors"];
}
#endif

#ifdef ERROR_EXPECTED_TYPE
def : Builtin {
// ERROR_EXPECTED_TYPE: :[[# @LINE + 1]]:7: error: Expected '>' after scalar type in '_ExtVector<N, type>'
let Prototype = "_ExtVector<8, int (double)";
let Spellings = ["__builtin_test_use_clang_extended_vectors"];
}
#endif

#ifdef ERROR_EXPECTED_A
def : Builtin {
// ERROR_EXPECTED_A: :[[# @LINE + 1]]:7: error: Expected '<' after '_ExtVector'
let Prototype = "_ExtVector(8, int) (double)";
let Spellings = ["__builtin_test_use_clang_extended_vectors"];
}
#endif

#ifdef ERROR_EXPECTED_B
def : Builtin {
// ERROR_EXPECTED_B: :[[# @LINE + 1]]:7: error: Expected '<' after '_ExtVector'
let Prototype = "double(_ExtVector(8, int))";
let Spellings = ["__builtin_test_use_clang_extended_vectors"];
}
#endif

#ifdef ERROR_EXPECTED_C
def : Builtin {
// ERROR_EXPECTED_C: :[[# @LINE + 1]]:7: error: Unknown Type: _EtxVector<8, int>
let Prototype = "_EtxVector<8, int>(void)";
let Spellings = ["__builtin_test_use_clang_extended_vectors"];
}
#endif

#ifdef ERROR_EXPECTED_D
def : Builtin {
// ERROR_EXPECTED_D: :[[# @LINE + 1]]:7: error: Expected number of lanes after '_ExtVector<'
let Prototype = "_ExtVector<>(void)";
let Spellings = ["__builtin_test_use_clang_extended_vectors"];
}
#endif

66 changes: 63 additions & 3 deletions clang/utils/TableGen/ClangBuiltinsEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,47 @@ class PrototypeParser {
if (!Prototype.ends_with(")"))
PrintFatalError(Loc, "Expected closing brace at end of prototype");
Prototype = Prototype.drop_back();
for (auto T = Prototype.split(','); !T.first.empty();
Prototype = T.second, T = Prototype.split(','))
ParseType(T.first);

// Look through the input parameters.
const size_t end = Prototype.size();
for (size_t I = 0; I != end;) {
const StringRef Current = Prototype.substr(I, end);
// Skip any leading space or commas
if (Current.starts_with(" ") || Current.starts_with(",")) {
++I;
continue;
}

// Check if we are in _ExtVector. We do this first because
// extended vectors are written in template form with the syntax
// _ExtVector< ..., ...>, so we need to make sure we are not
// detecting the comma of the template class as a separator for
// the parameters of the prototype. Note: the assumption is that
// we cannot have nested _ExtVector.
if (Current.starts_with("_ExtVector<")) {
const size_t EndTemplate = Current.find('>', 0);
ParseType(Current.substr(0, EndTemplate + 1));
// Move the prototype beyond _ExtVector<...>
I += EndTemplate + 1;
continue;
}

// We know that we are past _ExtVector, therefore the first seen
// comma is the boundary of a parameter in the prototype.
if (size_t CommaPos = Current.find(',', 0)) {
if (CommaPos != StringRef::npos) {
StringRef T = Current.substr(0, CommaPos);
ParseType(T);
// Move the prototype beyond the comma.
I += CommaPos + 1;
continue;
}
}

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

void ParseType(StringRef T) {
Expand Down Expand Up @@ -85,6 +123,28 @@ class PrototypeParser {
if (Substitution.empty())
PrintFatalError(Loc, "Not a template");
ParseType(Substitution);
} else if (T.consume_front("_ExtVector")) {
// Clang extended vector types are mangled as follows:
//
// '_ExtVector<' <lanes> ',' <scalar type> '>'

// Before parsing T(=<scalar type>), make sure the syntax of
// `_ExtVector<N, T>` is correct...
if (!T.consume_front("<"))
PrintFatalError(Loc, "Expected '<' after '_ExtVector'");
unsigned long long Lanes;
if (llvm::consumeUnsignedInteger(T, 10, Lanes))
PrintFatalError(Loc, "Expected number of lanes after '_ExtVector<'");
Type += "E" + std::to_string(Lanes);
if (!T.consume_front(","))
PrintFatalError(Loc,
"Expected ',' after number of lanes in '_ExtVector<'");
if (!T.consume_back(">"))
PrintFatalError(
Loc, "Expected '>' after scalar type in '_ExtVector<N, type>'");

// ...all good, we can check if we have a valid `<scalar type>`.
ParseType(T);
} else {
auto ReturnTypeVal = StringSwitch<std::string>(T)
.Case("__builtin_va_list_ref", "A")
Expand Down