[clang] Refactor Builtins.def to be a tablegen file (#68324)
This makes the builtins list quite a bit more verbose, but IMO this is a huge win in terms of readability.
This commit is contained in:
@@ -6410,7 +6410,7 @@ public:
|
||||
enum AtomicOp {
|
||||
#define BUILTIN(ID, TYPE, ATTRS)
|
||||
#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) AO ## ID,
|
||||
#include "clang/Basic/Builtins.def"
|
||||
#include "clang/Basic/Builtins.inc"
|
||||
// Avoid trailing comma
|
||||
BI_First = 0
|
||||
};
|
||||
@@ -6476,7 +6476,7 @@ public:
|
||||
#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \
|
||||
case AO##ID: \
|
||||
return #ID;
|
||||
#include "clang/Basic/Builtins.def"
|
||||
#include "clang/Basic/Builtins.inc"
|
||||
}
|
||||
llvm_unreachable("not an atomic operator?");
|
||||
}
|
||||
@@ -6505,8 +6505,8 @@ public:
|
||||
}
|
||||
|
||||
bool isOpenCL() const {
|
||||
return getOp() >= AO__opencl_atomic_init &&
|
||||
getOp() <= AO__opencl_atomic_fetch_max;
|
||||
return getOp() >= AO__opencl_atomic_compare_exchange_strong &&
|
||||
getOp() <= AO__opencl_atomic_store;
|
||||
}
|
||||
|
||||
SourceLocation getBuiltinLoc() const { return BuiltinLoc; }
|
||||
@@ -6531,11 +6531,14 @@ public:
|
||||
/// \return empty atomic scope model if the atomic op code does not have
|
||||
/// scope operand.
|
||||
static std::unique_ptr<AtomicScopeModel> getScopeModel(AtomicOp Op) {
|
||||
if (Op >= AO__opencl_atomic_load && Op <= AO__opencl_atomic_fetch_max)
|
||||
// FIXME: Allow grouping of builtins to be able to only check >= and <=
|
||||
if (Op >= AO__opencl_atomic_compare_exchange_strong &&
|
||||
Op <= AO__opencl_atomic_store && Op != AO__opencl_atomic_init)
|
||||
return AtomicScopeModel::create(AtomicScopeModelKind::OpenCL);
|
||||
else if (Op >= AO__hip_atomic_load && Op <= AO__hip_atomic_fetch_max)
|
||||
if (Op >= AO__hip_atomic_compare_exchange_strong &&
|
||||
Op <= AO__hip_atomic_store)
|
||||
return AtomicScopeModel::create(AtomicScopeModelKind::HIP);
|
||||
else if (Op >= AO__scoped_atomic_load && Op <= AO__scoped_atomic_fetch_max)
|
||||
if (Op >= AO__scoped_atomic_add_fetch && Op <= AO__scoped_atomic_xor_fetch)
|
||||
return AtomicScopeModel::create(AtomicScopeModelKind::Generic);
|
||||
return AtomicScopeModel::create(AtomicScopeModelKind::None);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -64,7 +64,7 @@ namespace Builtin {
|
||||
enum ID {
|
||||
NotBuiltin = 0, // This is not a builtin function.
|
||||
#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
|
||||
#include "clang/Basic/Builtins.def"
|
||||
#include "clang/Basic/Builtins.inc"
|
||||
FirstTSBuiltin
|
||||
};
|
||||
|
||||
|
||||
4537
clang/include/clang/Basic/Builtins.td
Normal file
4537
clang/include/clang/Basic/Builtins.td
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,33 +0,0 @@
|
||||
//===--- BuiltinsBPF.def - BPF Builtin function database --------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the BPF-specific builtin function database. Users of
|
||||
// this file must define the BUILTIN macro to make use of this information.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// The format of this database matches clang/Basic/Builtins.def.
|
||||
|
||||
#if defined(BUILTIN) && !defined(TARGET_BUILTIN)
|
||||
# define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BUILTIN(ID, TYPE, ATTRS)
|
||||
#endif
|
||||
|
||||
// Get record field information.
|
||||
TARGET_BUILTIN(__builtin_preserve_field_info, "Ui.", "t", "")
|
||||
|
||||
// Get BTF type id.
|
||||
TARGET_BUILTIN(__builtin_btf_type_id, "LUi.", "t", "")
|
||||
|
||||
// Get type information.
|
||||
TARGET_BUILTIN(__builtin_preserve_type_info, "Ui.", "t", "")
|
||||
|
||||
// Preserve enum value.
|
||||
TARGET_BUILTIN(__builtin_preserve_enum_value, "Li.", "t", "")
|
||||
|
||||
#undef BUILTIN
|
||||
#undef TARGET_BUILTIN
|
||||
37
clang/include/clang/Basic/BuiltinsBPF.td
Normal file
37
clang/include/clang/Basic/BuiltinsBPF.td
Normal file
@@ -0,0 +1,37 @@
|
||||
//===--- BuiltinsBPF.td - BPF Builtin function database ---------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
include "clang/Basic/BuiltinsBase.td"
|
||||
|
||||
// Get record field information
|
||||
def PreserveFieldInfo : TargetBuiltin {
|
||||
let Spellings = ["__builtin_preserve_field_info"];
|
||||
let Attributes = [CustomTypeChecking];
|
||||
let Prototype = "unsigned int(...)";
|
||||
}
|
||||
|
||||
// Get BTF type id
|
||||
def BtfTypeID : TargetBuiltin {
|
||||
let Spellings = ["__builtin_btf_type_id"];
|
||||
let Attributes = [CustomTypeChecking];
|
||||
let Prototype = "long unsigned int(...)";
|
||||
}
|
||||
|
||||
// Get type information
|
||||
def PreserveTypeInfo : TargetBuiltin {
|
||||
let Spellings = ["__builtin_preserve_type_info"];
|
||||
let Attributes = [CustomTypeChecking];
|
||||
let Prototype = "long unsigned int(...)";
|
||||
}
|
||||
|
||||
// Preserve enum value
|
||||
def PreserveEnumValue : TargetBuiltin {
|
||||
let Spellings = ["__builtin_preserve_enum_value"];
|
||||
let Attributes = [CustomTypeChecking];
|
||||
let Prototype = "long int(...)";
|
||||
}
|
||||
121
clang/include/clang/Basic/BuiltinsBase.td
Normal file
121
clang/include/clang/Basic/BuiltinsBase.td
Normal file
@@ -0,0 +1,121 @@
|
||||
//===--- BuiltinsBase.td - common structured used by builtins ---*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Attributes
|
||||
// ==========
|
||||
|
||||
class Attribute<string mangling> {
|
||||
string Mangling = mangling;
|
||||
}
|
||||
|
||||
class IndexedAttribute<string baseMangling, int I> : Attribute<baseMangling> {
|
||||
int Index = I;
|
||||
}
|
||||
|
||||
// Standard Attributes
|
||||
// -------------------
|
||||
def NoReturn : Attribute<"r">;
|
||||
|
||||
// Attributes from the gnu:: namespace
|
||||
// -----------------------------------
|
||||
def Const : Attribute<"c">;
|
||||
def NoThrow : Attribute<"n">;
|
||||
def Pure : Attribute<"U">;
|
||||
def ReturnsTwice : Attribute<"j">;
|
||||
// FIXME: gcc has nonnull
|
||||
|
||||
// builtin-specific attributes
|
||||
// ---------------------------
|
||||
|
||||
// Signature is meaningless, use custom typechecking.
|
||||
def CustomTypeChecking : Attribute<"t">;
|
||||
|
||||
// Type is not important to semantic analysis and codegen; recognize as builtin
|
||||
// even if type doesn't match signature, and don't warn if we can't be sure the
|
||||
// type is right.
|
||||
def IgnoreSignature : Attribute<"T">;
|
||||
|
||||
// Arguments are not evaluated for their side-effects.
|
||||
def UnevaluatedArguments : Attribute<"u">;
|
||||
|
||||
// FIXME: This is misused in a lot of the places it is used currently.
|
||||
// This function is equivalent to a library function without the __builtin_
|
||||
// prefix. This is relevant for CodeGen; it should not be used if custom CodeGen
|
||||
// is required for a builtin.
|
||||
def FunctionWithBuiltinPrefix : Attribute<"F">;
|
||||
|
||||
// const, but only when -fno-math-errno and FP exceptions are ignored.
|
||||
def ConstIgnoringErrnoAndExceptions : Attribute<"e">;
|
||||
|
||||
// const when FP exceptions are ignored.
|
||||
def ConstIgnoringExceptions : Attribute<"g">;
|
||||
|
||||
// This function requires a specific header or an explicit declaration.
|
||||
def RequireDeclaration : Attribute<"h">;
|
||||
|
||||
class PrintfFormat<int I> : IndexedAttribute<"p", I>;
|
||||
class VPrintfFormat<int I> : IndexedAttribute<"P", I>;
|
||||
class ScanfFormat<int I> : IndexedAttribute<"s", I>;
|
||||
class VScanfFormat<int I> : IndexedAttribute<"S", I>;
|
||||
|
||||
// Other Attributes
|
||||
// ----------------
|
||||
|
||||
// Builtin can be constant evaluated
|
||||
def Constexpr : Attribute<"E">;
|
||||
|
||||
// Builtin kinds
|
||||
// =============
|
||||
|
||||
class Builtin {
|
||||
list<string> Spellings;
|
||||
list<Attribute> Attributes = [];
|
||||
string Prototype;
|
||||
string Namespace;
|
||||
// On some platforms, some functions are actually macros. In that case we need
|
||||
// to #undef them.
|
||||
bit RequiresUndef = 0;
|
||||
}
|
||||
|
||||
class CustomEntry {
|
||||
string Entry;
|
||||
}
|
||||
|
||||
class AtomicBuiltin : Builtin;
|
||||
class TargetBuiltin : Builtin;
|
||||
|
||||
class LibBuiltin<string header, string languages = "ALL_LANGUAGES"> : Builtin {
|
||||
string Header = header;
|
||||
string Languages = languages;
|
||||
bit AddBuiltinPrefixedAlias = 0;
|
||||
bit OnlyBuiltinPrefixedAliasIsConstexpr = 0;
|
||||
}
|
||||
|
||||
class MSLibBuiltin<string header> : LibBuiltin<header, "ALL_MS_LANGUAGES">;
|
||||
class GNULibBuiltin<string header> : LibBuiltin<header, "ALL_GNU_LANGUAGES">;
|
||||
class ObjCLibBuiltin<string header> : LibBuiltin<header, "OBJC_LANG">;
|
||||
class CxxLibBuiltin<string header> : LibBuiltin<header, "CXX_LANG">;
|
||||
|
||||
class LangBuiltin<string languages> : Builtin {
|
||||
string Languages = languages;
|
||||
}
|
||||
|
||||
class MSLangBuiltin : LangBuiltin<"ALL_MS_LANGUAGES">;
|
||||
class CoroLangBuiltin : LangBuiltin<"COR_LANG">;
|
||||
class OCLPipeLangBuiltin : LangBuiltin<"OCL_PIPE">;
|
||||
class OCL_DSELangBuiltin : LangBuiltin<"OCL_DSE">;
|
||||
class OCL_GASLangBuiltin : LangBuiltin<"OCL_GAS">;
|
||||
class OCLLangBuiltin : LangBuiltin<"ALL_OCL_LANGUAGES">;
|
||||
|
||||
class Template<list<string> substitutions,
|
||||
list<string> affixes,
|
||||
bit as_prefix = 0> {
|
||||
list<string> Substitutions = substitutions;
|
||||
list<string> Affixes = affixes;
|
||||
bit AsPrefix = as_prefix;
|
||||
}
|
||||
@@ -57,6 +57,14 @@ clang_tablegen(AttrHasAttributeImpl.inc -gen-clang-attr-has-attribute-impl
|
||||
TARGET ClangAttrHasAttributeImpl
|
||||
)
|
||||
|
||||
clang_tablegen(Builtins.inc -gen-clang-builtins
|
||||
SOURCE Builtins.td
|
||||
TARGET ClangBuiltins)
|
||||
|
||||
clang_tablegen(BuiltinsBPF.inc -gen-clang-builtins
|
||||
SOURCE BuiltinsBPF.td
|
||||
TARGET ClangBuiltinsBPF)
|
||||
|
||||
# ARM NEON and MVE
|
||||
clang_tablegen(arm_neon.inc -gen-arm-neon-sema
|
||||
SOURCE arm_neon.td
|
||||
|
||||
@@ -84,7 +84,7 @@ namespace clang {
|
||||
enum {
|
||||
LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1,
|
||||
#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
|
||||
#include "clang/Basic/BuiltinsBPF.def"
|
||||
#include "clang/Basic/BuiltinsBPF.inc"
|
||||
LastTSBuiltin
|
||||
};
|
||||
}
|
||||
|
||||
@@ -42,8 +42,6 @@ module Clang_Basic {
|
||||
textual header "clang/Basic/BuiltinsAArch64NeonSVEBridge.def"
|
||||
textual header "clang/Basic/BuiltinsAArch64NeonSVEBridge_cg.def"
|
||||
textual header "clang/Basic/BuiltinsARM.def"
|
||||
textual header "clang/Basic/BuiltinsBPF.def"
|
||||
textual header "clang/Basic/Builtins.def"
|
||||
textual header "clang/Basic/BuiltinHeaders.def"
|
||||
textual header "clang/Basic/BuiltinsHexagon.def"
|
||||
textual header "clang/Basic/BuiltinsHexagonDep.def"
|
||||
|
||||
@@ -1833,7 +1833,7 @@ void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) {
|
||||
case AtomicExpr::AO ## ID: \
|
||||
Name = #ID "("; \
|
||||
break;
|
||||
#include "clang/Basic/Builtins.def"
|
||||
#include "clang/Basic/Builtins.inc"
|
||||
}
|
||||
OS << Name;
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ static constexpr Builtin::Info BuiltinInfo[] = {
|
||||
{#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, LANGS},
|
||||
#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, LANGS) \
|
||||
{#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, LANGS},
|
||||
#include "clang/Basic/Builtins.def"
|
||||
#include "clang/Basic/Builtins.inc"
|
||||
};
|
||||
|
||||
const Builtin::Info &Builtin::Context::getRecord(unsigned ID) const {
|
||||
|
||||
@@ -22,7 +22,7 @@ using namespace clang::targets;
|
||||
static constexpr Builtin::Info BuiltinInfo[] = {
|
||||
#define BUILTIN(ID, TYPE, ATTRS) \
|
||||
{#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
|
||||
#include "clang/Basic/BuiltinsBPF.def"
|
||||
#include "clang/Basic/BuiltinsBPF.inc"
|
||||
};
|
||||
|
||||
void BPFTargetInfo::getTargetDefines(const LangOptions &Opts,
|
||||
|
||||
@@ -936,7 +936,7 @@ def : Builtin<"read_mem_fence", [Void, MemFenceFlags]>;
|
||||
def : Builtin<"write_mem_fence", [Void, MemFenceFlags]>;
|
||||
|
||||
// OpenCL v3.0 s6.15.10 - Address Space Qualifier Functions.
|
||||
// to_global, to_local, to_private are declared in Builtins.def.
|
||||
// to_global, to_local, to_private are declared in Builtins.td.
|
||||
|
||||
let Extension = FuncExtOpenCLCGenericAddressSpace in {
|
||||
// The OpenCL 3.0 specification defines these with a "gentype" argument indicating any builtin
|
||||
@@ -1448,25 +1448,25 @@ let Extension = FuncExtOpenCLCWGCollectiveFunctions in {
|
||||
//--------------------------------------------------------------------
|
||||
// OpenCL2.0 : 6.13.16 : Pipe Functions
|
||||
// --- Table 27 ---
|
||||
// Defined in Builtins.def
|
||||
// Defined in Builtins.td
|
||||
|
||||
// --- Table 28 ---
|
||||
// Builtins taking pipe arguments are defined in Builtins.def
|
||||
// Builtins taking pipe arguments are defined in Builtins.td
|
||||
let Extension = FuncExtOpenCLCPipes in {
|
||||
def : Builtin<"is_valid_reserve_id", [Bool, ReserveId]>;
|
||||
}
|
||||
|
||||
// --- Table 29 ---
|
||||
// Defined in Builtins.def
|
||||
// Defined in Builtins.td
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// OpenCL2.0 : 6.13.17 : Enqueuing Kernels
|
||||
// --- Table 30 ---
|
||||
// Defined in Builtins.def
|
||||
// Defined in Builtins.td
|
||||
|
||||
// --- Table 32 ---
|
||||
// Defined in Builtins.def
|
||||
// Defined in Builtins.td
|
||||
|
||||
// --- Table 33 ---
|
||||
let Extension = FuncExtOpenCLCDeviceEnqueue in {
|
||||
|
||||
@@ -2471,7 +2471,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
|
||||
#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \
|
||||
case Builtin::BI##ID: \
|
||||
return SemaAtomicOpsOverloaded(TheCallResult, AtomicExpr::AO##ID);
|
||||
#include "clang/Basic/Builtins.def"
|
||||
#include "clang/Basic/Builtins.inc"
|
||||
case Builtin::BI__annotation:
|
||||
if (SemaBuiltinMSVCAnnotation(*this, TheCall))
|
||||
return ExprError();
|
||||
@@ -7869,18 +7869,18 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
|
||||
static_assert(sizeof(NumArgs)/sizeof(NumArgs[0]) == NumForm
|
||||
&& sizeof(NumVals)/sizeof(NumVals[0]) == NumForm,
|
||||
"need to update code for modified forms");
|
||||
static_assert(AtomicExpr::AO__c11_atomic_init == 0 &&
|
||||
AtomicExpr::AO__c11_atomic_fetch_min + 1 ==
|
||||
AtomicExpr::AO__atomic_load,
|
||||
static_assert(AtomicExpr::AO__atomic_add_fetch == 0 &&
|
||||
AtomicExpr::AO__atomic_xor_fetch + 1 ==
|
||||
AtomicExpr::AO__c11_atomic_compare_exchange_strong,
|
||||
"need to update code for modified C11 atomics");
|
||||
bool IsOpenCL = Op >= AtomicExpr::AO__opencl_atomic_init &&
|
||||
Op <= AtomicExpr::AO__opencl_atomic_fetch_max;
|
||||
bool IsHIP = Op >= AtomicExpr::AO__hip_atomic_load &&
|
||||
Op <= AtomicExpr::AO__hip_atomic_fetch_max;
|
||||
bool IsScoped = Op >= AtomicExpr::AO__scoped_atomic_load &&
|
||||
Op <= AtomicExpr::AO__scoped_atomic_fetch_max;
|
||||
bool IsC11 = (Op >= AtomicExpr::AO__c11_atomic_init &&
|
||||
Op <= AtomicExpr::AO__c11_atomic_fetch_min) ||
|
||||
bool IsOpenCL = Op >= AtomicExpr::AO__opencl_atomic_compare_exchange_strong &&
|
||||
Op <= AtomicExpr::AO__opencl_atomic_store;
|
||||
bool IsHIP = Op >= AtomicExpr::AO__hip_atomic_compare_exchange_strong &&
|
||||
Op <= AtomicExpr::AO__hip_atomic_store;
|
||||
bool IsScoped = Op >= AtomicExpr::AO__scoped_atomic_add_fetch &&
|
||||
Op <= AtomicExpr::AO__scoped_atomic_xor_fetch;
|
||||
bool IsC11 = (Op >= AtomicExpr::AO__c11_atomic_compare_exchange_strong &&
|
||||
Op <= AtomicExpr::AO__c11_atomic_store) ||
|
||||
IsOpenCL;
|
||||
bool IsN = Op == AtomicExpr::AO__atomic_load_n ||
|
||||
Op == AtomicExpr::AO__atomic_store_n ||
|
||||
|
||||
@@ -7504,7 +7504,7 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
|
||||
// Extract the return type from the (builtin) function pointer type.
|
||||
// FIXME Several builtins still have setType in
|
||||
// Sema::CheckBuiltinFunctionCall. One should review their definitions in
|
||||
// Builtins.def to ensure they are correct before removing setType calls.
|
||||
// Builtins.td to ensure they are correct before removing setType calls.
|
||||
QualType FnPtrTy = Context.getPointerType(FDecl->getType());
|
||||
Result = ImpCastExprToType(Fn, FnPtrTy, CK_BuiltinFnToFnPtr).get();
|
||||
ResultTy = FDecl->getCallResultType();
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// RUN: -analyzer-checker=alpha.unix.cstring \
|
||||
// RUN: -analyzer-disable-checker=alpha.unix.cstring.UninitializedRead \
|
||||
// RUN: -analyzer-checker=debug.ExprInspection \
|
||||
// RUN: -analyzer-config eagerly-assume=false
|
||||
// RUN: -analyzer-config eagerly-assume=false
|
||||
//
|
||||
// RUN: %clang_analyze_cc1 -verify %s -DUSE_BUILTINS \
|
||||
// RUN: -analyzer-checker=core \
|
||||
@@ -131,7 +131,7 @@ void memcpy5(void) {
|
||||
|
||||
void memcpy6(void) {
|
||||
int a[4] = {0};
|
||||
memcpy(a, a, 8); // expected-warning{{overlapping}}
|
||||
memcpy(a, a, 8); // expected-warning{{overlapping}}
|
||||
}
|
||||
|
||||
void memcpy7(void) {
|
||||
@@ -257,7 +257,7 @@ void mempcpy5(void) {
|
||||
|
||||
void mempcpy6(void) {
|
||||
int a[4] = {0};
|
||||
mempcpy(a, a, 8); // expected-warning{{overlapping}}
|
||||
mempcpy(a, a, 8); // expected-warning{{overlapping}}
|
||||
}
|
||||
|
||||
void mempcpy7(void) {
|
||||
@@ -319,7 +319,7 @@ void mempcpy15(void) {
|
||||
|
||||
p1 = (&s2) + 1;
|
||||
p2 = mempcpy(&s2, &s1, sizeof(struct st));
|
||||
|
||||
|
||||
clang_analyzer_eval(p1 == p2); // expected-warning{{TRUE}}
|
||||
}
|
||||
|
||||
@@ -405,7 +405,7 @@ void memmove2 (void) {
|
||||
#define bcmp BUILTIN(bcmp)
|
||||
int bcmp(const void *s1, const void *s2, size_t n);
|
||||
#define memcmp bcmp
|
||||
//
|
||||
//
|
||||
#else /* VARIANT */
|
||||
|
||||
#define memcmp BUILTIN(memcmp)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// FIXME: pthread_create() definition in Builtins.def doesn't match the real one, so it doesn't get recognized as a builtin and attributes aren't added.
|
||||
// FIXME: pthread_create() definition in Builtins.td doesn't match the real one, so it doesn't get recognized as a builtin and attributes aren't added.
|
||||
// RUN: false
|
||||
// XFAIL: *
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ add_tablegen(clang-tblgen CLANG
|
||||
ClangASTNodesEmitter.cpp
|
||||
ClangASTPropertiesEmitter.cpp
|
||||
ClangAttrEmitter.cpp
|
||||
ClangBuiltinsEmitter.cpp
|
||||
ClangCommentCommandInfoEmitter.cpp
|
||||
ClangCommentHTMLNamedCharacterReferenceEmitter.cpp
|
||||
ClangCommentHTMLTagsEmitter.cpp
|
||||
|
||||
334
clang/utils/TableGen/ClangBuiltinsEmitter.cpp
Normal file
334
clang/utils/TableGen/ClangBuiltinsEmitter.cpp
Normal file
@@ -0,0 +1,334 @@
|
||||
//=- ClangBuiltinsEmitter.cpp - Generate Clang builtins tables -*- C++ -*-====//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This tablegen backend emits Clang's builtins tables.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "TableGenBackends.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/TableGen/Error.h"
|
||||
#include "llvm/TableGen/Record.h"
|
||||
#include "llvm/TableGen/TableGenBackend.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
enum class BuiltinType {
|
||||
Builtin,
|
||||
AtomicBuiltin,
|
||||
LibBuiltin,
|
||||
LangBuiltin,
|
||||
TargetBuiltin,
|
||||
};
|
||||
|
||||
class PrototypeParser {
|
||||
public:
|
||||
PrototypeParser(StringRef Substitution, const Record *Builtin)
|
||||
: Loc(Builtin->getFieldLoc("Prototype")), Substitution(Substitution) {
|
||||
ParsePrototype(Builtin->getValueAsString("Prototype"));
|
||||
}
|
||||
|
||||
private:
|
||||
void ParsePrototype(StringRef Prototype) {
|
||||
Prototype = Prototype.trim();
|
||||
ParseTypes(Prototype);
|
||||
}
|
||||
|
||||
void ParseTypes(StringRef &Prototype) {
|
||||
auto ReturnType = Prototype.take_until([](char c) { return c == '('; });
|
||||
ParseType(ReturnType);
|
||||
Prototype = Prototype.drop_front(ReturnType.size() + 1);
|
||||
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);
|
||||
}
|
||||
|
||||
void ParseType(StringRef T) {
|
||||
T = T.trim();
|
||||
if (T.consume_back("*")) {
|
||||
ParseType(T);
|
||||
Type += "*";
|
||||
} else if (T.consume_back("const")) {
|
||||
ParseType(T);
|
||||
Type += "C";
|
||||
} else if (T.consume_back("volatile")) {
|
||||
ParseType(T);
|
||||
Type += "D";
|
||||
} else if (T.consume_back("restrict")) {
|
||||
ParseType(T);
|
||||
Type += "R";
|
||||
} else if (T.consume_back("&")) {
|
||||
ParseType(T);
|
||||
Type += "&";
|
||||
} else if (T.consume_front("long")) {
|
||||
Type += "L";
|
||||
ParseType(T);
|
||||
} else if (T.consume_front("unsigned")) {
|
||||
Type += "U";
|
||||
ParseType(T);
|
||||
} else if (T.consume_front("_Complex")) {
|
||||
Type += "X";
|
||||
ParseType(T);
|
||||
} else if (T.consume_front("_Constant")) {
|
||||
Type += "I";
|
||||
ParseType(T);
|
||||
} else if (T.consume_front("T")) {
|
||||
if (Substitution.empty())
|
||||
PrintFatalError(Loc, "Not a template");
|
||||
ParseType(Substitution);
|
||||
} else {
|
||||
auto ReturnTypeVal = StringSwitch<std::string>(T)
|
||||
.Case("__builtin_va_list_ref", "A")
|
||||
.Case("__builtin_va_list", "a")
|
||||
.Case("__float128", "LLd")
|
||||
.Case("__fp16", "h")
|
||||
.Case("__int128_t", "LLLi")
|
||||
.Case("_Float16", "x")
|
||||
.Case("bool", "b")
|
||||
.Case("char", "c")
|
||||
.Case("constant_CFString", "F")
|
||||
.Case("double", "d")
|
||||
.Case("FILE", "P")
|
||||
.Case("float", "f")
|
||||
.Case("id", "G")
|
||||
.Case("int", "i")
|
||||
.Case("int32_t", "Zi")
|
||||
.Case("int64_t", "Wi")
|
||||
.Case("jmp_buf", "J")
|
||||
.Case("msint32_t", "Ni")
|
||||
.Case("msuint32_t", "UNi")
|
||||
.Case("objc_super", "M")
|
||||
.Case("pid_t", "p")
|
||||
.Case("ptrdiff_t", "Y")
|
||||
.Case("SEL", "H")
|
||||
.Case("short", "s")
|
||||
.Case("sigjmp_buf", "SJ")
|
||||
.Case("size_t", "z")
|
||||
.Case("ucontext_t", "K")
|
||||
.Case("uint32_t", "UZi")
|
||||
.Case("uint64_t", "UWi")
|
||||
.Case("void", "v")
|
||||
.Case("wchar_t", "w")
|
||||
.Case("...", ".")
|
||||
.Default("error");
|
||||
if (ReturnTypeVal == "error")
|
||||
PrintFatalError(Loc, "Unknown Type: " + T);
|
||||
Type += ReturnTypeVal;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void Print(llvm::raw_ostream &OS) const { OS << ", \"" << Type << '\"'; }
|
||||
|
||||
private:
|
||||
SMLoc Loc;
|
||||
StringRef Substitution;
|
||||
std::string Type;
|
||||
};
|
||||
|
||||
class HeaderNameParser {
|
||||
public:
|
||||
HeaderNameParser(const Record *Builtin) {
|
||||
for (char c : Builtin->getValueAsString("Header")) {
|
||||
if (std::islower(c))
|
||||
HeaderName += static_cast<char>(std::toupper(c));
|
||||
else if (c == '.' || c == '_' || c == '/' || c == '-')
|
||||
HeaderName += '_';
|
||||
else
|
||||
PrintFatalError(Builtin->getLoc(), "Unexpected header name");
|
||||
}
|
||||
}
|
||||
|
||||
void Print(llvm::raw_ostream &OS) const { OS << HeaderName; }
|
||||
|
||||
private:
|
||||
std::string HeaderName;
|
||||
};
|
||||
|
||||
void PrintAttributes(const Record *Builtin, BuiltinType BT,
|
||||
llvm::raw_ostream &OS) {
|
||||
OS << '\"';
|
||||
if (Builtin->isSubClassOf("LibBuiltin")) {
|
||||
if (BT == BuiltinType::LibBuiltin) {
|
||||
OS << 'f';
|
||||
} else {
|
||||
OS << 'F';
|
||||
if (Builtin->getValueAsBit("OnlyBuiltinPrefixedAliasIsConstexpr"))
|
||||
OS << 'E';
|
||||
}
|
||||
}
|
||||
|
||||
if (auto NS = Builtin->getValueAsOptionalString("Namespace")) {
|
||||
if (NS != "std")
|
||||
PrintFatalError(Builtin->getFieldLoc("Namespace"), "Unknown namespace: ");
|
||||
OS << "z";
|
||||
}
|
||||
|
||||
for (const auto *Attr : Builtin->getValueAsListOfDefs("Attributes")) {
|
||||
OS << Attr->getValueAsString("Mangling");
|
||||
if (Attr->isSubClassOf("IndexedAttribute"))
|
||||
OS << ':' << Attr->getValueAsInt("Index") << ':';
|
||||
}
|
||||
OS << '\"';
|
||||
}
|
||||
|
||||
void EmitBuiltinDef(llvm::raw_ostream &OS, StringRef Substitution,
|
||||
const Record *Builtin, Twine Spelling, BuiltinType BT) {
|
||||
if (Builtin->getValueAsBit("RequiresUndef"))
|
||||
OS << "#undef " << Spelling << '\n';
|
||||
switch (BT) {
|
||||
case BuiltinType::LibBuiltin:
|
||||
OS << "LIBBUILTIN";
|
||||
break;
|
||||
case BuiltinType::LangBuiltin:
|
||||
OS << "LANGBUILTIN";
|
||||
break;
|
||||
case BuiltinType::Builtin:
|
||||
OS << "BUILTIN";
|
||||
break;
|
||||
case BuiltinType::AtomicBuiltin:
|
||||
OS << "ATOMIC_BUILTIN";
|
||||
break;
|
||||
case BuiltinType::TargetBuiltin:
|
||||
OS << "TARGET_BUILTIN";
|
||||
break;
|
||||
}
|
||||
|
||||
OS << "(" << Spelling;
|
||||
PrototypeParser{Substitution, Builtin}.Print(OS);
|
||||
OS << ", ";
|
||||
PrintAttributes(Builtin, BT, OS);
|
||||
|
||||
switch (BT) {
|
||||
case BuiltinType::LibBuiltin: {
|
||||
OS << ", ";
|
||||
HeaderNameParser{Builtin}.Print(OS);
|
||||
[[fallthrough]];
|
||||
}
|
||||
case BuiltinType::LangBuiltin: {
|
||||
OS << ", " << Builtin->getValueAsString("Languages");
|
||||
break;
|
||||
}
|
||||
case BuiltinType::TargetBuiltin:
|
||||
OS << ", \"\"";
|
||||
break;
|
||||
case BuiltinType::AtomicBuiltin:
|
||||
case BuiltinType::Builtin:
|
||||
break;
|
||||
}
|
||||
OS << ")\n";
|
||||
}
|
||||
|
||||
struct TemplateInsts {
|
||||
std::vector<std::string> Substitution;
|
||||
std::vector<std::string> Affix;
|
||||
bool IsPrefix;
|
||||
};
|
||||
|
||||
TemplateInsts getTemplateInsts(const Record *R) {
|
||||
TemplateInsts temp;
|
||||
auto Substitutions = R->getValueAsListOfStrings("Substitutions");
|
||||
auto Affixes = R->getValueAsListOfStrings("Affixes");
|
||||
temp.IsPrefix = R->getValueAsBit("AsPrefix");
|
||||
|
||||
if (Substitutions.size() != Affixes.size())
|
||||
PrintFatalError(R->getLoc(), "Substitutions and affixes "
|
||||
"don't have the same lengths");
|
||||
|
||||
for (auto [Affix, Substitution] : llvm::zip(Affixes, Substitutions)) {
|
||||
temp.Substitution.emplace_back(Substitution);
|
||||
temp.Affix.emplace_back(Affix);
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
void EmitBuiltin(llvm::raw_ostream &OS, const Record *Builtin) {
|
||||
TemplateInsts Templates = {};
|
||||
if (Builtin->isSubClassOf("Template")) {
|
||||
Templates = getTemplateInsts(Builtin);
|
||||
} else {
|
||||
Templates.Affix.emplace_back();
|
||||
Templates.Substitution.emplace_back();
|
||||
}
|
||||
|
||||
for (auto [Substitution, Affix] :
|
||||
llvm::zip(Templates.Substitution, Templates.Affix)) {
|
||||
for (StringRef Spelling : Builtin->getValueAsListOfStrings("Spellings")) {
|
||||
auto FullSpelling =
|
||||
(Templates.IsPrefix ? Affix + Spelling : Spelling + Affix).str();
|
||||
BuiltinType BT = BuiltinType::Builtin;
|
||||
if (Builtin->isSubClassOf("AtomicBuiltin")) {
|
||||
BT = BuiltinType::AtomicBuiltin;
|
||||
} else if (Builtin->isSubClassOf("LangBuiltin")) {
|
||||
BT = BuiltinType::LangBuiltin;
|
||||
} else if (Builtin->isSubClassOf("TargetBuiltin")) {
|
||||
BT = BuiltinType::TargetBuiltin;
|
||||
} else if (Builtin->isSubClassOf("LibBuiltin")) {
|
||||
BT = BuiltinType::LibBuiltin;
|
||||
if (Builtin->getValueAsBit("AddBuiltinPrefixedAlias"))
|
||||
EmitBuiltinDef(OS, Substitution, Builtin,
|
||||
std::string("__builtin_") + FullSpelling,
|
||||
BuiltinType::Builtin);
|
||||
}
|
||||
EmitBuiltinDef(OS, Substitution, Builtin, FullSpelling, BT);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void clang::EmitClangBuiltins(llvm::RecordKeeper &Records,
|
||||
llvm::raw_ostream &OS) {
|
||||
emitSourceFileHeader("List of builtins that Clang recognizes", OS);
|
||||
|
||||
OS << R"c++(
|
||||
#if defined(BUILTIN) && !defined(LIBBUILTIN)
|
||||
# define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS)
|
||||
#endif
|
||||
|
||||
#if defined(BUILTIN) && !defined(LANGBUILTIN)
|
||||
# define LANGBUILTIN(ID, TYPE, ATTRS, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS)
|
||||
#endif
|
||||
|
||||
// Some of our atomics builtins are handled by AtomicExpr rather than
|
||||
// as normal builtin CallExprs. This macro is used for such builtins.
|
||||
#ifndef ATOMIC_BUILTIN
|
||||
# define ATOMIC_BUILTIN(ID, TYPE, ATTRS) BUILTIN(ID, TYPE, ATTRS)
|
||||
#endif
|
||||
|
||||
#if defined(BUILTIN) && !defined(TARGET_BUILTIN)
|
||||
# define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BUILTIN(ID, TYPE, ATTRS)
|
||||
#endif
|
||||
)c++";
|
||||
|
||||
// AtomicBuiltins are order dependent
|
||||
// emit them first to make manual checking easier
|
||||
for (const auto *Builtin : Records.getAllDerivedDefinitions("AtomicBuiltin"))
|
||||
EmitBuiltin(OS, Builtin);
|
||||
|
||||
for (const auto *Builtin : Records.getAllDerivedDefinitions("Builtin")) {
|
||||
if (Builtin->isSubClassOf("AtomicBuiltin"))
|
||||
continue;
|
||||
EmitBuiltin(OS, Builtin);
|
||||
}
|
||||
|
||||
for (const auto *Entry : Records.getAllDerivedDefinitions("CustomEntry")) {
|
||||
OS << Entry->getValueAsString("Entry") << '\n';
|
||||
}
|
||||
|
||||
OS << R"c++(
|
||||
#undef ATOMIC_BUILTIN
|
||||
#undef BUILTIN
|
||||
#undef LIBBUILTIN
|
||||
#undef LANGBUILTIN
|
||||
#undef TARGET_BUILTIN
|
||||
)c++";
|
||||
}
|
||||
@@ -1846,7 +1846,7 @@ void MveEmitter::EmitHeader(raw_ostream &OS) {
|
||||
// declared 'static inline' without a body, which is fine
|
||||
// provided clang recognizes them as builtins, and has the
|
||||
// effect that this type signature is used in place of the one
|
||||
// that Builtins.def didn't provide. That's how we can get
|
||||
// that Builtins.td didn't provide. That's how we can get
|
||||
// structure types that weren't defined until this header was
|
||||
// included to be part of the type signature of a builtin that
|
||||
// was known to clang already.
|
||||
|
||||
@@ -49,6 +49,7 @@ enum ActionType {
|
||||
GenClangAttrNodeTraverse,
|
||||
GenClangBasicReader,
|
||||
GenClangBasicWriter,
|
||||
GenClangBuiltins,
|
||||
GenClangDiagsDefs,
|
||||
GenClangDiagGroups,
|
||||
GenClangDiagsIndexName,
|
||||
@@ -178,6 +179,8 @@ cl::opt<ActionType> Action(
|
||||
"Generate clang attribute text node dumper"),
|
||||
clEnumValN(GenClangAttrNodeTraverse, "gen-clang-attr-node-traverse",
|
||||
"Generate clang attribute traverser"),
|
||||
clEnumValN(GenClangBuiltins, "gen-clang-builtins",
|
||||
"Generate clang builtins list"),
|
||||
clEnumValN(GenClangDiagsDefs, "gen-clang-diags-defs",
|
||||
"Generate Clang diagnostics definitions"),
|
||||
clEnumValN(GenClangDiagGroups, "gen-clang-diag-groups",
|
||||
@@ -390,6 +393,9 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
|
||||
case GenClangAttrNodeTraverse:
|
||||
EmitClangAttrNodeTraverse(Records, OS);
|
||||
break;
|
||||
case GenClangBuiltins:
|
||||
EmitClangBuiltins(Records, OS);
|
||||
break;
|
||||
case GenClangDiagsDefs:
|
||||
EmitClangDiagsDefs(Records, OS, ClangComponent);
|
||||
break;
|
||||
|
||||
@@ -75,6 +75,8 @@ void EmitClangAttrNodeTraverse(llvm::RecordKeeper &Records,
|
||||
llvm::raw_ostream &OS);
|
||||
void EmitClangAttrDocTable(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
|
||||
|
||||
void EmitClangBuiltins(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
|
||||
|
||||
void EmitClangDiagsDefs(llvm::RecordKeeper &Records, llvm::raw_ostream &OS,
|
||||
const std::string &Component);
|
||||
void EmitClangDiagGroups(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
|
||||
|
||||
Reference in New Issue
Block a user