Skip to content

Commit

Permalink
[clang][Builtins] Parse clang extended vectors types. (#83584)
Browse files Browse the repository at this point in the history
Clang extended vector types are mangled as follows:

    '_ExtVector<' <lanes> ',' <scalar type> '>'

This is used to defetmine the builtins signature for builtins that
use parameters defined as

    typedef <scalar type> ext_vector_type_<lanes>_<scalar type> __attribute__((ext_vector_type(<lanes>)))

or 

    template <unsigned N, class T>
    using _ExtVector __attribute__((ext_vector_type(N))) = T;

For example:

    typedef double ext_vector_type_4_double __attribute__((ext_vector_type(4)))
  • Loading branch information
fpetrogalli authored Mar 5, 2024
1 parent 80f9458 commit 9b672de
Show file tree
Hide file tree
Showing 2 changed files with 178 additions and 3 deletions.
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

0 comments on commit 9b672de

Please sign in to comment.