diff --git a/clang/test/TableGen/target-builtins-prototype-parser.td b/clang/test/TableGen/target-builtins-prototype-parser.td new file mode 100644 index 0000000000000..3d6c92341ac43 --- /dev/null +++ b/clang/test/TableGen/target-builtins-prototype-parser.td @@ -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(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' + 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 + diff --git a/clang/utils/TableGen/ClangBuiltinsEmitter.cpp b/clang/utils/TableGen/ClangBuiltinsEmitter.cpp index 48f55b8af97e4..94f12a08164fd 100644 --- a/clang/utils/TableGen/ClangBuiltinsEmitter.cpp +++ b/clang/utils/TableGen/ClangBuiltinsEmitter.cpp @@ -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) { @@ -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<' ',' '>' + + // Before parsing T(=), make sure the syntax of + // `_ExtVector` 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'"); + + // ...all good, we can check if we have a valid ``. + ParseType(T); } else { auto ReturnTypeVal = StringSwitch(T) .Case("__builtin_va_list_ref", "A")