зеркало из https://github.com/microsoft/clang-1.git
Add the Clang tblgen backends to Clang, and flip the switch to cause
the build systems to use clang-tblgen. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@141291 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
733dbc805f
Коммит
51d7777a21
|
@ -153,7 +153,7 @@ function(clang_tablegen)
|
|||
endif()
|
||||
|
||||
set( LLVM_TARGET_DEFINITIONS ${CTG_SOURCE} )
|
||||
tablegen( LLVM ${CTG_DEFAULT_ARGS} )
|
||||
tablegen( CLANG ${CTG_DEFAULT_ARGS} )
|
||||
|
||||
list( GET CTG_DEFAULT_ARGS 0 output_file )
|
||||
if( CTG_TARGET )
|
||||
|
@ -244,6 +244,7 @@ set(LIBCLANG_LIBRARY_VERSION
|
|||
"Version number that will be placed into the libclang library , in the form XX.YY")
|
||||
mark_as_advanced(CLANG_EXECUTABLE_VERSION LIBCLANG_LIBRARY_VERSION)
|
||||
|
||||
add_subdirectory(utils/TableGen)
|
||||
|
||||
option(CLANG_BUILD_EXAMPLES "Build CLANG example programs." OFF)
|
||||
if(CLANG_BUILD_EXAMPLES)
|
||||
|
|
6
Makefile
6
Makefile
|
@ -14,7 +14,7 @@ ifndef CLANG_LEVEL
|
|||
|
||||
IS_TOP_LEVEL := 1
|
||||
CLANG_LEVEL := .
|
||||
DIRS := include lib tools runtime docs unittests
|
||||
DIRS := utils/TableGen include lib tools runtime docs unittests
|
||||
|
||||
PARALLEL_DIRS :=
|
||||
|
||||
|
@ -63,9 +63,9 @@ CXX.Flags += -fno-strict-aliasing
|
|||
# Set up Clang's tblgen.
|
||||
ifndef CLANG_TBLGEN
|
||||
ifeq ($(LLVM_CROSS_COMPILING),1)
|
||||
CLANG_TBLGEN := $(BuildLLVMToolDir)/llvm-tblgen$(BUILD_EXEEXT)
|
||||
CLANG_TBLGEN := $(BuildLLVMToolDir)/clang-tblgen$(BUILD_EXEEXT)
|
||||
else
|
||||
CLANG_TBLGEN := $(LLVMToolDir)/llvm-tblgen$(EXEEXT)
|
||||
CLANG_TBLGEN := $(LLVMToolDir)/clang-tblgen$(EXEEXT)
|
||||
endif
|
||||
endif
|
||||
ClangTableGen = $(CLANG_TBLGEN) $(TableGen.Flags)
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
set(LLVM_REQUIRES_EH 1)
|
||||
set(LLVM_REQUIRES_RTTI 1)
|
||||
|
||||
add_tablegen(clang-tblgen CLANG
|
||||
ClangASTNodesEmitter.cpp
|
||||
ClangAttrEmitter.cpp
|
||||
ClangDiagnosticsEmitter.cpp
|
||||
ClangSACheckersEmitter.cpp
|
||||
NeonEmitter.cpp
|
||||
OptParserEmitter.cpp
|
||||
TableGen.cpp
|
||||
)
|
|
@ -0,0 +1,168 @@
|
|||
//=== ClangASTNodesEmitter.cpp - Generate Clang AST node tables -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// These tablegen backends emit Clang AST node tables
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ClangASTNodesEmitter.h"
|
||||
#include <set>
|
||||
using namespace llvm;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Statement Node Tables (.inc file) generation.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Returns the first and last non-abstract subrecords
|
||||
// Called recursively to ensure that nodes remain contiguous
|
||||
std::pair<Record *, Record *> ClangASTNodesEmitter::EmitNode(
|
||||
const ChildMap &Tree,
|
||||
raw_ostream &OS,
|
||||
Record *Base) {
|
||||
std::string BaseName = macroName(Base->getName());
|
||||
|
||||
ChildIterator i = Tree.lower_bound(Base), e = Tree.upper_bound(Base);
|
||||
|
||||
Record *First = 0, *Last = 0;
|
||||
// This might be the pseudo-node for Stmt; don't assume it has an Abstract
|
||||
// bit
|
||||
if (Base->getValue("Abstract") && !Base->getValueAsBit("Abstract"))
|
||||
First = Last = Base;
|
||||
|
||||
for (; i != e; ++i) {
|
||||
Record *R = i->second;
|
||||
bool Abstract = R->getValueAsBit("Abstract");
|
||||
std::string NodeName = macroName(R->getName());
|
||||
|
||||
OS << "#ifndef " << NodeName << "\n";
|
||||
OS << "# define " << NodeName << "(Type, Base) "
|
||||
<< BaseName << "(Type, Base)\n";
|
||||
OS << "#endif\n";
|
||||
|
||||
if (Abstract)
|
||||
OS << "ABSTRACT_" << macroName(Root.getName()) << "(" << NodeName << "("
|
||||
<< R->getName() << ", " << baseName(*Base) << "))\n";
|
||||
else
|
||||
OS << NodeName << "(" << R->getName() << ", "
|
||||
<< baseName(*Base) << ")\n";
|
||||
|
||||
if (Tree.find(R) != Tree.end()) {
|
||||
const std::pair<Record *, Record *> &Result
|
||||
= EmitNode(Tree, OS, R);
|
||||
if (!First && Result.first)
|
||||
First = Result.first;
|
||||
if (Result.second)
|
||||
Last = Result.second;
|
||||
} else {
|
||||
if (!Abstract) {
|
||||
Last = R;
|
||||
|
||||
if (!First)
|
||||
First = R;
|
||||
}
|
||||
}
|
||||
|
||||
OS << "#undef " << NodeName << "\n\n";
|
||||
}
|
||||
|
||||
if (First) {
|
||||
assert (Last && "Got a first node but not a last node for a range!");
|
||||
if (Base == &Root)
|
||||
OS << "LAST_" << macroName(Root.getName()) << "_RANGE(";
|
||||
else
|
||||
OS << macroName(Root.getName()) << "_RANGE(";
|
||||
OS << Base->getName() << ", " << First->getName() << ", "
|
||||
<< Last->getName() << ")\n\n";
|
||||
}
|
||||
|
||||
return std::make_pair(First, Last);
|
||||
}
|
||||
|
||||
void ClangASTNodesEmitter::run(raw_ostream &OS) {
|
||||
// Write the preamble
|
||||
OS << "#ifndef ABSTRACT_" << macroName(Root.getName()) << "\n";
|
||||
OS << "# define ABSTRACT_" << macroName(Root.getName()) << "(Type) Type\n";
|
||||
OS << "#endif\n";
|
||||
|
||||
OS << "#ifndef " << macroName(Root.getName()) << "_RANGE\n";
|
||||
OS << "# define "
|
||||
<< macroName(Root.getName()) << "_RANGE(Base, First, Last)\n";
|
||||
OS << "#endif\n\n";
|
||||
|
||||
OS << "#ifndef LAST_" << macroName(Root.getName()) << "_RANGE\n";
|
||||
OS << "# define LAST_"
|
||||
<< macroName(Root.getName()) << "_RANGE(Base, First, Last) "
|
||||
<< macroName(Root.getName()) << "_RANGE(Base, First, Last)\n";
|
||||
OS << "#endif\n\n";
|
||||
|
||||
// Emit statements
|
||||
const std::vector<Record*> Stmts
|
||||
= Records.getAllDerivedDefinitions(Root.getName());
|
||||
|
||||
ChildMap Tree;
|
||||
|
||||
for (unsigned i = 0, e = Stmts.size(); i != e; ++i) {
|
||||
Record *R = Stmts[i];
|
||||
|
||||
if (R->getValue("Base"))
|
||||
Tree.insert(std::make_pair(R->getValueAsDef("Base"), R));
|
||||
else
|
||||
Tree.insert(std::make_pair(&Root, R));
|
||||
}
|
||||
|
||||
EmitNode(Tree, OS, &Root);
|
||||
|
||||
OS << "#undef " << macroName(Root.getName()) << "\n";
|
||||
OS << "#undef " << macroName(Root.getName()) << "_RANGE\n";
|
||||
OS << "#undef LAST_" << macroName(Root.getName()) << "_RANGE\n";
|
||||
OS << "#undef ABSTRACT_" << macroName(Root.getName()) << "\n";
|
||||
}
|
||||
|
||||
void ClangDeclContextEmitter::run(raw_ostream &OS) {
|
||||
// FIXME: Find a .td file format to allow for this to be represented better.
|
||||
|
||||
OS << "#ifndef DECL_CONTEXT\n";
|
||||
OS << "# define DECL_CONTEXT(DECL)\n";
|
||||
OS << "#endif\n";
|
||||
|
||||
OS << "#ifndef DECL_CONTEXT_BASE\n";
|
||||
OS << "# define DECL_CONTEXT_BASE(DECL) DECL_CONTEXT(DECL)\n";
|
||||
OS << "#endif\n";
|
||||
|
||||
typedef std::set<Record*> RecordSet;
|
||||
typedef std::vector<Record*> RecordVector;
|
||||
|
||||
RecordVector DeclContextsVector
|
||||
= Records.getAllDerivedDefinitions("DeclContext");
|
||||
RecordVector Decls = Records.getAllDerivedDefinitions("Decl");
|
||||
RecordSet DeclContexts (DeclContextsVector.begin(), DeclContextsVector.end());
|
||||
|
||||
for (RecordVector::iterator i = Decls.begin(), e = Decls.end(); i != e; ++i) {
|
||||
Record *R = *i;
|
||||
|
||||
if (R->getValue("Base")) {
|
||||
Record *B = R->getValueAsDef("Base");
|
||||
if (DeclContexts.find(B) != DeclContexts.end()) {
|
||||
OS << "DECL_CONTEXT_BASE(" << B->getName() << ")\n";
|
||||
DeclContexts.erase(B);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// To keep identical order, RecordVector may be used
|
||||
// instead of RecordSet.
|
||||
for (RecordVector::iterator
|
||||
i = DeclContextsVector.begin(), e = DeclContextsVector.end();
|
||||
i != e; ++i)
|
||||
if (DeclContexts.find(*i) != DeclContexts.end())
|
||||
OS << "DECL_CONTEXT(" << (*i)->getName() << ")\n";
|
||||
|
||||
OS << "#undef DECL_CONTEXT\n";
|
||||
OS << "#undef DECL_CONTEXT_BASE\n";
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
//===- ClangASTNodesEmitter.h - Generate Clang AST node tables -*- C++ -*--===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// These tablegen backends emit Clang AST node tables
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef CLANGAST_EMITTER_H
|
||||
#define CLANGAST_EMITTER_H
|
||||
|
||||
#include "llvm/TableGen/TableGenBackend.h"
|
||||
#include "llvm/TableGen/Record.h"
|
||||
#include <string>
|
||||
#include <cctype>
|
||||
#include <map>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// ClangASTNodesEmitter - The top-level class emits .inc files containing
|
||||
/// declarations of Clang statements.
|
||||
///
|
||||
class ClangASTNodesEmitter : public TableGenBackend {
|
||||
// A map from a node to each of its derived nodes.
|
||||
typedef std::multimap<Record*, Record*> ChildMap;
|
||||
typedef ChildMap::const_iterator ChildIterator;
|
||||
|
||||
RecordKeeper &Records;
|
||||
Record Root;
|
||||
const std::string &BaseSuffix;
|
||||
|
||||
// Create a macro-ized version of a name
|
||||
static std::string macroName(std::string S) {
|
||||
for (unsigned i = 0; i < S.size(); ++i)
|
||||
S[i] = std::toupper(S[i]);
|
||||
|
||||
return S;
|
||||
}
|
||||
|
||||
// Return the name to be printed in the base field. Normally this is
|
||||
// the record's name plus the base suffix, but if it is the root node and
|
||||
// the suffix is non-empty, it's just the suffix.
|
||||
std::string baseName(Record &R) {
|
||||
if (&R == &Root && !BaseSuffix.empty())
|
||||
return BaseSuffix;
|
||||
|
||||
return R.getName() + BaseSuffix;
|
||||
}
|
||||
|
||||
std::pair<Record *, Record *> EmitNode (const ChildMap &Tree, raw_ostream& OS,
|
||||
Record *Base);
|
||||
public:
|
||||
explicit ClangASTNodesEmitter(RecordKeeper &R, const std::string &N,
|
||||
const std::string &S)
|
||||
: Records(R), Root(N, SMLoc(), R), BaseSuffix(S)
|
||||
{}
|
||||
|
||||
// run - Output the .inc file contents
|
||||
void run(raw_ostream &OS);
|
||||
};
|
||||
|
||||
/// ClangDeclContextEmitter - Emits an addendum to a .inc file to enumerate the
|
||||
/// clang declaration contexts.
|
||||
///
|
||||
class ClangDeclContextEmitter : public TableGenBackend {
|
||||
RecordKeeper &Records;
|
||||
|
||||
public:
|
||||
explicit ClangDeclContextEmitter(RecordKeeper &R)
|
||||
: Records(R)
|
||||
{}
|
||||
|
||||
// run - Output the .inc file contents
|
||||
void run(raw_ostream &OS);
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
|
@ -0,0 +1,788 @@
|
|||
//===- ClangAttrEmitter.cpp - Generate Clang attribute handling =-*- C++ -*--=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// These tablegen backends emit Clang attribute processing code
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ClangAttrEmitter.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/TableGen/Record.h"
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
static const std::vector<StringRef>
|
||||
getValueAsListOfStrings(Record &R, StringRef FieldName) {
|
||||
ListInit *List = R.getValueAsListInit(FieldName);
|
||||
assert (List && "Got a null ListInit");
|
||||
|
||||
std::vector<StringRef> Strings;
|
||||
Strings.reserve(List->getSize());
|
||||
|
||||
for (ListInit::const_iterator i = List->begin(), e = List->end();
|
||||
i != e;
|
||||
++i) {
|
||||
assert(*i && "Got a null element in a ListInit");
|
||||
if (StringInit *S = dynamic_cast<StringInit *>(*i))
|
||||
Strings.push_back(S->getValue());
|
||||
else if (CodeInit *C = dynamic_cast<CodeInit *>(*i))
|
||||
Strings.push_back(C->getValue());
|
||||
else
|
||||
assert(false && "Got a non-string, non-code element in a ListInit");
|
||||
}
|
||||
|
||||
return Strings;
|
||||
}
|
||||
|
||||
static std::string ReadPCHRecord(StringRef type) {
|
||||
return StringSwitch<std::string>(type)
|
||||
.EndsWith("Decl *", "GetLocalDeclAs<"
|
||||
+ std::string(type, 0, type.size()-1) + ">(F, Record[Idx++])")
|
||||
.Case("QualType", "getLocalType(F, Record[Idx++])")
|
||||
.Case("Expr *", "ReadSubExpr()")
|
||||
.Case("IdentifierInfo *", "GetIdentifierInfo(F, Record, Idx)")
|
||||
.Case("SourceLocation", "ReadSourceLocation(F, Record, Idx)")
|
||||
.Default("Record[Idx++]");
|
||||
}
|
||||
|
||||
// Assumes that the way to get the value is SA->getname()
|
||||
static std::string WritePCHRecord(StringRef type, StringRef name) {
|
||||
return StringSwitch<std::string>(type)
|
||||
.EndsWith("Decl *", "AddDeclRef(" + std::string(name) +
|
||||
", Record);\n")
|
||||
.Case("QualType", "AddTypeRef(" + std::string(name) + ", Record);\n")
|
||||
.Case("Expr *", "AddStmt(" + std::string(name) + ");\n")
|
||||
.Case("IdentifierInfo *",
|
||||
"AddIdentifierRef(" + std::string(name) + ", Record);\n")
|
||||
.Case("SourceLocation",
|
||||
"AddSourceLocation(" + std::string(name) + ", Record);\n")
|
||||
.Default("Record.push_back(" + std::string(name) + ");\n");
|
||||
}
|
||||
|
||||
namespace {
|
||||
class Argument {
|
||||
std::string lowerName, upperName;
|
||||
StringRef attrName;
|
||||
|
||||
public:
|
||||
Argument(Record &Arg, StringRef Attr)
|
||||
: lowerName(Arg.getValueAsString("Name")), upperName(lowerName),
|
||||
attrName(Attr) {
|
||||
if (!lowerName.empty()) {
|
||||
lowerName[0] = std::tolower(lowerName[0]);
|
||||
upperName[0] = std::toupper(upperName[0]);
|
||||
}
|
||||
}
|
||||
virtual ~Argument() {}
|
||||
|
||||
StringRef getLowerName() const { return lowerName; }
|
||||
StringRef getUpperName() const { return upperName; }
|
||||
StringRef getAttrName() const { return attrName; }
|
||||
|
||||
// These functions print the argument contents formatted in different ways.
|
||||
virtual void writeAccessors(raw_ostream &OS) const = 0;
|
||||
virtual void writeAccessorDefinitions(raw_ostream &OS) const {}
|
||||
virtual void writeCloneArgs(raw_ostream &OS) const = 0;
|
||||
virtual void writeCtorBody(raw_ostream &OS) const {}
|
||||
virtual void writeCtorInitializers(raw_ostream &OS) const = 0;
|
||||
virtual void writeCtorParameters(raw_ostream &OS) const = 0;
|
||||
virtual void writeDeclarations(raw_ostream &OS) const = 0;
|
||||
virtual void writePCHReadArgs(raw_ostream &OS) const = 0;
|
||||
virtual void writePCHReadDecls(raw_ostream &OS) const = 0;
|
||||
virtual void writePCHWrite(raw_ostream &OS) const = 0;
|
||||
};
|
||||
|
||||
class SimpleArgument : public Argument {
|
||||
std::string type;
|
||||
|
||||
public:
|
||||
SimpleArgument(Record &Arg, StringRef Attr, std::string T)
|
||||
: Argument(Arg, Attr), type(T)
|
||||
{}
|
||||
|
||||
void writeAccessors(raw_ostream &OS) const {
|
||||
OS << " " << type << " get" << getUpperName() << "() const {\n";
|
||||
OS << " return " << getLowerName() << ";\n";
|
||||
OS << " }";
|
||||
}
|
||||
void writeCloneArgs(raw_ostream &OS) const {
|
||||
OS << getLowerName();
|
||||
}
|
||||
void writeCtorInitializers(raw_ostream &OS) const {
|
||||
OS << getLowerName() << "(" << getUpperName() << ")";
|
||||
}
|
||||
void writeCtorParameters(raw_ostream &OS) const {
|
||||
OS << type << " " << getUpperName();
|
||||
}
|
||||
void writeDeclarations(raw_ostream &OS) const {
|
||||
OS << type << " " << getLowerName() << ";";
|
||||
}
|
||||
void writePCHReadDecls(raw_ostream &OS) const {
|
||||
std::string read = ReadPCHRecord(type);
|
||||
OS << " " << type << " " << getLowerName() << " = " << read << ";\n";
|
||||
}
|
||||
void writePCHReadArgs(raw_ostream &OS) const {
|
||||
OS << getLowerName();
|
||||
}
|
||||
void writePCHWrite(raw_ostream &OS) const {
|
||||
OS << " " << WritePCHRecord(type, "SA->get" +
|
||||
std::string(getUpperName()) + "()");
|
||||
}
|
||||
};
|
||||
|
||||
class StringArgument : public Argument {
|
||||
public:
|
||||
StringArgument(Record &Arg, StringRef Attr)
|
||||
: Argument(Arg, Attr)
|
||||
{}
|
||||
|
||||
void writeAccessors(raw_ostream &OS) const {
|
||||
OS << " llvm::StringRef get" << getUpperName() << "() const {\n";
|
||||
OS << " return llvm::StringRef(" << getLowerName() << ", "
|
||||
<< getLowerName() << "Length);\n";
|
||||
OS << " }\n";
|
||||
OS << " unsigned get" << getUpperName() << "Length() const {\n";
|
||||
OS << " return " << getLowerName() << "Length;\n";
|
||||
OS << " }\n";
|
||||
OS << " void set" << getUpperName()
|
||||
<< "(ASTContext &C, llvm::StringRef S) {\n";
|
||||
OS << " " << getLowerName() << "Length = S.size();\n";
|
||||
OS << " this->" << getLowerName() << " = new (C, 1) char ["
|
||||
<< getLowerName() << "Length];\n";
|
||||
OS << " std::memcpy(this->" << getLowerName() << ", S.data(), "
|
||||
<< getLowerName() << "Length);\n";
|
||||
OS << " }";
|
||||
}
|
||||
void writeCloneArgs(raw_ostream &OS) const {
|
||||
OS << "get" << getUpperName() << "()";
|
||||
}
|
||||
void writeCtorBody(raw_ostream &OS) const {
|
||||
OS << " std::memcpy(" << getLowerName() << ", " << getUpperName()
|
||||
<< ".data(), " << getLowerName() << "Length);";
|
||||
}
|
||||
void writeCtorInitializers(raw_ostream &OS) const {
|
||||
OS << getLowerName() << "Length(" << getUpperName() << ".size()),"
|
||||
<< getLowerName() << "(new (Ctx, 1) char[" << getLowerName()
|
||||
<< "Length])";
|
||||
}
|
||||
void writeCtorParameters(raw_ostream &OS) const {
|
||||
OS << "llvm::StringRef " << getUpperName();
|
||||
}
|
||||
void writeDeclarations(raw_ostream &OS) const {
|
||||
OS << "unsigned " << getLowerName() << "Length;\n";
|
||||
OS << "char *" << getLowerName() << ";";
|
||||
}
|
||||
void writePCHReadDecls(raw_ostream &OS) const {
|
||||
OS << " std::string " << getLowerName()
|
||||
<< "= ReadString(Record, Idx);\n";
|
||||
}
|
||||
void writePCHReadArgs(raw_ostream &OS) const {
|
||||
OS << getLowerName();
|
||||
}
|
||||
void writePCHWrite(raw_ostream &OS) const {
|
||||
OS << " AddString(SA->get" << getUpperName() << "(), Record);\n";
|
||||
}
|
||||
};
|
||||
|
||||
class AlignedArgument : public Argument {
|
||||
public:
|
||||
AlignedArgument(Record &Arg, StringRef Attr)
|
||||
: Argument(Arg, Attr)
|
||||
{}
|
||||
|
||||
void writeAccessors(raw_ostream &OS) const {
|
||||
OS << " bool is" << getUpperName() << "Dependent() const;\n";
|
||||
|
||||
OS << " unsigned get" << getUpperName() << "(ASTContext &Ctx) const;\n";
|
||||
|
||||
OS << " bool is" << getUpperName() << "Expr() const {\n";
|
||||
OS << " return is" << getLowerName() << "Expr;\n";
|
||||
OS << " }\n";
|
||||
|
||||
OS << " Expr *get" << getUpperName() << "Expr() const {\n";
|
||||
OS << " assert(is" << getLowerName() << "Expr);\n";
|
||||
OS << " return " << getLowerName() << "Expr;\n";
|
||||
OS << " }\n";
|
||||
|
||||
OS << " TypeSourceInfo *get" << getUpperName() << "Type() const {\n";
|
||||
OS << " assert(!is" << getLowerName() << "Expr);\n";
|
||||
OS << " return " << getLowerName() << "Type;\n";
|
||||
OS << " }";
|
||||
}
|
||||
void writeAccessorDefinitions(raw_ostream &OS) const {
|
||||
OS << "bool " << getAttrName() << "Attr::is" << getUpperName()
|
||||
<< "Dependent() const {\n";
|
||||
OS << " if (is" << getLowerName() << "Expr)\n";
|
||||
OS << " return " << getLowerName() << "Expr && (" << getLowerName()
|
||||
<< "Expr->isValueDependent() || " << getLowerName()
|
||||
<< "Expr->isTypeDependent());\n";
|
||||
OS << " else\n";
|
||||
OS << " return " << getLowerName()
|
||||
<< "Type->getType()->isDependentType();\n";
|
||||
OS << "}\n";
|
||||
|
||||
// FIXME: Do not do the calculation here
|
||||
// FIXME: Handle types correctly
|
||||
// A null pointer means maximum alignment
|
||||
// FIXME: Load the platform-specific maximum alignment, rather than
|
||||
// 16, the x86 max.
|
||||
OS << "unsigned " << getAttrName() << "Attr::get" << getUpperName()
|
||||
<< "(ASTContext &Ctx) const {\n";
|
||||
OS << " assert(!is" << getUpperName() << "Dependent());\n";
|
||||
OS << " if (is" << getLowerName() << "Expr)\n";
|
||||
OS << " return (" << getLowerName() << "Expr ? " << getLowerName()
|
||||
<< "Expr->EvaluateAsInt(Ctx).getZExtValue() : 16)"
|
||||
<< "* Ctx.getCharWidth();\n";
|
||||
OS << " else\n";
|
||||
OS << " return 0; // FIXME\n";
|
||||
OS << "}\n";
|
||||
}
|
||||
void writeCloneArgs(raw_ostream &OS) const {
|
||||
OS << "is" << getLowerName() << "Expr, is" << getLowerName()
|
||||
<< "Expr ? static_cast<void*>(" << getLowerName()
|
||||
<< "Expr) : " << getLowerName()
|
||||
<< "Type";
|
||||
}
|
||||
void writeCtorBody(raw_ostream &OS) const {
|
||||
OS << " if (is" << getLowerName() << "Expr)\n";
|
||||
OS << " " << getLowerName() << "Expr = reinterpret_cast<Expr *>("
|
||||
<< getUpperName() << ");\n";
|
||||
OS << " else\n";
|
||||
OS << " " << getLowerName()
|
||||
<< "Type = reinterpret_cast<TypeSourceInfo *>(" << getUpperName()
|
||||
<< ");";
|
||||
}
|
||||
void writeCtorInitializers(raw_ostream &OS) const {
|
||||
OS << "is" << getLowerName() << "Expr(Is" << getUpperName() << "Expr)";
|
||||
}
|
||||
void writeCtorParameters(raw_ostream &OS) const {
|
||||
OS << "bool Is" << getUpperName() << "Expr, void *" << getUpperName();
|
||||
}
|
||||
void writeDeclarations(raw_ostream &OS) const {
|
||||
OS << "bool is" << getLowerName() << "Expr;\n";
|
||||
OS << "union {\n";
|
||||
OS << "Expr *" << getLowerName() << "Expr;\n";
|
||||
OS << "TypeSourceInfo *" << getLowerName() << "Type;\n";
|
||||
OS << "};";
|
||||
}
|
||||
void writePCHReadArgs(raw_ostream &OS) const {
|
||||
OS << "is" << getLowerName() << "Expr, " << getLowerName() << "Ptr";
|
||||
}
|
||||
void writePCHReadDecls(raw_ostream &OS) const {
|
||||
OS << " bool is" << getLowerName() << "Expr = Record[Idx++];\n";
|
||||
OS << " void *" << getLowerName() << "Ptr;\n";
|
||||
OS << " if (is" << getLowerName() << "Expr)\n";
|
||||
OS << " " << getLowerName() << "Ptr = ReadExpr(F);\n";
|
||||
OS << " else\n";
|
||||
OS << " " << getLowerName()
|
||||
<< "Ptr = GetTypeSourceInfo(F, Record, Idx);\n";
|
||||
}
|
||||
void writePCHWrite(raw_ostream &OS) const {
|
||||
OS << " Record.push_back(SA->is" << getUpperName() << "Expr());\n";
|
||||
OS << " if (SA->is" << getUpperName() << "Expr())\n";
|
||||
OS << " AddStmt(SA->get" << getUpperName() << "Expr());\n";
|
||||
OS << " else\n";
|
||||
OS << " AddTypeSourceInfo(SA->get" << getUpperName()
|
||||
<< "Type(), Record);\n";
|
||||
}
|
||||
};
|
||||
|
||||
class VariadicArgument : public Argument {
|
||||
std::string type;
|
||||
|
||||
public:
|
||||
VariadicArgument(Record &Arg, StringRef Attr, std::string T)
|
||||
: Argument(Arg, Attr), type(T)
|
||||
{}
|
||||
|
||||
std::string getType() const { return type; }
|
||||
|
||||
void writeAccessors(raw_ostream &OS) const {
|
||||
OS << " typedef " << type << "* " << getLowerName() << "_iterator;\n";
|
||||
OS << " " << getLowerName() << "_iterator " << getLowerName()
|
||||
<< "_begin() const {\n";
|
||||
OS << " return " << getLowerName() << ";\n";
|
||||
OS << " }\n";
|
||||
OS << " " << getLowerName() << "_iterator " << getLowerName()
|
||||
<< "_end() const {\n";
|
||||
OS << " return " << getLowerName() << " + " << getLowerName()
|
||||
<< "Size;\n";
|
||||
OS << " }\n";
|
||||
OS << " unsigned " << getLowerName() << "_size() const {\n"
|
||||
<< " return " << getLowerName() << "Size;\n;";
|
||||
OS << " }";
|
||||
}
|
||||
void writeCloneArgs(raw_ostream &OS) const {
|
||||
OS << getLowerName() << ", " << getLowerName() << "Size";
|
||||
}
|
||||
void writeCtorBody(raw_ostream &OS) const {
|
||||
// FIXME: memcpy is not safe on non-trivial types.
|
||||
OS << " std::memcpy(" << getLowerName() << ", " << getUpperName()
|
||||
<< ", " << getLowerName() << "Size * sizeof(" << getType() << "));\n";
|
||||
}
|
||||
void writeCtorInitializers(raw_ostream &OS) const {
|
||||
OS << getLowerName() << "Size(" << getUpperName() << "Size), "
|
||||
<< getLowerName() << "(new (Ctx, 16) " << getType() << "["
|
||||
<< getLowerName() << "Size])";
|
||||
}
|
||||
void writeCtorParameters(raw_ostream &OS) const {
|
||||
OS << getType() << " *" << getUpperName() << ", unsigned "
|
||||
<< getUpperName() << "Size";
|
||||
}
|
||||
void writeDeclarations(raw_ostream &OS) const {
|
||||
OS << " unsigned " << getLowerName() << "Size;\n";
|
||||
OS << " " << getType() << " *" << getLowerName() << ";";
|
||||
}
|
||||
void writePCHReadDecls(raw_ostream &OS) const {
|
||||
OS << " unsigned " << getLowerName() << "Size = Record[Idx++];\n";
|
||||
OS << " llvm::SmallVector<" << type << ", 4> " << getLowerName()
|
||||
<< ";\n";
|
||||
OS << " " << getLowerName() << ".reserve(" << getLowerName()
|
||||
<< "Size);\n";
|
||||
OS << " for (unsigned i = " << getLowerName() << "Size; i; --i)\n";
|
||||
|
||||
std::string read = ReadPCHRecord(type);
|
||||
OS << " " << getLowerName() << ".push_back(" << read << ");\n";
|
||||
}
|
||||
void writePCHReadArgs(raw_ostream &OS) const {
|
||||
OS << getLowerName() << ".data(), " << getLowerName() << "Size";
|
||||
}
|
||||
void writePCHWrite(raw_ostream &OS) const{
|
||||
OS << " Record.push_back(SA->" << getLowerName() << "_size());\n";
|
||||
OS << " for (" << getAttrName() << "Attr::" << getLowerName()
|
||||
<< "_iterator i = SA->" << getLowerName() << "_begin(), e = SA->"
|
||||
<< getLowerName() << "_end(); i != e; ++i)\n";
|
||||
OS << " " << WritePCHRecord(type, "(*i)");
|
||||
}
|
||||
};
|
||||
|
||||
class EnumArgument : public Argument {
|
||||
std::string type;
|
||||
std::vector<StringRef> values, enums;
|
||||
public:
|
||||
EnumArgument(Record &Arg, StringRef Attr)
|
||||
: Argument(Arg, Attr), type(Arg.getValueAsString("Type")),
|
||||
values(getValueAsListOfStrings(Arg, "Values")),
|
||||
enums(getValueAsListOfStrings(Arg, "Enums"))
|
||||
{}
|
||||
|
||||
void writeAccessors(raw_ostream &OS) const {
|
||||
OS << " " << type << " get" << getUpperName() << "() const {\n";
|
||||
OS << " return " << getLowerName() << ";\n";
|
||||
OS << " }";
|
||||
}
|
||||
void writeCloneArgs(raw_ostream &OS) const {
|
||||
OS << getLowerName();
|
||||
}
|
||||
void writeCtorInitializers(raw_ostream &OS) const {
|
||||
OS << getLowerName() << "(" << getUpperName() << ")";
|
||||
}
|
||||
void writeCtorParameters(raw_ostream &OS) const {
|
||||
OS << type << " " << getUpperName();
|
||||
}
|
||||
void writeDeclarations(raw_ostream &OS) const {
|
||||
// Calculate the various enum values
|
||||
std::vector<StringRef> uniques(enums);
|
||||
std::sort(uniques.begin(), uniques.end());
|
||||
uniques.erase(std::unique(uniques.begin(), uniques.end()),
|
||||
uniques.end());
|
||||
// FIXME: Emit a proper error
|
||||
assert(!uniques.empty());
|
||||
|
||||
std::vector<StringRef>::iterator i = uniques.begin(),
|
||||
e = uniques.end();
|
||||
// The last one needs to not have a comma.
|
||||
--e;
|
||||
|
||||
OS << "public:\n";
|
||||
OS << " enum " << type << " {\n";
|
||||
for (; i != e; ++i)
|
||||
OS << " " << *i << ",\n";
|
||||
OS << " " << *e << "\n";
|
||||
OS << " };\n";
|
||||
OS << "private:\n";
|
||||
OS << " " << type << " " << getLowerName() << ";";
|
||||
}
|
||||
void writePCHReadDecls(raw_ostream &OS) const {
|
||||
OS << " " << getAttrName() << "Attr::" << type << " " << getLowerName()
|
||||
<< "(static_cast<" << getAttrName() << "Attr::" << type
|
||||
<< ">(Record[Idx++]));\n";
|
||||
}
|
||||
void writePCHReadArgs(raw_ostream &OS) const {
|
||||
OS << getLowerName();
|
||||
}
|
||||
void writePCHWrite(raw_ostream &OS) const {
|
||||
OS << "Record.push_back(SA->get" << getUpperName() << "());\n";
|
||||
}
|
||||
};
|
||||
|
||||
class VersionArgument : public Argument {
|
||||
public:
|
||||
VersionArgument(Record &Arg, StringRef Attr)
|
||||
: Argument(Arg, Attr)
|
||||
{}
|
||||
|
||||
void writeAccessors(raw_ostream &OS) const {
|
||||
OS << " VersionTuple get" << getUpperName() << "() const {\n";
|
||||
OS << " return " << getLowerName() << ";\n";
|
||||
OS << " }\n";
|
||||
OS << " void set" << getUpperName()
|
||||
<< "(ASTContext &C, VersionTuple V) {\n";
|
||||
OS << " " << getLowerName() << " = V;\n";
|
||||
OS << " }";
|
||||
}
|
||||
void writeCloneArgs(raw_ostream &OS) const {
|
||||
OS << "get" << getUpperName() << "()";
|
||||
}
|
||||
void writeCtorBody(raw_ostream &OS) const {
|
||||
}
|
||||
void writeCtorInitializers(raw_ostream &OS) const {
|
||||
OS << getLowerName() << "(" << getUpperName() << ")";
|
||||
}
|
||||
void writeCtorParameters(raw_ostream &OS) const {
|
||||
OS << "VersionTuple " << getUpperName();
|
||||
}
|
||||
void writeDeclarations(raw_ostream &OS) const {
|
||||
OS << "VersionTuple " << getLowerName() << ";\n";
|
||||
}
|
||||
void writePCHReadDecls(raw_ostream &OS) const {
|
||||
OS << " VersionTuple " << getLowerName()
|
||||
<< "= ReadVersionTuple(Record, Idx);\n";
|
||||
}
|
||||
void writePCHReadArgs(raw_ostream &OS) const {
|
||||
OS << getLowerName();
|
||||
}
|
||||
void writePCHWrite(raw_ostream &OS) const {
|
||||
OS << " AddVersionTuple(SA->get" << getUpperName() << "(), Record);\n";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static Argument *createArgument(Record &Arg, StringRef Attr,
|
||||
Record *Search = 0) {
|
||||
if (!Search)
|
||||
Search = &Arg;
|
||||
|
||||
Argument *Ptr = 0;
|
||||
llvm::StringRef ArgName = Search->getName();
|
||||
|
||||
if (ArgName == "AlignedArgument") Ptr = new AlignedArgument(Arg, Attr);
|
||||
else if (ArgName == "EnumArgument") Ptr = new EnumArgument(Arg, Attr);
|
||||
else if (ArgName == "ExprArgument") Ptr = new SimpleArgument(Arg, Attr,
|
||||
"Expr *");
|
||||
else if (ArgName == "FunctionArgument")
|
||||
Ptr = new SimpleArgument(Arg, Attr, "FunctionDecl *");
|
||||
else if (ArgName == "IdentifierArgument")
|
||||
Ptr = new SimpleArgument(Arg, Attr, "IdentifierInfo *");
|
||||
else if (ArgName == "BoolArgument") Ptr = new SimpleArgument(Arg, Attr,
|
||||
"bool");
|
||||
else if (ArgName == "IntArgument") Ptr = new SimpleArgument(Arg, Attr, "int");
|
||||
else if (ArgName == "StringArgument") Ptr = new StringArgument(Arg, Attr);
|
||||
else if (ArgName == "TypeArgument")
|
||||
Ptr = new SimpleArgument(Arg, Attr, "QualType");
|
||||
else if (ArgName == "UnsignedArgument")
|
||||
Ptr = new SimpleArgument(Arg, Attr, "unsigned");
|
||||
else if (ArgName == "SourceLocArgument")
|
||||
Ptr = new SimpleArgument(Arg, Attr, "SourceLocation");
|
||||
else if (ArgName == "VariadicUnsignedArgument")
|
||||
Ptr = new VariadicArgument(Arg, Attr, "unsigned");
|
||||
else if (ArgName == "VariadicExprArgument")
|
||||
Ptr = new VariadicArgument(Arg, Attr, "Expr *");
|
||||
else if (ArgName == "VersionArgument")
|
||||
Ptr = new VersionArgument(Arg, Attr);
|
||||
|
||||
if (!Ptr) {
|
||||
std::vector<Record*> Bases = Search->getSuperClasses();
|
||||
for (std::vector<Record*>::iterator i = Bases.begin(), e = Bases.end();
|
||||
i != e; ++i) {
|
||||
Ptr = createArgument(Arg, Attr, *i);
|
||||
if (Ptr)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Ptr;
|
||||
}
|
||||
|
||||
void ClangAttrClassEmitter::run(raw_ostream &OS) {
|
||||
OS << "// This file is generated by TableGen. Do not edit.\n\n";
|
||||
OS << "#ifndef LLVM_CLANG_ATTR_CLASSES_INC\n";
|
||||
OS << "#define LLVM_CLANG_ATTR_CLASSES_INC\n\n";
|
||||
|
||||
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
|
||||
|
||||
for (std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end();
|
||||
i != e; ++i) {
|
||||
Record &R = **i;
|
||||
const std::string &SuperName = R.getSuperClasses().back()->getName();
|
||||
|
||||
OS << "class " << R.getName() << "Attr : public " << SuperName << " {\n";
|
||||
|
||||
std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args");
|
||||
std::vector<Argument*> Args;
|
||||
std::vector<Argument*>::iterator ai, ae;
|
||||
Args.reserve(ArgRecords.size());
|
||||
|
||||
for (std::vector<Record*>::iterator ri = ArgRecords.begin(),
|
||||
re = ArgRecords.end();
|
||||
ri != re; ++ri) {
|
||||
Record &ArgRecord = **ri;
|
||||
Argument *Arg = createArgument(ArgRecord, R.getName());
|
||||
assert(Arg);
|
||||
Args.push_back(Arg);
|
||||
|
||||
Arg->writeDeclarations(OS);
|
||||
OS << "\n\n";
|
||||
}
|
||||
|
||||
ae = Args.end();
|
||||
|
||||
OS << "\n public:\n";
|
||||
OS << " " << R.getName() << "Attr(SourceRange R, ASTContext &Ctx\n";
|
||||
|
||||
for (ai = Args.begin(); ai != ae; ++ai) {
|
||||
OS << " , ";
|
||||
(*ai)->writeCtorParameters(OS);
|
||||
OS << "\n";
|
||||
}
|
||||
|
||||
OS << " )\n";
|
||||
OS << " : " << SuperName << "(attr::" << R.getName() << ", R)\n";
|
||||
|
||||
for (ai = Args.begin(); ai != ae; ++ai) {
|
||||
OS << " , ";
|
||||
(*ai)->writeCtorInitializers(OS);
|
||||
OS << "\n";
|
||||
}
|
||||
|
||||
OS << " {\n";
|
||||
|
||||
for (ai = Args.begin(); ai != ae; ++ai) {
|
||||
(*ai)->writeCtorBody(OS);
|
||||
OS << "\n";
|
||||
}
|
||||
OS << " }\n\n";
|
||||
|
||||
OS << " virtual " << R.getName() << "Attr *clone (ASTContext &C) const;\n";
|
||||
|
||||
for (ai = Args.begin(); ai != ae; ++ai) {
|
||||
(*ai)->writeAccessors(OS);
|
||||
OS << "\n\n";
|
||||
}
|
||||
|
||||
OS << R.getValueAsCode("AdditionalMembers");
|
||||
OS << "\n\n";
|
||||
|
||||
OS << " static bool classof(const Attr *A) { return A->getKind() == "
|
||||
<< "attr::" << R.getName() << "; }\n";
|
||||
OS << " static bool classof(const " << R.getName()
|
||||
<< "Attr *) { return true; }\n";
|
||||
OS << "};\n\n";
|
||||
}
|
||||
|
||||
OS << "#endif\n";
|
||||
}
|
||||
|
||||
void ClangAttrImplEmitter::run(raw_ostream &OS) {
|
||||
OS << "// This file is generated by TableGen. Do not edit.\n\n";
|
||||
|
||||
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
|
||||
std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(), ri, re;
|
||||
std::vector<Argument*>::iterator ai, ae;
|
||||
|
||||
for (; i != e; ++i) {
|
||||
Record &R = **i;
|
||||
std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args");
|
||||
std::vector<Argument*> Args;
|
||||
for (ri = ArgRecords.begin(), re = ArgRecords.end(); ri != re; ++ri)
|
||||
Args.push_back(createArgument(**ri, R.getName()));
|
||||
|
||||
for (ai = Args.begin(), ae = Args.end(); ai != ae; ++ai)
|
||||
(*ai)->writeAccessorDefinitions(OS);
|
||||
|
||||
OS << R.getName() << "Attr *" << R.getName()
|
||||
<< "Attr::clone(ASTContext &C) const {\n";
|
||||
OS << " return new (C) " << R.getName() << "Attr(getLocation(), C";
|
||||
for (ai = Args.begin(); ai != ae; ++ai) {
|
||||
OS << ", ";
|
||||
(*ai)->writeCloneArgs(OS);
|
||||
}
|
||||
OS << ");\n}\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
static void EmitAttrList(raw_ostream &OS, StringRef Class,
|
||||
const std::vector<Record*> &AttrList) {
|
||||
std::vector<Record*>::const_iterator i = AttrList.begin(), e = AttrList.end();
|
||||
|
||||
if (i != e) {
|
||||
// Move the end iterator back to emit the last attribute.
|
||||
for(--e; i != e; ++i)
|
||||
OS << Class << "(" << (*i)->getName() << ")\n";
|
||||
|
||||
OS << "LAST_" << Class << "(" << (*i)->getName() << ")\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
void ClangAttrListEmitter::run(raw_ostream &OS) {
|
||||
OS << "// This file is generated by TableGen. Do not edit.\n\n";
|
||||
|
||||
OS << "#ifndef LAST_ATTR\n";
|
||||
OS << "#define LAST_ATTR(NAME) ATTR(NAME)\n";
|
||||
OS << "#endif\n\n";
|
||||
|
||||
OS << "#ifndef INHERITABLE_ATTR\n";
|
||||
OS << "#define INHERITABLE_ATTR(NAME) ATTR(NAME)\n";
|
||||
OS << "#endif\n\n";
|
||||
|
||||
OS << "#ifndef LAST_INHERITABLE_ATTR\n";
|
||||
OS << "#define LAST_INHERITABLE_ATTR(NAME) INHERITABLE_ATTR(NAME)\n";
|
||||
OS << "#endif\n\n";
|
||||
|
||||
OS << "#ifndef INHERITABLE_PARAM_ATTR\n";
|
||||
OS << "#define INHERITABLE_PARAM_ATTR(NAME) ATTR(NAME)\n";
|
||||
OS << "#endif\n\n";
|
||||
|
||||
OS << "#ifndef LAST_INHERITABLE_PARAM_ATTR\n";
|
||||
OS << "#define LAST_INHERITABLE_PARAM_ATTR(NAME)"
|
||||
" INHERITABLE_PARAM_ATTR(NAME)\n";
|
||||
OS << "#endif\n\n";
|
||||
|
||||
Record *InhClass = Records.getClass("InheritableAttr");
|
||||
Record *InhParamClass = Records.getClass("InheritableParamAttr");
|
||||
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"),
|
||||
NonInhAttrs, InhAttrs, InhParamAttrs;
|
||||
for (std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end();
|
||||
i != e; ++i) {
|
||||
if ((*i)->isSubClassOf(InhParamClass))
|
||||
InhParamAttrs.push_back(*i);
|
||||
else if ((*i)->isSubClassOf(InhClass))
|
||||
InhAttrs.push_back(*i);
|
||||
else
|
||||
NonInhAttrs.push_back(*i);
|
||||
}
|
||||
|
||||
EmitAttrList(OS, "INHERITABLE_PARAM_ATTR", InhParamAttrs);
|
||||
EmitAttrList(OS, "INHERITABLE_ATTR", InhAttrs);
|
||||
EmitAttrList(OS, "ATTR", NonInhAttrs);
|
||||
|
||||
OS << "#undef LAST_ATTR\n";
|
||||
OS << "#undef INHERITABLE_ATTR\n";
|
||||
OS << "#undef LAST_INHERITABLE_ATTR\n";
|
||||
OS << "#undef LAST_INHERITABLE_PARAM_ATTR\n";
|
||||
OS << "#undef ATTR\n";
|
||||
}
|
||||
|
||||
void ClangAttrPCHReadEmitter::run(raw_ostream &OS) {
|
||||
OS << "// This file is generated by TableGen. Do not edit.\n\n";
|
||||
|
||||
Record *InhClass = Records.getClass("InheritableAttr");
|
||||
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"),
|
||||
ArgRecords;
|
||||
std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(), ai, ae;
|
||||
std::vector<Argument*> Args;
|
||||
std::vector<Argument*>::iterator ri, re;
|
||||
|
||||
OS << " switch (Kind) {\n";
|
||||
OS << " default:\n";
|
||||
OS << " assert(0 && \"Unknown attribute!\");\n";
|
||||
OS << " break;\n";
|
||||
for (; i != e; ++i) {
|
||||
Record &R = **i;
|
||||
OS << " case attr::" << R.getName() << ": {\n";
|
||||
if (R.isSubClassOf(InhClass))
|
||||
OS << " bool isInherited = Record[Idx++];\n";
|
||||
ArgRecords = R.getValueAsListOfDefs("Args");
|
||||
Args.clear();
|
||||
for (ai = ArgRecords.begin(), ae = ArgRecords.end(); ai != ae; ++ai) {
|
||||
Argument *A = createArgument(**ai, R.getName());
|
||||
Args.push_back(A);
|
||||
A->writePCHReadDecls(OS);
|
||||
}
|
||||
OS << " New = new (Context) " << R.getName() << "Attr(Range, Context";
|
||||
for (ri = Args.begin(), re = Args.end(); ri != re; ++ri) {
|
||||
OS << ", ";
|
||||
(*ri)->writePCHReadArgs(OS);
|
||||
}
|
||||
OS << ");\n";
|
||||
if (R.isSubClassOf(InhClass))
|
||||
OS << " cast<InheritableAttr>(New)->setInherited(isInherited);\n";
|
||||
OS << " break;\n";
|
||||
OS << " }\n";
|
||||
}
|
||||
OS << " }\n";
|
||||
}
|
||||
|
||||
void ClangAttrPCHWriteEmitter::run(raw_ostream &OS) {
|
||||
Record *InhClass = Records.getClass("InheritableAttr");
|
||||
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), Args;
|
||||
std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(), ai, ae;
|
||||
|
||||
OS << " switch (A->getKind()) {\n";
|
||||
OS << " default:\n";
|
||||
OS << " llvm_unreachable(\"Unknown attribute kind!\");\n";
|
||||
OS << " break;\n";
|
||||
for (; i != e; ++i) {
|
||||
Record &R = **i;
|
||||
OS << " case attr::" << R.getName() << ": {\n";
|
||||
Args = R.getValueAsListOfDefs("Args");
|
||||
if (R.isSubClassOf(InhClass) || !Args.empty())
|
||||
OS << " const " << R.getName() << "Attr *SA = cast<" << R.getName()
|
||||
<< "Attr>(A);\n";
|
||||
if (R.isSubClassOf(InhClass))
|
||||
OS << " Record.push_back(SA->isInherited());\n";
|
||||
for (ai = Args.begin(), ae = Args.end(); ai != ae; ++ai)
|
||||
createArgument(**ai, R.getName())->writePCHWrite(OS);
|
||||
OS << " break;\n";
|
||||
OS << " }\n";
|
||||
}
|
||||
OS << " }\n";
|
||||
}
|
||||
|
||||
void ClangAttrSpellingListEmitter::run(raw_ostream &OS) {
|
||||
OS << "// This file is generated by TableGen. Do not edit.\n\n";
|
||||
|
||||
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
|
||||
|
||||
for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end(); I != E; ++I) {
|
||||
Record &Attr = **I;
|
||||
|
||||
std::vector<StringRef> Spellings = getValueAsListOfStrings(Attr, "Spellings");
|
||||
|
||||
for (std::vector<StringRef>::const_iterator I = Spellings.begin(), E = Spellings.end(); I != E; ++I) {
|
||||
StringRef Spelling = *I;
|
||||
OS << ".Case(\"" << Spelling << "\", true)\n";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ClangAttrLateParsedListEmitter::run(raw_ostream &OS) {
|
||||
OS << "// This file is generated by TableGen. Do not edit.\n\n";
|
||||
|
||||
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
|
||||
|
||||
for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end();
|
||||
I != E; ++I) {
|
||||
Record &Attr = **I;
|
||||
|
||||
bool LateParsed = Attr.getValueAsBit("LateParsed");
|
||||
|
||||
if (LateParsed) {
|
||||
std::vector<StringRef> Spellings =
|
||||
getValueAsListOfStrings(Attr, "Spellings");
|
||||
|
||||
for (std::vector<StringRef>::const_iterator I = Spellings.begin(),
|
||||
E = Spellings.end(); I != E; ++I) {
|
||||
OS << ".Case(\"" << (*I) << "\", " << LateParsed << ")\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
//===- ClangAttrEmitter.h - Generate Clang attribute handling =-*- C++ -*--===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// These tablegen backends emit Clang attribute processing code
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef CLANGATTR_EMITTER_H
|
||||
#define CLANGATTR_EMITTER_H
|
||||
|
||||
#include "llvm/TableGen/TableGenBackend.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// ClangAttrClassEmitter - class emits the class defintions for attributes for
|
||||
/// clang.
|
||||
class ClangAttrClassEmitter : public TableGenBackend {
|
||||
RecordKeeper &Records;
|
||||
|
||||
public:
|
||||
explicit ClangAttrClassEmitter(RecordKeeper &R)
|
||||
: Records(R)
|
||||
{}
|
||||
|
||||
void run(raw_ostream &OS);
|
||||
};
|
||||
|
||||
/// ClangAttrImplEmitter - class emits the class method defintions for
|
||||
/// attributes for clang.
|
||||
class ClangAttrImplEmitter : public TableGenBackend {
|
||||
RecordKeeper &Records;
|
||||
|
||||
public:
|
||||
explicit ClangAttrImplEmitter(RecordKeeper &R)
|
||||
: Records(R)
|
||||
{}
|
||||
|
||||
void run(raw_ostream &OS);
|
||||
};
|
||||
|
||||
/// ClangAttrListEmitter - class emits the enumeration list for attributes for
|
||||
/// clang.
|
||||
class ClangAttrListEmitter : public TableGenBackend {
|
||||
RecordKeeper &Records;
|
||||
|
||||
public:
|
||||
explicit ClangAttrListEmitter(RecordKeeper &R)
|
||||
: Records(R)
|
||||
{}
|
||||
|
||||
void run(raw_ostream &OS);
|
||||
};
|
||||
|
||||
/// ClangAttrPCHReadEmitter - class emits the code to read an attribute from
|
||||
/// a clang precompiled header.
|
||||
class ClangAttrPCHReadEmitter : public TableGenBackend {
|
||||
RecordKeeper &Records;
|
||||
|
||||
public:
|
||||
explicit ClangAttrPCHReadEmitter(RecordKeeper &R)
|
||||
: Records(R)
|
||||
{}
|
||||
|
||||
void run(raw_ostream &OS);
|
||||
};
|
||||
|
||||
/// ClangAttrPCHWriteEmitter - class emits the code to read an attribute from
|
||||
/// a clang precompiled header.
|
||||
class ClangAttrPCHWriteEmitter : public TableGenBackend {
|
||||
RecordKeeper &Records;
|
||||
|
||||
public:
|
||||
explicit ClangAttrPCHWriteEmitter(RecordKeeper &R)
|
||||
: Records(R)
|
||||
{}
|
||||
|
||||
void run(raw_ostream &OS);
|
||||
};
|
||||
|
||||
/// ClangAttrSpellingListEmitter - class emits the list of spellings for attributes for
|
||||
/// clang.
|
||||
class ClangAttrSpellingListEmitter : public TableGenBackend {
|
||||
RecordKeeper &Records;
|
||||
|
||||
public:
|
||||
explicit ClangAttrSpellingListEmitter(RecordKeeper &R)
|
||||
: Records(R)
|
||||
{}
|
||||
|
||||
void run(raw_ostream &OS);
|
||||
};
|
||||
|
||||
/// ClangAttrLateParsedListEmitter emits the LateParsed property for attributes
|
||||
/// for clang.
|
||||
class ClangAttrLateParsedListEmitter : public TableGenBackend {
|
||||
RecordKeeper &Records;
|
||||
|
||||
public:
|
||||
explicit ClangAttrLateParsedListEmitter(RecordKeeper &R)
|
||||
: Records(R)
|
||||
{}
|
||||
|
||||
void run(raw_ostream &OS);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,378 @@
|
|||
//=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- C++ -*-
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// These tablegen backends emit Clang diagnostics tables.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ClangDiagnosticsEmitter.h"
|
||||
#include "llvm/TableGen/Record.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/VectorExtras.h"
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
using namespace llvm;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Diagnostic category computation code.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
class DiagGroupParentMap {
|
||||
RecordKeeper &Records;
|
||||
std::map<const Record*, std::vector<Record*> > Mapping;
|
||||
public:
|
||||
DiagGroupParentMap(RecordKeeper &records) : Records(records) {
|
||||
std::vector<Record*> DiagGroups
|
||||
= Records.getAllDerivedDefinitions("DiagGroup");
|
||||
for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
|
||||
std::vector<Record*> SubGroups =
|
||||
DiagGroups[i]->getValueAsListOfDefs("SubGroups");
|
||||
for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
|
||||
Mapping[SubGroups[j]].push_back(DiagGroups[i]);
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<Record*> &getParents(const Record *Group) {
|
||||
return Mapping[Group];
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace.
|
||||
|
||||
|
||||
static std::string
|
||||
getCategoryFromDiagGroup(const Record *Group,
|
||||
DiagGroupParentMap &DiagGroupParents) {
|
||||
// If the DiagGroup has a category, return it.
|
||||
std::string CatName = Group->getValueAsString("CategoryName");
|
||||
if (!CatName.empty()) return CatName;
|
||||
|
||||
// The diag group may the subgroup of one or more other diagnostic groups,
|
||||
// check these for a category as well.
|
||||
const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
|
||||
for (unsigned i = 0, e = Parents.size(); i != e; ++i) {
|
||||
CatName = getCategoryFromDiagGroup(Parents[i], DiagGroupParents);
|
||||
if (!CatName.empty()) return CatName;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/// getDiagnosticCategory - Return the category that the specified diagnostic
|
||||
/// lives in.
|
||||
static std::string getDiagnosticCategory(const Record *R,
|
||||
DiagGroupParentMap &DiagGroupParents) {
|
||||
// If the diagnostic is in a group, and that group has a category, use it.
|
||||
if (DefInit *Group = dynamic_cast<DefInit*>(R->getValueInit("Group"))) {
|
||||
// Check the diagnostic's diag group for a category.
|
||||
std::string CatName = getCategoryFromDiagGroup(Group->getDef(),
|
||||
DiagGroupParents);
|
||||
if (!CatName.empty()) return CatName;
|
||||
}
|
||||
|
||||
// If the diagnostic itself has a category, get it.
|
||||
return R->getValueAsString("CategoryName");
|
||||
}
|
||||
|
||||
namespace {
|
||||
class DiagCategoryIDMap {
|
||||
RecordKeeper &Records;
|
||||
StringMap<unsigned> CategoryIDs;
|
||||
std::vector<std::string> CategoryStrings;
|
||||
public:
|
||||
DiagCategoryIDMap(RecordKeeper &records) : Records(records) {
|
||||
DiagGroupParentMap ParentInfo(Records);
|
||||
|
||||
// The zero'th category is "".
|
||||
CategoryStrings.push_back("");
|
||||
CategoryIDs[""] = 0;
|
||||
|
||||
std::vector<Record*> Diags =
|
||||
Records.getAllDerivedDefinitions("Diagnostic");
|
||||
for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
|
||||
std::string Category = getDiagnosticCategory(Diags[i], ParentInfo);
|
||||
if (Category.empty()) continue; // Skip diags with no category.
|
||||
|
||||
unsigned &ID = CategoryIDs[Category];
|
||||
if (ID != 0) continue; // Already seen.
|
||||
|
||||
ID = CategoryStrings.size();
|
||||
CategoryStrings.push_back(Category);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned getID(StringRef CategoryString) {
|
||||
return CategoryIDs[CategoryString];
|
||||
}
|
||||
|
||||
typedef std::vector<std::string>::iterator iterator;
|
||||
iterator begin() { return CategoryStrings.begin(); }
|
||||
iterator end() { return CategoryStrings.end(); }
|
||||
};
|
||||
} // end anonymous namespace.
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Warning Tables (.inc file) generation.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void ClangDiagsDefsEmitter::run(raw_ostream &OS) {
|
||||
// Write the #if guard
|
||||
if (!Component.empty()) {
|
||||
std::string ComponentName = UppercaseString(Component);
|
||||
OS << "#ifdef " << ComponentName << "START\n";
|
||||
OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName
|
||||
<< ",\n";
|
||||
OS << "#undef " << ComponentName << "START\n";
|
||||
OS << "#endif\n\n";
|
||||
}
|
||||
|
||||
const std::vector<Record*> &Diags =
|
||||
Records.getAllDerivedDefinitions("Diagnostic");
|
||||
|
||||
DiagCategoryIDMap CategoryIDs(Records);
|
||||
DiagGroupParentMap DGParentMap(Records);
|
||||
|
||||
for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
|
||||
const Record &R = *Diags[i];
|
||||
// Filter by component.
|
||||
if (!Component.empty() && Component != R.getValueAsString("Component"))
|
||||
continue;
|
||||
|
||||
OS << "DIAG(" << R.getName() << ", ";
|
||||
OS << R.getValueAsDef("Class")->getName();
|
||||
OS << ", diag::" << R.getValueAsDef("DefaultMapping")->getName();
|
||||
|
||||
// Description string.
|
||||
OS << ", \"";
|
||||
OS.write_escaped(R.getValueAsString("Text")) << '"';
|
||||
|
||||
// Warning associated with the diagnostic.
|
||||
if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group"))) {
|
||||
OS << ", \"";
|
||||
OS.write_escaped(DI->getDef()->getValueAsString("GroupName")) << '"';
|
||||
} else {
|
||||
OS << ", \"\"";
|
||||
}
|
||||
|
||||
// SFINAE bit
|
||||
if (R.getValueAsBit("SFINAE"))
|
||||
OS << ", true";
|
||||
else
|
||||
OS << ", false";
|
||||
|
||||
// Access control bit
|
||||
if (R.getValueAsBit("AccessControl"))
|
||||
OS << ", true";
|
||||
else
|
||||
OS << ", false";
|
||||
|
||||
// FIXME: This condition is just to avoid temporary revlock, it can be
|
||||
// removed.
|
||||
if (R.getValue("WarningNoWerror")) {
|
||||
// Default warning has no Werror bit.
|
||||
if (R.getValueAsBit("WarningNoWerror"))
|
||||
OS << ", true";
|
||||
else
|
||||
OS << ", false";
|
||||
|
||||
// Default warning show in system header bit.
|
||||
if (R.getValueAsBit("WarningShowInSystemHeader"))
|
||||
OS << ", true";
|
||||
else
|
||||
OS << ", false";
|
||||
}
|
||||
|
||||
// Category number.
|
||||
OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap));
|
||||
|
||||
// Brief
|
||||
OS << ", \"";
|
||||
OS.write_escaped(R.getValueAsString("Brief")) << '"';
|
||||
|
||||
// Explanation
|
||||
OS << ", \"";
|
||||
OS.write_escaped(R.getValueAsString("Explanation")) << '"';
|
||||
OS << ")\n";
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Warning Group Tables generation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static std::string getDiagCategoryEnum(llvm::StringRef name) {
|
||||
if (name.empty())
|
||||
return "DiagCat_None";
|
||||
llvm::SmallString<256> enumName = llvm::StringRef("DiagCat_");
|
||||
for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I)
|
||||
enumName += isalnum(*I) ? *I : '_';
|
||||
return enumName.str();
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct GroupInfo {
|
||||
std::vector<const Record*> DiagsInGroup;
|
||||
std::vector<std::string> SubGroups;
|
||||
unsigned IDNo;
|
||||
};
|
||||
} // end anonymous namespace.
|
||||
|
||||
void ClangDiagGroupsEmitter::run(raw_ostream &OS) {
|
||||
// Compute a mapping from a DiagGroup to all of its parents.
|
||||
DiagGroupParentMap DGParentMap(Records);
|
||||
|
||||
// Invert the 1-[0/1] mapping of diags to group into a one to many mapping of
|
||||
// groups to diags in the group.
|
||||
std::map<std::string, GroupInfo> DiagsInGroup;
|
||||
|
||||
std::vector<Record*> Diags =
|
||||
Records.getAllDerivedDefinitions("Diagnostic");
|
||||
for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
|
||||
const Record *R = Diags[i];
|
||||
DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("Group"));
|
||||
if (DI == 0) continue;
|
||||
std::string GroupName = DI->getDef()->getValueAsString("GroupName");
|
||||
DiagsInGroup[GroupName].DiagsInGroup.push_back(R);
|
||||
}
|
||||
|
||||
// Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty
|
||||
// groups (these are warnings that GCC supports that clang never produces).
|
||||
std::vector<Record*> DiagGroups
|
||||
= Records.getAllDerivedDefinitions("DiagGroup");
|
||||
for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
|
||||
Record *Group = DiagGroups[i];
|
||||
GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")];
|
||||
|
||||
std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups");
|
||||
for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
|
||||
GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName"));
|
||||
}
|
||||
|
||||
// Assign unique ID numbers to the groups.
|
||||
unsigned IDNo = 0;
|
||||
for (std::map<std::string, GroupInfo>::iterator
|
||||
I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo)
|
||||
I->second.IDNo = IDNo;
|
||||
|
||||
// Walk through the groups emitting an array for each diagnostic of the diags
|
||||
// that are mapped to.
|
||||
OS << "\n#ifdef GET_DIAG_ARRAYS\n";
|
||||
unsigned MaxLen = 0;
|
||||
for (std::map<std::string, GroupInfo>::iterator
|
||||
I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
|
||||
MaxLen = std::max(MaxLen, (unsigned)I->first.size());
|
||||
|
||||
std::vector<const Record*> &V = I->second.DiagsInGroup;
|
||||
if (!V.empty()) {
|
||||
OS << "static const short DiagArray" << I->second.IDNo << "[] = { ";
|
||||
for (unsigned i = 0, e = V.size(); i != e; ++i)
|
||||
OS << "diag::" << V[i]->getName() << ", ";
|
||||
OS << "-1 };\n";
|
||||
}
|
||||
|
||||
const std::vector<std::string> &SubGroups = I->second.SubGroups;
|
||||
if (!SubGroups.empty()) {
|
||||
OS << "static const short DiagSubGroup" << I->second.IDNo << "[] = { ";
|
||||
for (unsigned i = 0, e = SubGroups.size(); i != e; ++i) {
|
||||
std::map<std::string, GroupInfo>::iterator RI =
|
||||
DiagsInGroup.find(SubGroups[i]);
|
||||
assert(RI != DiagsInGroup.end() && "Referenced without existing?");
|
||||
OS << RI->second.IDNo << ", ";
|
||||
}
|
||||
OS << "-1 };\n";
|
||||
}
|
||||
}
|
||||
OS << "#endif // GET_DIAG_ARRAYS\n\n";
|
||||
|
||||
// Emit the table now.
|
||||
OS << "\n#ifdef GET_DIAG_TABLE\n";
|
||||
for (std::map<std::string, GroupInfo>::iterator
|
||||
I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
|
||||
// Group option string.
|
||||
OS << " { ";
|
||||
OS << I->first.size() << ", ";
|
||||
OS << "\"";
|
||||
OS.write_escaped(I->first) << "\","
|
||||
<< std::string(MaxLen-I->first.size()+1, ' ');
|
||||
|
||||
// Diagnostics in the group.
|
||||
if (I->second.DiagsInGroup.empty())
|
||||
OS << "0, ";
|
||||
else
|
||||
OS << "DiagArray" << I->second.IDNo << ", ";
|
||||
|
||||
// Subgroups.
|
||||
if (I->second.SubGroups.empty())
|
||||
OS << 0;
|
||||
else
|
||||
OS << "DiagSubGroup" << I->second.IDNo;
|
||||
OS << " },\n";
|
||||
}
|
||||
OS << "#endif // GET_DIAG_TABLE\n\n";
|
||||
|
||||
// Emit the category table next.
|
||||
DiagCategoryIDMap CategoriesByID(Records);
|
||||
OS << "\n#ifdef GET_CATEGORY_TABLE\n";
|
||||
for (DiagCategoryIDMap::iterator I = CategoriesByID.begin(),
|
||||
E = CategoriesByID.end(); I != E; ++I)
|
||||
OS << "CATEGORY(\"" << *I << "\", " << getDiagCategoryEnum(*I) << ")\n";
|
||||
OS << "#endif // GET_CATEGORY_TABLE\n\n";
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Diagnostic name index generation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
struct RecordIndexElement
|
||||
{
|
||||
RecordIndexElement() {}
|
||||
explicit RecordIndexElement(Record const &R):
|
||||
Name(R.getName()) {}
|
||||
|
||||
std::string Name;
|
||||
};
|
||||
|
||||
struct RecordIndexElementSorter :
|
||||
public std::binary_function<RecordIndexElement, RecordIndexElement, bool> {
|
||||
|
||||
bool operator()(RecordIndexElement const &Lhs,
|
||||
RecordIndexElement const &Rhs) const {
|
||||
return Lhs.Name < Rhs.Name;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // end anonymous namespace.
|
||||
|
||||
void ClangDiagsIndexNameEmitter::run(raw_ostream &OS) {
|
||||
const std::vector<Record*> &Diags =
|
||||
Records.getAllDerivedDefinitions("Diagnostic");
|
||||
|
||||
std::vector<RecordIndexElement> Index;
|
||||
Index.reserve(Diags.size());
|
||||
for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
|
||||
const Record &R = *(Diags[i]);
|
||||
Index.push_back(RecordIndexElement(R));
|
||||
}
|
||||
|
||||
std::sort(Index.begin(), Index.end(), RecordIndexElementSorter());
|
||||
|
||||
for (unsigned i = 0, e = Index.size(); i != e; ++i) {
|
||||
const RecordIndexElement &R = Index[i];
|
||||
|
||||
OS << "DIAG_NAME_INDEX(" << R.Name << ")\n";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
//===- ClangDiagnosticsEmitter.h - Generate Clang diagnostics tables -*- C++ -*-
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// These tablegen backends emit Clang diagnostics tables.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef CLANGDIAGS_EMITTER_H
|
||||
#define CLANGDIAGS_EMITTER_H
|
||||
|
||||
#include "llvm/TableGen/TableGenBackend.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// ClangDiagsDefsEmitter - The top-level class emits .def files containing
|
||||
/// declarations of Clang diagnostics.
|
||||
///
|
||||
class ClangDiagsDefsEmitter : public TableGenBackend {
|
||||
RecordKeeper &Records;
|
||||
const std::string& Component;
|
||||
public:
|
||||
explicit ClangDiagsDefsEmitter(RecordKeeper &R, const std::string& component)
|
||||
: Records(R), Component(component) {}
|
||||
|
||||
// run - Output the .def file contents
|
||||
void run(raw_ostream &OS);
|
||||
};
|
||||
|
||||
class ClangDiagGroupsEmitter : public TableGenBackend {
|
||||
RecordKeeper &Records;
|
||||
public:
|
||||
explicit ClangDiagGroupsEmitter(RecordKeeper &R) : Records(R) {}
|
||||
|
||||
void run(raw_ostream &OS);
|
||||
};
|
||||
|
||||
class ClangDiagsIndexNameEmitter : public TableGenBackend {
|
||||
RecordKeeper &Records;
|
||||
public:
|
||||
explicit ClangDiagsIndexNameEmitter(RecordKeeper &R) : Records(R) {}
|
||||
|
||||
void run(raw_ostream &OS);
|
||||
};
|
||||
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
|
@ -0,0 +1,319 @@
|
|||
//=- ClangSACheckersEmitter.cpp - Generate Clang SA checkers tables -*- C++ -*-
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This tablegen backend emits Clang Static Analyzer checkers tables.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ClangSACheckersEmitter.h"
|
||||
#include "llvm/TableGen/Record.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
using namespace llvm;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Static Analyzer Checkers Tables generation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// \brief True if it is specified hidden or a parent package is specified
|
||||
/// as hidden, otherwise false.
|
||||
static bool isHidden(const Record &R) {
|
||||
if (R.getValueAsBit("Hidden"))
|
||||
return true;
|
||||
// Not declared as hidden, check the parent package if it is hidden.
|
||||
if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("ParentPackage")))
|
||||
return isHidden(*DI->getDef());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool isCheckerNamed(const Record *R) {
|
||||
return !R->getValueAsString("CheckerName").empty();
|
||||
}
|
||||
|
||||
static std::string getPackageFullName(const Record *R);
|
||||
|
||||
static std::string getParentPackageFullName(const Record *R) {
|
||||
std::string name;
|
||||
if (DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("ParentPackage")))
|
||||
name = getPackageFullName(DI->getDef());
|
||||
return name;
|
||||
}
|
||||
|
||||
static std::string getPackageFullName(const Record *R) {
|
||||
std::string name = getParentPackageFullName(R);
|
||||
if (!name.empty()) name += ".";
|
||||
return name + R->getValueAsString("PackageName");
|
||||
}
|
||||
|
||||
static std::string getCheckerFullName(const Record *R) {
|
||||
std::string name = getParentPackageFullName(R);
|
||||
if (isCheckerNamed(R)) {
|
||||
if (!name.empty()) name += ".";
|
||||
name += R->getValueAsString("CheckerName");
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
static std::string getStringValue(const Record &R, StringRef field) {
|
||||
if (StringInit *
|
||||
SI = dynamic_cast<StringInit*>(R.getValueInit(field)))
|
||||
return SI->getValue();
|
||||
return std::string();
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct GroupInfo {
|
||||
llvm::DenseSet<const Record*> Checkers;
|
||||
llvm::DenseSet<const Record *> SubGroups;
|
||||
bool Hidden;
|
||||
unsigned Index;
|
||||
|
||||
GroupInfo() : Hidden(false) { }
|
||||
};
|
||||
}
|
||||
|
||||
static void addPackageToCheckerGroup(const Record *package, const Record *group,
|
||||
llvm::DenseMap<const Record *, GroupInfo *> &recordGroupMap) {
|
||||
llvm::DenseSet<const Record *> &checkers = recordGroupMap[package]->Checkers;
|
||||
for (llvm::DenseSet<const Record *>::iterator
|
||||
I = checkers.begin(), E = checkers.end(); I != E; ++I)
|
||||
recordGroupMap[group]->Checkers.insert(*I);
|
||||
|
||||
llvm::DenseSet<const Record *> &subGroups = recordGroupMap[package]->SubGroups;
|
||||
for (llvm::DenseSet<const Record *>::iterator
|
||||
I = subGroups.begin(), E = subGroups.end(); I != E; ++I)
|
||||
addPackageToCheckerGroup(*I, group, recordGroupMap);
|
||||
}
|
||||
|
||||
void ClangSACheckersEmitter::run(raw_ostream &OS) {
|
||||
std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker");
|
||||
llvm::DenseMap<const Record *, unsigned> checkerRecIndexMap;
|
||||
for (unsigned i = 0, e = checkers.size(); i != e; ++i)
|
||||
checkerRecIndexMap[checkers[i]] = i;
|
||||
|
||||
// Invert the mapping of checkers to package/group into a one to many
|
||||
// mapping of packages/groups to checkers.
|
||||
std::map<std::string, GroupInfo> groupInfoByName;
|
||||
llvm::DenseMap<const Record *, GroupInfo *> recordGroupMap;
|
||||
|
||||
std::vector<Record*> packages = Records.getAllDerivedDefinitions("Package");
|
||||
for (unsigned i = 0, e = packages.size(); i != e; ++i) {
|
||||
Record *R = packages[i];
|
||||
std::string fullName = getPackageFullName(R);
|
||||
if (!fullName.empty()) {
|
||||
GroupInfo &info = groupInfoByName[fullName];
|
||||
info.Hidden = isHidden(*R);
|
||||
recordGroupMap[R] = &info;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Record*>
|
||||
checkerGroups = Records.getAllDerivedDefinitions("CheckerGroup");
|
||||
for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i) {
|
||||
Record *R = checkerGroups[i];
|
||||
std::string name = R->getValueAsString("GroupName");
|
||||
if (!name.empty()) {
|
||||
GroupInfo &info = groupInfoByName[name];
|
||||
recordGroupMap[R] = &info;
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0, e = checkers.size(); i != e; ++i) {
|
||||
Record *R = checkers[i];
|
||||
Record *package = 0;
|
||||
if (DefInit *
|
||||
DI = dynamic_cast<DefInit*>(R->getValueInit("ParentPackage")))
|
||||
package = DI->getDef();
|
||||
if (!isCheckerNamed(R) && !package)
|
||||
throw "Checker '" + R->getName() + "' is neither named, nor in a package!";
|
||||
|
||||
if (isCheckerNamed(R)) {
|
||||
// Create a pseudo-group to hold this checker.
|
||||
std::string fullName = getCheckerFullName(R);
|
||||
GroupInfo &info = groupInfoByName[fullName];
|
||||
info.Hidden = R->getValueAsBit("Hidden");
|
||||
recordGroupMap[R] = &info;
|
||||
info.Checkers.insert(R);
|
||||
} else {
|
||||
recordGroupMap[package]->Checkers.insert(R);
|
||||
}
|
||||
|
||||
Record *currR = isCheckerNamed(R) ? R : package;
|
||||
// Insert the checker and its parent packages into the subgroups set of
|
||||
// the corresponding parent package.
|
||||
while (DefInit *DI
|
||||
= dynamic_cast<DefInit*>(currR->getValueInit("ParentPackage"))) {
|
||||
Record *parentPackage = DI->getDef();
|
||||
recordGroupMap[parentPackage]->SubGroups.insert(currR);
|
||||
currR = parentPackage;
|
||||
}
|
||||
// Insert the checker into the set of its group.
|
||||
if (DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("Group")))
|
||||
recordGroupMap[DI->getDef()]->Checkers.insert(R);
|
||||
}
|
||||
|
||||
// If a package is in group, add all its checkers and its sub-packages
|
||||
// checkers into the group.
|
||||
for (unsigned i = 0, e = packages.size(); i != e; ++i)
|
||||
if (DefInit *DI = dynamic_cast<DefInit*>(packages[i]->getValueInit("Group")))
|
||||
addPackageToCheckerGroup(packages[i], DI->getDef(), recordGroupMap);
|
||||
|
||||
typedef std::map<std::string, const Record *> SortedRecords;
|
||||
typedef llvm::DenseMap<const Record *, unsigned> RecToSortIndex;
|
||||
|
||||
SortedRecords sortedGroups;
|
||||
RecToSortIndex groupToSortIndex;
|
||||
OS << "\n#ifdef GET_GROUPS\n";
|
||||
{
|
||||
for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i)
|
||||
sortedGroups[checkerGroups[i]->getValueAsString("GroupName")]
|
||||
= checkerGroups[i];
|
||||
|
||||
unsigned sortIndex = 0;
|
||||
for (SortedRecords::iterator
|
||||
I = sortedGroups.begin(), E = sortedGroups.end(); I != E; ++I) {
|
||||
const Record *R = I->second;
|
||||
|
||||
OS << "GROUP(" << "\"";
|
||||
OS.write_escaped(R->getValueAsString("GroupName")) << "\"";
|
||||
OS << ")\n";
|
||||
|
||||
groupToSortIndex[R] = sortIndex++;
|
||||
}
|
||||
}
|
||||
OS << "#endif // GET_GROUPS\n\n";
|
||||
|
||||
OS << "\n#ifdef GET_PACKAGES\n";
|
||||
{
|
||||
SortedRecords sortedPackages;
|
||||
for (unsigned i = 0, e = packages.size(); i != e; ++i)
|
||||
sortedPackages[getPackageFullName(packages[i])] = packages[i];
|
||||
|
||||
for (SortedRecords::iterator
|
||||
I = sortedPackages.begin(), E = sortedPackages.end(); I != E; ++I) {
|
||||
const Record &R = *I->second;
|
||||
|
||||
OS << "PACKAGE(" << "\"";
|
||||
OS.write_escaped(getPackageFullName(&R)) << "\", ";
|
||||
// Group index
|
||||
if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group")))
|
||||
OS << groupToSortIndex[DI->getDef()] << ", ";
|
||||
else
|
||||
OS << "-1, ";
|
||||
// Hidden bit
|
||||
if (isHidden(R))
|
||||
OS << "true";
|
||||
else
|
||||
OS << "false";
|
||||
OS << ")\n";
|
||||
}
|
||||
}
|
||||
OS << "#endif // GET_PACKAGES\n\n";
|
||||
|
||||
OS << "\n#ifdef GET_CHECKERS\n";
|
||||
for (unsigned i = 0, e = checkers.size(); i != e; ++i) {
|
||||
const Record &R = *checkers[i];
|
||||
|
||||
OS << "CHECKER(" << "\"";
|
||||
std::string name;
|
||||
if (isCheckerNamed(&R))
|
||||
name = getCheckerFullName(&R);
|
||||
OS.write_escaped(name) << "\", ";
|
||||
OS << R.getName() << ", ";
|
||||
OS << getStringValue(R, "DescFile") << ", ";
|
||||
OS << "\"";
|
||||
OS.write_escaped(getStringValue(R, "HelpText")) << "\", ";
|
||||
// Group index
|
||||
if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group")))
|
||||
OS << groupToSortIndex[DI->getDef()] << ", ";
|
||||
else
|
||||
OS << "-1, ";
|
||||
// Hidden bit
|
||||
if (isHidden(R))
|
||||
OS << "true";
|
||||
else
|
||||
OS << "false";
|
||||
OS << ")\n";
|
||||
}
|
||||
OS << "#endif // GET_CHECKERS\n\n";
|
||||
|
||||
unsigned index = 0;
|
||||
for (std::map<std::string, GroupInfo>::iterator
|
||||
I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I)
|
||||
I->second.Index = index++;
|
||||
|
||||
// Walk through the packages/groups/checkers emitting an array for each
|
||||
// set of checkers and an array for each set of subpackages.
|
||||
|
||||
OS << "\n#ifdef GET_MEMBER_ARRAYS\n";
|
||||
unsigned maxLen = 0;
|
||||
for (std::map<std::string, GroupInfo>::iterator
|
||||
I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) {
|
||||
maxLen = std::max(maxLen, (unsigned)I->first.size());
|
||||
|
||||
llvm::DenseSet<const Record *> &checkers = I->second.Checkers;
|
||||
if (!checkers.empty()) {
|
||||
OS << "static const short CheckerArray" << I->second.Index << "[] = { ";
|
||||
// Make the output order deterministic.
|
||||
std::map<int, const Record *> sorted;
|
||||
for (llvm::DenseSet<const Record *>::iterator
|
||||
I = checkers.begin(), E = checkers.end(); I != E; ++I)
|
||||
sorted[(*I)->getID()] = *I;
|
||||
|
||||
for (std::map<int, const Record *>::iterator
|
||||
I = sorted.begin(), E = sorted.end(); I != E; ++I)
|
||||
OS << checkerRecIndexMap[I->second] << ", ";
|
||||
OS << "-1 };\n";
|
||||
}
|
||||
|
||||
llvm::DenseSet<const Record *> &subGroups = I->second.SubGroups;
|
||||
if (!subGroups.empty()) {
|
||||
OS << "static const short SubPackageArray" << I->second.Index << "[] = { ";
|
||||
// Make the output order deterministic.
|
||||
std::map<int, const Record *> sorted;
|
||||
for (llvm::DenseSet<const Record *>::iterator
|
||||
I = subGroups.begin(), E = subGroups.end(); I != E; ++I)
|
||||
sorted[(*I)->getID()] = *I;
|
||||
|
||||
for (std::map<int, const Record *>::iterator
|
||||
I = sorted.begin(), E = sorted.end(); I != E; ++I) {
|
||||
OS << recordGroupMap[I->second]->Index << ", ";
|
||||
}
|
||||
OS << "-1 };\n";
|
||||
}
|
||||
}
|
||||
OS << "#endif // GET_MEMBER_ARRAYS\n\n";
|
||||
|
||||
OS << "\n#ifdef GET_CHECKNAME_TABLE\n";
|
||||
for (std::map<std::string, GroupInfo>::iterator
|
||||
I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) {
|
||||
// Group option string.
|
||||
OS << " { \"";
|
||||
OS.write_escaped(I->first) << "\","
|
||||
<< std::string(maxLen-I->first.size()+1, ' ');
|
||||
|
||||
if (I->second.Checkers.empty())
|
||||
OS << "0, ";
|
||||
else
|
||||
OS << "CheckerArray" << I->second.Index << ", ";
|
||||
|
||||
// Subgroups.
|
||||
if (I->second.SubGroups.empty())
|
||||
OS << "0, ";
|
||||
else
|
||||
OS << "SubPackageArray" << I->second.Index << ", ";
|
||||
|
||||
OS << (I->second.Hidden ? "true" : "false");
|
||||
|
||||
OS << " },\n";
|
||||
}
|
||||
OS << "#endif // GET_CHECKNAME_TABLE\n\n";
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
//===- ClangSACheckersEmitter.h - Generate Clang SA checkers tables -*- C++ -*-
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This tablegen backend emits Clang Static Analyzer checkers tables.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef CLANGSACHECKERS_EMITTER_H
|
||||
#define CLANGSACHECKERS_EMITTER_H
|
||||
|
||||
#include "llvm/TableGen/TableGenBackend.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class ClangSACheckersEmitter : public TableGenBackend {
|
||||
RecordKeeper &Records;
|
||||
public:
|
||||
explicit ClangSACheckersEmitter(RecordKeeper &R) : Records(R) {}
|
||||
|
||||
void run(raw_ostream &OS);
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
|
@ -0,0 +1,19 @@
|
|||
##===- utils/TableGen/Makefile -----------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
CLANG_LEVEL = ../..
|
||||
TOOLNAME = clang-tblgen
|
||||
USEDLIBS = LLVMTableGen.a LLVMSupport.a
|
||||
REQUIRES_EH := 1
|
||||
REQUIRES_RTTI := 1
|
||||
|
||||
# This tool has no plugins, optimize startup time.
|
||||
TOOL_NO_EXPORTS = 1
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,176 @@
|
|||
//===- NeonEmitter.h - Generate arm_neon.h for use with clang ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This tablegen backend is responsible for emitting arm_neon.h, which includes
|
||||
// a declaration and definition of each function specified by the ARM NEON
|
||||
// compiler interface. See ARM document DUI0348B.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef NEON_EMITTER_H
|
||||
#define NEON_EMITTER_H
|
||||
|
||||
#include "llvm/TableGen/Record.h"
|
||||
#include "llvm/TableGen/TableGenBackend.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
|
||||
enum OpKind {
|
||||
OpNone,
|
||||
OpAdd,
|
||||
OpAddl,
|
||||
OpAddw,
|
||||
OpSub,
|
||||
OpSubl,
|
||||
OpSubw,
|
||||
OpMul,
|
||||
OpMla,
|
||||
OpMlal,
|
||||
OpMls,
|
||||
OpMlsl,
|
||||
OpMulN,
|
||||
OpMlaN,
|
||||
OpMlsN,
|
||||
OpMlalN,
|
||||
OpMlslN,
|
||||
OpMulLane,
|
||||
OpMullLane,
|
||||
OpMlaLane,
|
||||
OpMlsLane,
|
||||
OpMlalLane,
|
||||
OpMlslLane,
|
||||
OpQDMullLane,
|
||||
OpQDMlalLane,
|
||||
OpQDMlslLane,
|
||||
OpQDMulhLane,
|
||||
OpQRDMulhLane,
|
||||
OpEq,
|
||||
OpGe,
|
||||
OpLe,
|
||||
OpGt,
|
||||
OpLt,
|
||||
OpNeg,
|
||||
OpNot,
|
||||
OpAnd,
|
||||
OpOr,
|
||||
OpXor,
|
||||
OpAndNot,
|
||||
OpOrNot,
|
||||
OpCast,
|
||||
OpConcat,
|
||||
OpDup,
|
||||
OpDupLane,
|
||||
OpHi,
|
||||
OpLo,
|
||||
OpSelect,
|
||||
OpRev16,
|
||||
OpRev32,
|
||||
OpRev64,
|
||||
OpReinterpret,
|
||||
OpAbdl,
|
||||
OpAba,
|
||||
OpAbal
|
||||
};
|
||||
|
||||
enum ClassKind {
|
||||
ClassNone,
|
||||
ClassI, // generic integer instruction, e.g., "i8" suffix
|
||||
ClassS, // signed/unsigned/poly, e.g., "s8", "u8" or "p8" suffix
|
||||
ClassW, // width-specific instruction, e.g., "8" suffix
|
||||
ClassB // bitcast arguments with enum argument to specify type
|
||||
};
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class NeonEmitter : public TableGenBackend {
|
||||
RecordKeeper &Records;
|
||||
StringMap<OpKind> OpMap;
|
||||
DenseMap<Record*, ClassKind> ClassMap;
|
||||
|
||||
public:
|
||||
NeonEmitter(RecordKeeper &R) : Records(R) {
|
||||
OpMap["OP_NONE"] = OpNone;
|
||||
OpMap["OP_ADD"] = OpAdd;
|
||||
OpMap["OP_ADDL"] = OpAddl;
|
||||
OpMap["OP_ADDW"] = OpAddw;
|
||||
OpMap["OP_SUB"] = OpSub;
|
||||
OpMap["OP_SUBL"] = OpSubl;
|
||||
OpMap["OP_SUBW"] = OpSubw;
|
||||
OpMap["OP_MUL"] = OpMul;
|
||||
OpMap["OP_MLA"] = OpMla;
|
||||
OpMap["OP_MLAL"] = OpMlal;
|
||||
OpMap["OP_MLS"] = OpMls;
|
||||
OpMap["OP_MLSL"] = OpMlsl;
|
||||
OpMap["OP_MUL_N"] = OpMulN;
|
||||
OpMap["OP_MLA_N"] = OpMlaN;
|
||||
OpMap["OP_MLS_N"] = OpMlsN;
|
||||
OpMap["OP_MLAL_N"] = OpMlalN;
|
||||
OpMap["OP_MLSL_N"] = OpMlslN;
|
||||
OpMap["OP_MUL_LN"]= OpMulLane;
|
||||
OpMap["OP_MULL_LN"] = OpMullLane;
|
||||
OpMap["OP_MLA_LN"]= OpMlaLane;
|
||||
OpMap["OP_MLS_LN"]= OpMlsLane;
|
||||
OpMap["OP_MLAL_LN"] = OpMlalLane;
|
||||
OpMap["OP_MLSL_LN"] = OpMlslLane;
|
||||
OpMap["OP_QDMULL_LN"] = OpQDMullLane;
|
||||
OpMap["OP_QDMLAL_LN"] = OpQDMlalLane;
|
||||
OpMap["OP_QDMLSL_LN"] = OpQDMlslLane;
|
||||
OpMap["OP_QDMULH_LN"] = OpQDMulhLane;
|
||||
OpMap["OP_QRDMULH_LN"] = OpQRDMulhLane;
|
||||
OpMap["OP_EQ"] = OpEq;
|
||||
OpMap["OP_GE"] = OpGe;
|
||||
OpMap["OP_LE"] = OpLe;
|
||||
OpMap["OP_GT"] = OpGt;
|
||||
OpMap["OP_LT"] = OpLt;
|
||||
OpMap["OP_NEG"] = OpNeg;
|
||||
OpMap["OP_NOT"] = OpNot;
|
||||
OpMap["OP_AND"] = OpAnd;
|
||||
OpMap["OP_OR"] = OpOr;
|
||||
OpMap["OP_XOR"] = OpXor;
|
||||
OpMap["OP_ANDN"] = OpAndNot;
|
||||
OpMap["OP_ORN"] = OpOrNot;
|
||||
OpMap["OP_CAST"] = OpCast;
|
||||
OpMap["OP_CONC"] = OpConcat;
|
||||
OpMap["OP_HI"] = OpHi;
|
||||
OpMap["OP_LO"] = OpLo;
|
||||
OpMap["OP_DUP"] = OpDup;
|
||||
OpMap["OP_DUP_LN"] = OpDupLane;
|
||||
OpMap["OP_SEL"] = OpSelect;
|
||||
OpMap["OP_REV16"] = OpRev16;
|
||||
OpMap["OP_REV32"] = OpRev32;
|
||||
OpMap["OP_REV64"] = OpRev64;
|
||||
OpMap["OP_REINT"] = OpReinterpret;
|
||||
OpMap["OP_ABDL"] = OpAbdl;
|
||||
OpMap["OP_ABA"] = OpAba;
|
||||
OpMap["OP_ABAL"] = OpAbal;
|
||||
|
||||
Record *SI = R.getClass("SInst");
|
||||
Record *II = R.getClass("IInst");
|
||||
Record *WI = R.getClass("WInst");
|
||||
ClassMap[SI] = ClassS;
|
||||
ClassMap[II] = ClassI;
|
||||
ClassMap[WI] = ClassW;
|
||||
}
|
||||
|
||||
// run - Emit arm_neon.h.inc
|
||||
void run(raw_ostream &o);
|
||||
|
||||
// runHeader - Emit all the __builtin prototypes used in arm_neon.h
|
||||
void runHeader(raw_ostream &o);
|
||||
|
||||
// runTests - Emit tests for all the Neon intrinsics.
|
||||
void runTests(raw_ostream &o);
|
||||
|
||||
private:
|
||||
void emitIntrinsic(raw_ostream &OS, Record *R);
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
|
@ -0,0 +1,194 @@
|
|||
//===- OptParserEmitter.cpp - Table Driven Command Line Parsing -----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "OptParserEmitter.h"
|
||||
#include "llvm/TableGen/Record.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
using namespace llvm;
|
||||
|
||||
static int StrCmpOptionName(const char *A, const char *B) {
|
||||
char a = *A, b = *B;
|
||||
while (a == b) {
|
||||
if (a == '\0')
|
||||
return 0;
|
||||
|
||||
a = *++A;
|
||||
b = *++B;
|
||||
}
|
||||
|
||||
if (a == '\0') // A is a prefix of B.
|
||||
return 1;
|
||||
if (b == '\0') // B is a prefix of A.
|
||||
return -1;
|
||||
|
||||
// Otherwise lexicographic.
|
||||
return (a < b) ? -1 : 1;
|
||||
}
|
||||
|
||||
static int CompareOptionRecords(const void *Av, const void *Bv) {
|
||||
const Record *A = *(Record**) Av;
|
||||
const Record *B = *(Record**) Bv;
|
||||
|
||||
// Sentinel options precede all others and are only ordered by precedence.
|
||||
bool ASent = A->getValueAsDef("Kind")->getValueAsBit("Sentinel");
|
||||
bool BSent = B->getValueAsDef("Kind")->getValueAsBit("Sentinel");
|
||||
if (ASent != BSent)
|
||||
return ASent ? -1 : 1;
|
||||
|
||||
// Compare options by name, unless they are sentinels.
|
||||
if (!ASent)
|
||||
if (int Cmp = StrCmpOptionName(A->getValueAsString("Name").c_str(),
|
||||
B->getValueAsString("Name").c_str()))
|
||||
return Cmp;
|
||||
|
||||
// Then by the kind precedence;
|
||||
int APrec = A->getValueAsDef("Kind")->getValueAsInt("Precedence");
|
||||
int BPrec = B->getValueAsDef("Kind")->getValueAsInt("Precedence");
|
||||
assert(APrec != BPrec && "Options are equivalent!");
|
||||
return APrec < BPrec ? -1 : 1;
|
||||
}
|
||||
|
||||
static const std::string getOptionName(const Record &R) {
|
||||
// Use the record name unless EnumName is defined.
|
||||
if (dynamic_cast<UnsetInit*>(R.getValueInit("EnumName")))
|
||||
return R.getName();
|
||||
|
||||
return R.getValueAsString("EnumName");
|
||||
}
|
||||
|
||||
static raw_ostream &write_cstring(raw_ostream &OS, llvm::StringRef Str) {
|
||||
OS << '"';
|
||||
OS.write_escaped(Str);
|
||||
OS << '"';
|
||||
return OS;
|
||||
}
|
||||
|
||||
void OptParserEmitter::run(raw_ostream &OS) {
|
||||
// Get the option groups and options.
|
||||
const std::vector<Record*> &Groups =
|
||||
Records.getAllDerivedDefinitions("OptionGroup");
|
||||
std::vector<Record*> Opts = Records.getAllDerivedDefinitions("Option");
|
||||
|
||||
if (GenDefs)
|
||||
EmitSourceFileHeader("Option Parsing Definitions", OS);
|
||||
else
|
||||
EmitSourceFileHeader("Option Parsing Table", OS);
|
||||
|
||||
array_pod_sort(Opts.begin(), Opts.end(), CompareOptionRecords);
|
||||
if (GenDefs) {
|
||||
OS << "#ifndef OPTION\n";
|
||||
OS << "#error \"Define OPTION prior to including this file!\"\n";
|
||||
OS << "#endif\n\n";
|
||||
|
||||
OS << "/////////\n";
|
||||
OS << "// Groups\n\n";
|
||||
for (unsigned i = 0, e = Groups.size(); i != e; ++i) {
|
||||
const Record &R = *Groups[i];
|
||||
|
||||
// Start a single option entry.
|
||||
OS << "OPTION(";
|
||||
|
||||
// The option string.
|
||||
OS << '"' << R.getValueAsString("Name") << '"';
|
||||
|
||||
// The option identifier name.
|
||||
OS << ", "<< getOptionName(R);
|
||||
|
||||
// The option kind.
|
||||
OS << ", Group";
|
||||
|
||||
// The containing option group (if any).
|
||||
OS << ", ";
|
||||
if (const DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group")))
|
||||
OS << getOptionName(*DI->getDef());
|
||||
else
|
||||
OS << "INVALID";
|
||||
|
||||
// The other option arguments (unused for groups).
|
||||
OS << ", INVALID, 0, 0";
|
||||
|
||||
// The option help text.
|
||||
if (!dynamic_cast<UnsetInit*>(R.getValueInit("HelpText"))) {
|
||||
OS << ",\n";
|
||||
OS << " ";
|
||||
write_cstring(OS, R.getValueAsString("HelpText"));
|
||||
} else
|
||||
OS << ", 0";
|
||||
|
||||
// The option meta-variable name (unused).
|
||||
OS << ", 0)\n";
|
||||
}
|
||||
OS << "\n";
|
||||
|
||||
OS << "//////////\n";
|
||||
OS << "// Options\n\n";
|
||||
for (unsigned i = 0, e = Opts.size(); i != e; ++i) {
|
||||
const Record &R = *Opts[i];
|
||||
|
||||
// Start a single option entry.
|
||||
OS << "OPTION(";
|
||||
|
||||
// The option string.
|
||||
write_cstring(OS, R.getValueAsString("Name"));
|
||||
|
||||
// The option identifier name.
|
||||
OS << ", "<< getOptionName(R);
|
||||
|
||||
// The option kind.
|
||||
OS << ", " << R.getValueAsDef("Kind")->getValueAsString("Name");
|
||||
|
||||
// The containing option group (if any).
|
||||
OS << ", ";
|
||||
if (const DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group")))
|
||||
OS << getOptionName(*DI->getDef());
|
||||
else
|
||||
OS << "INVALID";
|
||||
|
||||
// The option alias (if any).
|
||||
OS << ", ";
|
||||
if (const DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Alias")))
|
||||
OS << getOptionName(*DI->getDef());
|
||||
else
|
||||
OS << "INVALID";
|
||||
|
||||
// The option flags.
|
||||
const ListInit *LI = R.getValueAsListInit("Flags");
|
||||
if (LI->empty()) {
|
||||
OS << ", 0";
|
||||
} else {
|
||||
OS << ", ";
|
||||
for (unsigned i = 0, e = LI->size(); i != e; ++i) {
|
||||
if (i)
|
||||
OS << " | ";
|
||||
OS << dynamic_cast<DefInit*>(LI->getElement(i))->getDef()->getName();
|
||||
}
|
||||
}
|
||||
|
||||
// The option parameter field.
|
||||
OS << ", " << R.getValueAsInt("NumArgs");
|
||||
|
||||
// The option help text.
|
||||
if (!dynamic_cast<UnsetInit*>(R.getValueInit("HelpText"))) {
|
||||
OS << ",\n";
|
||||
OS << " ";
|
||||
write_cstring(OS, R.getValueAsString("HelpText"));
|
||||
} else
|
||||
OS << ", 0";
|
||||
|
||||
// The option meta-variable name.
|
||||
OS << ", ";
|
||||
if (!dynamic_cast<UnsetInit*>(R.getValueInit("MetaVarName")))
|
||||
write_cstring(OS, R.getValueAsString("MetaVarName"));
|
||||
else
|
||||
OS << "0";
|
||||
|
||||
OS << ")\n";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
//===- OptParserEmitter.h - Table Driven Command Line Parsing ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef UTILS_TABLEGEN_OPTPARSEREMITTER_H
|
||||
#define UTILS_TABLEGEN_OPTPARSEREMITTER_H
|
||||
|
||||
#include "llvm/TableGen/TableGenBackend.h"
|
||||
|
||||
namespace llvm {
|
||||
/// OptParserEmitter - This tablegen backend takes an input .td file
|
||||
/// describing a list of options and emits a data structure for parsing and
|
||||
/// working with those options when given an input command line.
|
||||
class OptParserEmitter : public TableGenBackend {
|
||||
RecordKeeper &Records;
|
||||
bool GenDefs;
|
||||
|
||||
public:
|
||||
OptParserEmitter(RecordKeeper &R, bool _GenDefs)
|
||||
: Records(R), GenDefs(_GenDefs) {}
|
||||
|
||||
/// run - Output the option parsing information.
|
||||
///
|
||||
/// \param GenHeader - Generate the header describing the option IDs.x
|
||||
void run(raw_ostream &OS);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,176 @@
|
|||
//===- TableGen.cpp - Top-Level TableGen implementation for Clang ---------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the main function for Clang's TableGen.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ClangASTNodesEmitter.h"
|
||||
#include "ClangAttrEmitter.h"
|
||||
#include "ClangDiagnosticsEmitter.h"
|
||||
#include "ClangSACheckersEmitter.h"
|
||||
#include "NeonEmitter.h"
|
||||
#include "OptParserEmitter.h"
|
||||
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/TableGen/Error.h"
|
||||
#include "llvm/TableGen/Main.h"
|
||||
#include "llvm/TableGen/Record.h"
|
||||
#include "llvm/TableGen/TableGenAction.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
enum ActionType {
|
||||
GenClangAttrClasses,
|
||||
GenClangAttrImpl,
|
||||
GenClangAttrList,
|
||||
GenClangAttrPCHRead,
|
||||
GenClangAttrPCHWrite,
|
||||
GenClangAttrSpellingList,
|
||||
GenClangAttrLateParsedList,
|
||||
GenClangDiagsDefs,
|
||||
GenClangDiagGroups,
|
||||
GenClangDiagsIndexName,
|
||||
GenClangDeclNodes,
|
||||
GenClangStmtNodes,
|
||||
GenClangSACheckers,
|
||||
GenOptParserDefs, GenOptParserImpl,
|
||||
GenArmNeon,
|
||||
GenArmNeonSema,
|
||||
GenArmNeonTest
|
||||
};
|
||||
|
||||
namespace {
|
||||
cl::opt<ActionType>
|
||||
Action(cl::desc("Action to perform:"),
|
||||
cl::values(clEnumValN(GenOptParserDefs, "gen-opt-parser-defs",
|
||||
"Generate option definitions"),
|
||||
clEnumValN(GenOptParserImpl, "gen-opt-parser-impl",
|
||||
"Generate option parser implementation"),
|
||||
clEnumValN(GenClangAttrClasses, "gen-clang-attr-classes",
|
||||
"Generate clang attribute clases"),
|
||||
clEnumValN(GenClangAttrImpl, "gen-clang-attr-impl",
|
||||
"Generate clang attribute implementations"),
|
||||
clEnumValN(GenClangAttrList, "gen-clang-attr-list",
|
||||
"Generate a clang attribute list"),
|
||||
clEnumValN(GenClangAttrPCHRead, "gen-clang-attr-pch-read",
|
||||
"Generate clang PCH attribute reader"),
|
||||
clEnumValN(GenClangAttrPCHWrite, "gen-clang-attr-pch-write",
|
||||
"Generate clang PCH attribute writer"),
|
||||
clEnumValN(GenClangAttrSpellingList,
|
||||
"gen-clang-attr-spelling-list",
|
||||
"Generate a clang attribute spelling list"),
|
||||
clEnumValN(GenClangAttrLateParsedList,
|
||||
"gen-clang-attr-late-parsed-list",
|
||||
"Generate a clang attribute LateParsed list"),
|
||||
clEnumValN(GenClangDiagsDefs, "gen-clang-diags-defs",
|
||||
"Generate Clang diagnostics definitions"),
|
||||
clEnumValN(GenClangDiagGroups, "gen-clang-diag-groups",
|
||||
"Generate Clang diagnostic groups"),
|
||||
clEnumValN(GenClangDiagsIndexName,
|
||||
"gen-clang-diags-index-name",
|
||||
"Generate Clang diagnostic name index"),
|
||||
clEnumValN(GenClangDeclNodes, "gen-clang-decl-nodes",
|
||||
"Generate Clang AST declaration nodes"),
|
||||
clEnumValN(GenClangStmtNodes, "gen-clang-stmt-nodes",
|
||||
"Generate Clang AST statement nodes"),
|
||||
clEnumValN(GenClangSACheckers, "gen-clang-sa-checkers",
|
||||
"Generate Clang Static Analyzer checkers"),
|
||||
clEnumValN(GenArmNeon, "gen-arm-neon",
|
||||
"Generate arm_neon.h for clang"),
|
||||
clEnumValN(GenArmNeonSema, "gen-arm-neon-sema",
|
||||
"Generate ARM NEON sema support for clang"),
|
||||
clEnumValN(GenArmNeonTest, "gen-arm-neon-test",
|
||||
"Generate ARM NEON tests for clang"),
|
||||
clEnumValEnd));
|
||||
|
||||
cl::opt<std::string>
|
||||
ClangComponent("clang-component",
|
||||
cl::desc("Only use warnings from specified component"),
|
||||
cl::value_desc("component"), cl::Hidden);
|
||||
}
|
||||
|
||||
class ClangTableGenAction : public TableGenAction {
|
||||
public:
|
||||
bool operator()(raw_ostream &OS, RecordKeeper &Records) {
|
||||
switch (Action) {
|
||||
case GenClangAttrClasses:
|
||||
ClangAttrClassEmitter(Records).run(OS);
|
||||
break;
|
||||
case GenClangAttrImpl:
|
||||
ClangAttrImplEmitter(Records).run(OS);
|
||||
break;
|
||||
case GenClangAttrList:
|
||||
ClangAttrListEmitter(Records).run(OS);
|
||||
break;
|
||||
case GenClangAttrPCHRead:
|
||||
ClangAttrPCHReadEmitter(Records).run(OS);
|
||||
break;
|
||||
case GenClangAttrPCHWrite:
|
||||
ClangAttrPCHWriteEmitter(Records).run(OS);
|
||||
break;
|
||||
case GenClangAttrSpellingList:
|
||||
ClangAttrSpellingListEmitter(Records).run(OS);
|
||||
break;
|
||||
case GenClangAttrLateParsedList:
|
||||
ClangAttrLateParsedListEmitter(Records).run(OS);
|
||||
break;
|
||||
case GenClangDiagsDefs:
|
||||
ClangDiagsDefsEmitter(Records, ClangComponent).run(OS);
|
||||
break;
|
||||
case GenClangDiagGroups:
|
||||
ClangDiagGroupsEmitter(Records).run(OS);
|
||||
break;
|
||||
case GenClangDiagsIndexName:
|
||||
ClangDiagsIndexNameEmitter(Records).run(OS);
|
||||
break;
|
||||
case GenClangDeclNodes:
|
||||
ClangASTNodesEmitter(Records, "Decl", "Decl").run(OS);
|
||||
ClangDeclContextEmitter(Records).run(OS);
|
||||
break;
|
||||
case GenClangStmtNodes:
|
||||
ClangASTNodesEmitter(Records, "Stmt", "").run(OS);
|
||||
break;
|
||||
case GenClangSACheckers:
|
||||
ClangSACheckersEmitter(Records).run(OS);
|
||||
break;
|
||||
case GenOptParserDefs:
|
||||
OptParserEmitter(Records, true).run(OS);
|
||||
break;
|
||||
case GenOptParserImpl:
|
||||
OptParserEmitter(Records, false).run(OS);
|
||||
break;
|
||||
case GenArmNeon:
|
||||
NeonEmitter(Records).run(OS);
|
||||
break;
|
||||
case GenArmNeonSema:
|
||||
NeonEmitter(Records).runHeader(OS);
|
||||
break;
|
||||
case GenArmNeonTest:
|
||||
NeonEmitter(Records).runTests(OS);
|
||||
break;
|
||||
default:
|
||||
assert(1 && "Invalid Action");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
sys::PrintStackTraceOnErrorSignal();
|
||||
PrettyStackTraceProgram X(argc, argv);
|
||||
cl::ParseCommandLineOptions(argc, argv);
|
||||
|
||||
ClangTableGenAction Action;
|
||||
return TableGenMain(argv[0], Action);
|
||||
}
|
Загрузка…
Ссылка в новой задаче