diff options
Diffstat (limited to 'utils/TableGen/ClangTypeNodesEmitter.cpp')
-rw-r--r-- | utils/TableGen/ClangTypeNodesEmitter.cpp | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/utils/TableGen/ClangTypeNodesEmitter.cpp b/utils/TableGen/ClangTypeNodesEmitter.cpp new file mode 100644 index 000000000000..c9986c8fa496 --- /dev/null +++ b/utils/TableGen/ClangTypeNodesEmitter.cpp @@ -0,0 +1,220 @@ +//=== ClangTypeNodesEmitter.cpp - Generate type node 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 tblgen backend emits the node table (the .def file) for Clang +// type nodes. +// +// This file defines the AST type info database. Each type node is +// enumerated by providing its name (e.g., "Builtin" or "Enum") and +// base class (e.g., "Type" or "TagType"). Depending on where in the +// abstract syntax tree the type will show up, the enumeration uses +// one of five different macros: +// +// TYPE(Class, Base) - A type that can show up anywhere in the AST, +// and might be dependent, canonical, or non-canonical. All clients +// will need to understand these types. +// +// ABSTRACT_TYPE(Class, Base) - An abstract class that shows up in +// the type hierarchy but has no concrete instances. +// +// NON_CANONICAL_TYPE(Class, Base) - A type that can show up +// anywhere in the AST but will never be a part of a canonical +// type. Clients that only need to deal with canonical types +// (ignoring, e.g., typedefs and other type aliases used for +// pretty-printing) can ignore these types. +// +// DEPENDENT_TYPE(Class, Base) - A type that will only show up +// within a C++ template that has not been instantiated, e.g., a +// type that is always dependent. Clients that do not need to deal +// with uninstantiated C++ templates can ignore these types. +// +// NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) - A type that +// is non-canonical unless it is dependent. Defaults to TYPE because +// it is neither reliably dependent nor reliably non-canonical. +// +// There is a sixth macro, independent of the others. Most clients +// will not need to use it. +// +// LEAF_TYPE(Class) - A type that never has inner types. Clients +// which can operate on such types more efficiently may wish to do so. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringRef.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" +#include <set> +#include <string> +#include <vector> +#include "TableGenBackends.h" + +using namespace llvm; + +// These are spellings in the generated output. +#define TypeMacroName "TYPE" +#define AbstractTypeMacroName "ABSTRACT_TYPE" +#define DependentTypeMacroName "DEPENDENT_TYPE" +#define NonCanonicalTypeMacroName "NON_CANONICAL_TYPE" +#define NonCanonicalUnlessDependentTypeMacroName "NON_CANONICAL_UNLESS_DEPENDENT_TYPE" +#define TypeMacroArgs "(Class, Base)" +#define LastTypeMacroName "LAST_TYPE" +#define LeafTypeMacroName "LEAF_TYPE" + +// These are spellings in the tblgen file. +// (Type is also used for the spelling of the AST class.) +#define TypeClassName "Type" +#define DerivedTypeClassName "DerivedType" +#define AlwaysDependentClassName "AlwaysDependent" +#define NeverCanonicalClassName "NeverCanonical" +#define NeverCanonicalUnlessDependentClassName "NeverCanonicalUnlessDependent" +#define LeafTypeClassName "LeafType" +#define AbstractFieldName "Abstract" +#define BaseFieldName "Base" + +static StringRef getIdForType(Record *type) { + // The record name is expected to be the full C++ class name, + // including "Type". Check for that and strip it off. + auto fullName = type->getName(); + if (!fullName.endswith("Type")) + PrintFatalError(type->getLoc(), "name of Type node doesn't end in Type"); + return fullName.drop_back(4); +} + +namespace { +class TypeNodeEmitter { + RecordKeeper &Records; + raw_ostream &Out; + const std::vector<Record*> Types; + std::vector<StringRef> MacrosToUndef; + +public: + TypeNodeEmitter(RecordKeeper &records, raw_ostream &out) + : Records(records), Out(out), + Types(Records.getAllDerivedDefinitions("Type")) { + } + + void emit(); + +private: + void emitFallbackDefine(StringRef macroName, StringRef fallbackMacroName, + StringRef args); + + void emitNodeInvocations(); + void emitLastNodeInvocation(); + void emitLeafNodeInvocations(); + + void addMacroToUndef(StringRef macroName); + void emitUndefs(); +}; +} + +void TypeNodeEmitter::emit() { + if (Types.empty()) + PrintFatalError("no Type records in input!"); + + emitSourceFileHeader("An x-macro database of Clang type nodes", Out); + + // Preamble + addMacroToUndef(TypeMacroName); + addMacroToUndef(AbstractTypeMacroName); + emitFallbackDefine(AbstractTypeMacroName, TypeMacroName, TypeMacroArgs); + emitFallbackDefine(NonCanonicalTypeMacroName, TypeMacroName, TypeMacroArgs); + emitFallbackDefine(DependentTypeMacroName, TypeMacroName, TypeMacroArgs); + emitFallbackDefine(NonCanonicalUnlessDependentTypeMacroName, TypeMacroName, + TypeMacroArgs); + + // Invocations. + emitNodeInvocations(); + emitLastNodeInvocation(); + emitLeafNodeInvocations(); + + // Postmatter + emitUndefs(); +} + +void TypeNodeEmitter::emitFallbackDefine(StringRef macroName, + StringRef fallbackMacroName, + StringRef args) { + Out << "#ifndef " << macroName << "\n"; + Out << "# define " << macroName << args + << " " << fallbackMacroName << args << "\n"; + Out << "#endif\n"; + + addMacroToUndef(macroName); +} + +void TypeNodeEmitter::emitNodeInvocations() { + for (auto type : Types) { + // The name with the Type suffix. + StringRef id = getIdForType(type); + + // Figure out which macro to use. + StringRef macroName; + auto setMacroName = [&](StringRef newName) { + if (!macroName.empty()) + PrintFatalError(type->getLoc(), + Twine("conflict when computing macro name for " + "Type node: trying to use both \"") + + macroName + "\" and \"" + newName + "\""); + macroName = newName; + }; + if (type->isSubClassOf(AlwaysDependentClassName)) + setMacroName(DependentTypeMacroName); + if (type->isSubClassOf(NeverCanonicalClassName)) + setMacroName(NonCanonicalTypeMacroName); + if (type->isSubClassOf(NeverCanonicalUnlessDependentClassName)) + setMacroName(NonCanonicalUnlessDependentTypeMacroName); + if (type->getValueAsBit(AbstractFieldName)) + setMacroName(AbstractTypeMacroName); + if (macroName.empty()) + macroName = TypeMacroName; + + // Compute the base class. + StringRef baseName = TypeClassName; + if (type->isSubClassOf(DerivedTypeClassName)) + baseName = type->getValueAsDef(BaseFieldName)->getName(); + + // Generate the invocation line. + Out << macroName << "(" << id << ", " << baseName << ")\n"; + } +} + +void TypeNodeEmitter::emitLastNodeInvocation() { + // We check that this is non-empty earlier. + Out << "#ifdef " LastTypeMacroName "\n" + LastTypeMacroName "(" << getIdForType(Types.back()) << ")\n" + "#undef " LastTypeMacroName "\n" + "#endif\n"; +} + +void TypeNodeEmitter::emitLeafNodeInvocations() { + Out << "#ifdef " LeafTypeMacroName "\n"; + + for (auto type : Types) { + if (!type->isSubClassOf(LeafTypeClassName)) continue; + Out << LeafTypeMacroName "(" << getIdForType(type) << ")\n"; + } + + Out << "#undef " LeafTypeMacroName "\n" + "#endif\n"; +} + +void TypeNodeEmitter::addMacroToUndef(StringRef macroName) { + MacrosToUndef.push_back(macroName); +} + +void TypeNodeEmitter::emitUndefs() { + for (auto ¯oName : MacrosToUndef) { + Out << "#undef " << macroName << "\n"; + } +} + +void clang::EmitClangTypeNodes(RecordKeeper &records, raw_ostream &out) { + TypeNodeEmitter(records, out).emit(); +} |