[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:
Nikolas Klauser
2024-01-24 11:22:43 +01:00
committed by GitHub
parent cd7ea4ea65
commit 4a58284559
23 changed files with 5089 additions and 1774 deletions

View File

@@ -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

View File

@@ -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
};

File diff suppressed because it is too large Load Diff

View File

@@ -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

View 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(...)";
}

View 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;
}

View File

@@ -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

View File

@@ -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
};
}

View File

@@ -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"

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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,

View File

@@ -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 {

View File

@@ -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 ||

View File

@@ -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();

View File

@@ -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)

View File

@@ -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: *

View File

@@ -7,6 +7,7 @@ add_tablegen(clang-tblgen CLANG
ClangASTNodesEmitter.cpp
ClangASTPropertiesEmitter.cpp
ClangAttrEmitter.cpp
ClangBuiltinsEmitter.cpp
ClangCommentCommandInfoEmitter.cpp
ClangCommentHTMLNamedCharacterReferenceEmitter.cpp
ClangCommentHTMLTagsEmitter.cpp

View 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++";
}

View File

@@ -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.

View File

@@ -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;

View File

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