diff options
Diffstat (limited to 'contrib/llvm/tools/clang/utils')
11 files changed, 5447 insertions, 0 deletions
diff --git a/contrib/llvm/tools/clang/utils/TableGen/ClangASTNodesEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/ClangASTNodesEmitter.cpp new file mode 100644 index 0000000..682f9c7 --- /dev/null +++ b/contrib/llvm/tools/clang/utils/TableGen/ClangASTNodesEmitter.cpp @@ -0,0 +1,229 @@ +//=== 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 "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" +#include <cctype> +#include <map> +#include <set> +#include <string> +using namespace llvm; + +/// ClangASTNodesEmitter - The top-level class emits .inc files containing +/// declarations of Clang statements. +/// +namespace { +class ClangASTNodesEmitter { + // 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); +}; +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// 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) { + emitSourceFileHeader("List of AST nodes of a particular kind", 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"; +} + +namespace clang { +void EmitClangASTNodes(RecordKeeper &RK, raw_ostream &OS, + const std::string &N, const std::string &S) { + ClangASTNodesEmitter(RK, N, S).run(OS); +} + +// Emits and addendum to a .inc file to enumerate the clang declaration +// contexts. +void EmitClangDeclContext(RecordKeeper &Records, raw_ostream &OS) { + // FIXME: Find a .td file format to allow for this to be represented better. + + emitSourceFileHeader("List of AST Decl nodes", OS); + + 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"; +} +} // end namespace clang diff --git a/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp new file mode 100644 index 0000000..7c8603f --- /dev/null +++ b/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -0,0 +1,1495 @@ +//===- 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 "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/StringMatcher.h" +#include "llvm/TableGen/TableGenBackend.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 = dyn_cast<StringInit>(*i)) + Strings.push_back(S->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 *", "ReadExpr(F)") + .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"); +} + +// Normalize attribute name by removing leading and trailing +// underscores. For example, __foo, foo__, __foo__ would +// become foo. +static StringRef NormalizeAttrName(StringRef AttrName) { + if (AttrName.startswith("__")) + AttrName = AttrName.substr(2, AttrName.size()); + + if (AttrName.endswith("__")) + AttrName = AttrName.substr(0, AttrName.size() - 2); + + return AttrName; +} + +// Normalize attribute spelling only if the spelling has both leading +// and trailing underscores. For example, __ms_struct__ will be +// normalized to "ms_struct"; __cdecl will remain intact. +static StringRef NormalizeAttrSpelling(StringRef AttrSpelling) { + if (AttrSpelling.startswith("__") && AttrSpelling.endswith("__")) { + AttrSpelling = AttrSpelling.substr(2, AttrSpelling.size() - 4); + } + + return AttrSpelling; +} + +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 writeTemplateInstantiationArgs(raw_ostream &OS) const = 0; + virtual void writeTemplateInstantiation(raw_ostream &OS) const {} + 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; + virtual void writeValue(raw_ostream &OS) const = 0; + virtual void writeDump(raw_ostream &OS) const = 0; + virtual void writeDumpChildren(raw_ostream &OS) const {} + virtual void writeHasChildren(raw_ostream &OS) const { OS << "false"; } + }; + + class SimpleArgument : public Argument { + std::string type; + + public: + SimpleArgument(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 << " " << type << " get" << getUpperName() << "() const {\n"; + OS << " return " << getLowerName() << ";\n"; + OS << " }"; + } + void writeCloneArgs(raw_ostream &OS) const { + OS << getLowerName(); + } + void writeTemplateInstantiationArgs(raw_ostream &OS) const { + OS << "A->get" << getUpperName() << "()"; + } + 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()) + "()"); + } + void writeValue(raw_ostream &OS) const { + if (type == "FunctionDecl *") { + OS << "\" << get" << getUpperName() << "()->getNameInfo().getAsString() << \""; + } else if (type == "IdentifierInfo *") { + OS << "\" << get" << getUpperName() << "()->getName() << \""; + } else if (type == "QualType") { + OS << "\" << get" << getUpperName() << "().getAsString() << \""; + } else if (type == "SourceLocation") { + OS << "\" << get" << getUpperName() << "().getRawEncoding() << \""; + } else { + OS << "\" << get" << getUpperName() << "() << \""; + } + } + void writeDump(raw_ostream &OS) const { + if (type == "FunctionDecl *") { + OS << " OS << \" \";\n"; + OS << " dumpBareDeclRef(SA->get" << getUpperName() << "());\n"; + } else if (type == "IdentifierInfo *") { + OS << " OS << \" \" << SA->get" << getUpperName() + << "()->getName();\n"; + } else if (type == "QualType") { + OS << " OS << \" \" << SA->get" << getUpperName() + << "().getAsString();\n"; + } else if (type == "SourceLocation") { + OS << " OS << \" \";\n"; + OS << " SA->get" << getUpperName() << "().print(OS, *SM);\n"; + } else if (type == "bool") { + OS << " if (SA->get" << getUpperName() << "()) OS << \" " + << getUpperName() << "\";\n"; + } else if (type == "int" || type == "unsigned") { + OS << " OS << \" \" << SA->get" << getUpperName() << "();\n"; + } else { + llvm_unreachable("Unknown SimpleArgument type!"); + } + } + }; + + 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 writeTemplateInstantiationArgs(raw_ostream &OS) const { + OS << "A->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"; + } + void writeValue(raw_ostream &OS) const { + OS << "\\\"\" << get" << getUpperName() << "() << \"\\\""; + } + void writeDump(raw_ostream &OS) const { + OS << " OS << \" \\\"\" << SA->get" << getUpperName() + << "() << \"\\\"\";\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->EvaluateKnownConstInt(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 writeTemplateInstantiationArgs(raw_ostream &OS) const { + // FIXME: move the definition in Sema::InstantiateAttrs to here. + // In the meantime, aligned attributes are cloned. + } + 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"; + } + void writeValue(raw_ostream &OS) const { + OS << "\";\n" + << " " << getLowerName() << "Expr->printPretty(OS, 0, Policy);\n" + << " OS << \""; + } + void writeDump(raw_ostream &OS) const { + } + void writeDumpChildren(raw_ostream &OS) const { + OS << " if (SA->is" << getUpperName() << "Expr()) {\n"; + OS << " lastChild();\n"; + OS << " dumpStmt(SA->get" << getUpperName() << "Expr());\n"; + OS << " } else\n"; + OS << " dumpType(SA->get" << getUpperName() + << "Type()->getType());\n"; + } + void writeHasChildren(raw_ostream &OS) const { + OS << "SA->is" << getUpperName() << "Expr()"; + } + }; + + 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 writeTemplateInstantiationArgs(raw_ostream &OS) const { + // This isn't elegant, but we have to go through public methods... + OS << "A->" << getLowerName() << "_begin(), " + << "A->" << 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 << " 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)"); + } + void writeValue(raw_ostream &OS) const { + OS << "\";\n"; + OS << " bool isFirst = true;\n" + << " for (" << getAttrName() << "Attr::" << getLowerName() + << "_iterator i = " << getLowerName() << "_begin(), e = " + << getLowerName() << "_end(); i != e; ++i) {\n" + << " if (isFirst) isFirst = false;\n" + << " else OS << \", \";\n" + << " OS << *i;\n" + << " }\n"; + OS << " OS << \""; + } + void writeDump(raw_ostream &OS) const { + OS << " for (" << getAttrName() << "Attr::" << getLowerName() + << "_iterator I = SA->" << getLowerName() << "_begin(), E = SA->" + << getLowerName() << "_end(); I != E; ++I)\n"; + OS << " OS << \" \" << *I;\n"; + } + }; + + class EnumArgument : public Argument { + std::string type; + std::vector<StringRef> values, enums, uniques; + public: + EnumArgument(Record &Arg, StringRef Attr) + : Argument(Arg, Attr), type(Arg.getValueAsString("Type")), + values(getValueAsListOfStrings(Arg, "Values")), + enums(getValueAsListOfStrings(Arg, "Enums")), + uniques(enums) + { + // Calculate the various enum values + std::sort(uniques.begin(), uniques.end()); + uniques.erase(std::unique(uniques.begin(), uniques.end()), uniques.end()); + // FIXME: Emit a proper error + assert(!uniques.empty()); + } + + 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 writeTemplateInstantiationArgs(raw_ostream &OS) const { + OS << "A->get" << getUpperName() << "()"; + } + void writeCtorInitializers(raw_ostream &OS) const { + OS << getLowerName() << "(" << getUpperName() << ")"; + } + void writeCtorParameters(raw_ostream &OS) const { + OS << type << " " << getUpperName(); + } + void writeDeclarations(raw_ostream &OS) const { + std::vector<StringRef>::const_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"; + } + void writeValue(raw_ostream &OS) const { + OS << "\" << get" << getUpperName() << "() << \""; + } + void writeDump(raw_ostream &OS) const { + OS << " switch(SA->get" << getUpperName() << "()) {\n"; + for (std::vector<StringRef>::const_iterator I = uniques.begin(), + E = uniques.end(); I != E; ++I) { + OS << " case " << getAttrName() << "Attr::" << *I << ":\n"; + OS << " OS << \" " << *I << "\";\n"; + OS << " break;\n"; + } + OS << " }\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 writeTemplateInstantiationArgs(raw_ostream &OS) const { + OS << "A->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"; + } + void writeValue(raw_ostream &OS) const { + OS << getLowerName() << "=\" << get" << getUpperName() << "() << \""; + } + void writeDump(raw_ostream &OS) const { + OS << " OS << \" \" << SA->get" << getUpperName() << "();\n"; + } + }; + + class ExprArgument : public SimpleArgument { + public: + ExprArgument(Record &Arg, StringRef Attr) + : SimpleArgument(Arg, Attr, "Expr *") + {} + + void writeTemplateInstantiationArgs(raw_ostream &OS) const { + OS << "tempInst" << getUpperName(); + } + + void writeTemplateInstantiation(raw_ostream &OS) const { + OS << " " << getType() << " tempInst" << getUpperName() << ";\n"; + OS << " {\n"; + OS << " EnterExpressionEvaluationContext " + << "Unevaluated(S, Sema::Unevaluated);\n"; + OS << " ExprResult " << "Result = S.SubstExpr(" + << "A->get" << getUpperName() << "(), TemplateArgs);\n"; + OS << " tempInst" << getUpperName() << " = " + << "Result.takeAs<Expr>();\n"; + OS << " }\n"; + } + + void writeDump(raw_ostream &OS) const { + } + + void writeDumpChildren(raw_ostream &OS) const { + OS << " lastChild();\n"; + OS << " dumpStmt(SA->get" << getUpperName() << "());\n"; + } + void writeHasChildren(raw_ostream &OS) const { OS << "true"; } + }; + + class VariadicExprArgument : public VariadicArgument { + public: + VariadicExprArgument(Record &Arg, StringRef Attr) + : VariadicArgument(Arg, Attr, "Expr *") + {} + + void writeTemplateInstantiationArgs(raw_ostream &OS) const { + OS << "tempInst" << getUpperName() << ", " + << "A->" << getLowerName() << "_size()"; + } + + void writeTemplateInstantiation(raw_ostream &OS) const { + OS << " " << getType() << " *tempInst" << getUpperName() + << " = new (C, 16) " << getType() + << "[A->" << getLowerName() << "_size()];\n"; + OS << " {\n"; + OS << " EnterExpressionEvaluationContext " + << "Unevaluated(S, Sema::Unevaluated);\n"; + OS << " " << getType() << " *TI = tempInst" << getUpperName() + << ";\n"; + OS << " " << getType() << " *I = A->" << getLowerName() + << "_begin();\n"; + OS << " " << getType() << " *E = A->" << getLowerName() + << "_end();\n"; + OS << " for (; I != E; ++I, ++TI) {\n"; + OS << " ExprResult Result = S.SubstExpr(*I, TemplateArgs);\n"; + OS << " *TI = Result.takeAs<Expr>();\n"; + OS << " }\n"; + OS << " }\n"; + } + + void writeDump(raw_ostream &OS) const { + } + + void writeDumpChildren(raw_ostream &OS) const { + OS << " for (" << getAttrName() << "Attr::" << getLowerName() + << "_iterator I = SA->" << getLowerName() << "_begin(), E = SA->" + << getLowerName() << "_end(); I != E; ++I) {\n"; + OS << " if (I + 1 == E)\n"; + OS << " lastChild();\n"; + OS << " dumpStmt(*I);\n"; + OS << " }\n"; + } + + void writeHasChildren(raw_ostream &OS) const { + OS << "SA->" << getLowerName() << "_begin() != " + << "SA->" << getLowerName() << "_end()"; + } + }; +} + +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 ExprArgument(Arg, Attr); + 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 VariadicExprArgument(Arg, Attr); + 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; +} + +static void writeAvailabilityValue(raw_ostream &OS) { + OS << "\" << getPlatform()->getName();\n" + << " if (!getIntroduced().empty()) OS << \", introduced=\" << getIntroduced();\n" + << " if (!getDeprecated().empty()) OS << \", deprecated=\" << getDeprecated();\n" + << " if (!getObsoleted().empty()) OS << \", obsoleted=\" << getObsoleted();\n" + << " if (getUnavailable()) OS << \", unavailable\";\n" + << " OS << \""; +} + +static void writePrettyPrintFunction(Record &R, std::vector<Argument*> &Args, + raw_ostream &OS) { + std::vector<Record*> Spellings = R.getValueAsListOfDefs("Spellings"); + + OS << "void " << R.getName() << "Attr::printPretty(" + << "raw_ostream &OS, const PrintingPolicy &Policy) const {\n"; + + if (Spellings.size() == 0) { + OS << "}\n\n"; + return; + } + + OS << + " switch (SpellingListIndex) {\n" + " default:\n" + " llvm_unreachable(\"Unknown attribute spelling!\");\n" + " break;\n"; + + for (unsigned I = 0; I < Spellings.size(); ++ I) { + llvm::SmallString<16> Prefix; + llvm::SmallString<8> Suffix; + // The actual spelling of the name and namespace (if applicable) + // of an attribute without considering prefix and suffix. + llvm::SmallString<64> Spelling; + std::string Name = Spellings[I]->getValueAsString("Name"); + std::string Variety = Spellings[I]->getValueAsString("Variety"); + + if (Variety == "GNU") { + Prefix = " __attribute__(("; + Suffix = "))"; + } else if (Variety == "CXX11") { + Prefix = " [["; + Suffix = "]]"; + std::string Namespace = Spellings[I]->getValueAsString("Namespace"); + if (Namespace != "") { + Spelling += Namespace; + Spelling += "::"; + } + } else if (Variety == "Declspec") { + Prefix = " __declspec("; + Suffix = ")"; + } else if (Variety == "Keyword") { + Prefix = " "; + Suffix = ""; + } else { + llvm_unreachable("Unknown attribute syntax variety!"); + } + + Spelling += Name; + + OS << + " case " << I << " : {\n" + " OS << \"" + Prefix.str() + Spelling.str(); + + if (Args.size()) OS << "("; + if (Spelling == "availability") { + writeAvailabilityValue(OS); + } else { + for (std::vector<Argument*>::const_iterator I = Args.begin(), + E = Args.end(); I != E; ++ I) { + if (I != Args.begin()) OS << ", "; + (*I)->writeValue(OS); + } + } + + if (Args.size()) OS << ")"; + OS << Suffix.str() + "\";\n"; + + OS << + " break;\n" + " }\n"; + } + + // End of the switch statement. + OS << "}\n"; + // End of the print function. + OS << "}\n\n"; +} + +/// \brief Return the index of a spelling in a spelling list. +static unsigned getSpellingListIndex(const std::vector<Record*> &SpellingList, + const Record &Spelling) { + assert(SpellingList.size() && "Spelling list is empty!"); + + for (unsigned Index = 0; Index < SpellingList.size(); ++Index) { + Record *S = SpellingList[Index]; + if (S->getValueAsString("Variety") != Spelling.getValueAsString("Variety")) + continue; + if (S->getValueAsString("Variety") == "CXX11" && + S->getValueAsString("Namespace") != + Spelling.getValueAsString("Namespace")) + continue; + if (S->getValueAsString("Name") != Spelling.getValueAsString("Name")) + continue; + + return Index; + } + + llvm_unreachable("Unknown spelling!"); +} + +static void writeAttrAccessorDefinition(Record &R, raw_ostream &OS) { + std::vector<Record*> Accessors = R.getValueAsListOfDefs("Accessors"); + for (std::vector<Record*>::const_iterator I = Accessors.begin(), + E = Accessors.end(); I != E; ++I) { + Record *Accessor = *I; + std::string Name = Accessor->getValueAsString("Name"); + std::vector<Record*> Spellings = Accessor->getValueAsListOfDefs( + "Spellings"); + std::vector<Record*> SpellingList = R.getValueAsListOfDefs("Spellings"); + assert(SpellingList.size() && + "Attribute with empty spelling list can't have accessors!"); + + OS << " bool " << Name << "() const { return SpellingListIndex == "; + for (unsigned Index = 0; Index < Spellings.size(); ++Index) { + OS << getSpellingListIndex(SpellingList, *Spellings[Index]); + if (Index != Spellings.size() -1) + OS << " ||\n SpellingListIndex == "; + else + OS << "; }\n"; + } + } +} + +namespace clang { + +// Emits the class definitions for attributes. +void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader("Attribute classes' definitions", OS); + + 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; + + if (!R.getValueAsBit("ASTNode")) + continue; + + 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 << " , "; + OS << "unsigned SI = 0\n"; + + OS << " )\n"; + OS << " : " << SuperName << "(attr::" << R.getName() << ", R, SI)\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"; + OS << " virtual void printPretty(raw_ostream &OS,\n" + << " const PrintingPolicy &Policy) const;\n"; + + writeAttrAccessorDefinition(R, OS); + + for (ai = Args.begin(); ai != ae; ++ai) { + (*ai)->writeAccessors(OS); + OS << "\n\n"; + } + + OS << R.getValueAsString("AdditionalMembers"); + OS << "\n\n"; + + OS << " static bool classof(const Attr *A) { return A->getKind() == " + << "attr::" << R.getName() << "; }\n"; + + bool LateParsed = R.getValueAsBit("LateParsed"); + OS << " virtual bool isLateParsed() const { return " + << LateParsed << "; }\n"; + + OS << "};\n\n"; + } + + OS << "#endif\n"; +} + +// Emits the class method definitions for attributes. +void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader("Attribute classes' member function definitions", OS); + + 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; + + if (!R.getValueAsBit("ASTNode")) + continue; + + 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 << ", getSpellingListIndex());\n}\n\n"; + + writePrettyPrintFunction(R, Args, OS); + } +} + +} // end namespace clang + +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) { + if (!(*i)->getValueAsBit("ASTNode")) + continue; + + OS << Class << "(" << (*i)->getName() << ")\n"; + } + + OS << "LAST_" << Class << "(" << (*i)->getName() << ")\n\n"; + } +} + +namespace clang { + +// Emits the enumeration list for attributes. +void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader("List of all attributes that Clang recognizes", OS); + + 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"; + + OS << "#ifndef MS_INHERITABLE_ATTR\n"; + OS << "#define MS_INHERITABLE_ATTR(NAME) INHERITABLE_ATTR(NAME)\n"; + OS << "#endif\n\n"; + + OS << "#ifndef LAST_MS_INHERITABLE_ATTR\n"; + OS << "#define LAST_MS_INHERITABLE_ATTR(NAME)" + " MS_INHERITABLE_ATTR(NAME)\n"; + OS << "#endif\n\n"; + + Record *InhClass = Records.getClass("InheritableAttr"); + Record *InhParamClass = Records.getClass("InheritableParamAttr"); + Record *MSInheritanceClass = Records.getClass("MSInheritanceAttr"); + std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), + NonInhAttrs, InhAttrs, InhParamAttrs, MSInhAttrs; + for (std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(); + i != e; ++i) { + if (!(*i)->getValueAsBit("ASTNode")) + continue; + + if ((*i)->isSubClassOf(InhParamClass)) + InhParamAttrs.push_back(*i); + else if ((*i)->isSubClassOf(MSInheritanceClass)) + MSInhAttrs.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, "MS_INHERITABLE_ATTR", MSInhAttrs); + EmitAttrList(OS, "INHERITABLE_ATTR", InhAttrs); + EmitAttrList(OS, "ATTR", NonInhAttrs); + + OS << "#undef LAST_ATTR\n"; + OS << "#undef INHERITABLE_ATTR\n"; + OS << "#undef MS_INHERITABLE_ATTR\n"; + OS << "#undef LAST_INHERITABLE_ATTR\n"; + OS << "#undef LAST_INHERITABLE_PARAM_ATTR\n"; + OS << "#undef LAST_MS_INHERITABLE_ATTR\n"; + OS << "#undef ATTR\n"; +} + +// Emits the code to read an attribute from a precompiled header. +void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader("Attribute deserialization code", OS); + + 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; + if (!R.getValueAsBit("ASTNode")) + continue; + + 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"; +} + +// Emits the code to write an attribute to a precompiled header. +void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader("Attribute serialization code", 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; + if (!R.getValueAsBit("ASTNode")) + continue; + 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"; +} + +// Emits the list of spellings for attributes. +void EmitClangAttrSpellingList(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader("llvm::StringSwitch code to match all known attributes", + OS); + + 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<Record*> Spellings = Attr.getValueAsListOfDefs("Spellings"); + + for (std::vector<Record*>::const_iterator I = Spellings.begin(), E = Spellings.end(); I != E; ++I) { + OS << ".Case(\"" << (*I)->getValueAsString("Name") << "\", true)\n"; + } + } + +} + +void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader("Code to translate different attribute spellings " + "into internal identifiers", OS); + + OS << + " unsigned Index = 0;\n" + " switch (AttrKind) {\n" + " default:\n" + " llvm_unreachable(\"Unknown attribute kind!\");\n" + " break;\n"; + + std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); + for (std::vector<Record*>::const_iterator I = Attrs.begin(), E = Attrs.end(); + I != E; ++I) { + Record &R = **I; + // We only care about attributes that participate in Sema checking, so + // skip those attributes that are not able to make their way to Sema. + if (!R.getValueAsBit("SemaHandler")) + continue; + + std::vector<Record*> Spellings = R.getValueAsListOfDefs("Spellings"); + // Each distinct spelling yields an attribute kind. + if (R.getValueAsBit("DistinctSpellings")) { + for (unsigned I = 0; I < Spellings.size(); ++ I) { + OS << + " case AT_" << Spellings[I]->getValueAsString("Name") << ": \n" + " Index = " << I << ";\n" + " break;\n"; + } + } else { + OS << " case AT_" << R.getName() << " : {\n"; + for (unsigned I = 0; I < Spellings.size(); ++ I) { + SmallString<16> Namespace; + if (Spellings[I]->getValueAsString("Variety") == "CXX11") + Namespace = Spellings[I]->getValueAsString("Namespace"); + else + Namespace = ""; + + OS << " if (Name == \"" + << Spellings[I]->getValueAsString("Name") << "\" && " + << "SyntaxUsed == " + << StringSwitch<unsigned>(Spellings[I]->getValueAsString("Variety")) + .Case("GNU", 0) + .Case("CXX11", 1) + .Case("Declspec", 2) + .Case("Keyword", 3) + .Default(0) + << " && Scope == \"" << Namespace << "\")\n" + << " return " << I << ";\n"; + } + + OS << " break;\n"; + OS << " }\n"; + } + } + + OS << " }\n"; + OS << " return Index;\n"; +} + +// Emits the LateParsed property for attributes. +void EmitClangAttrLateParsedList(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader("llvm::StringSwitch code to match late parsed " + "attributes", OS); + + 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<Record*> Spellings = + Attr.getValueAsListOfDefs("Spellings"); + + // FIXME: Handle non-GNU attributes + for (std::vector<Record*>::const_iterator I = Spellings.begin(), + E = Spellings.end(); I != E; ++I) { + if ((*I)->getValueAsString("Variety") != "GNU") + continue; + OS << ".Case(\"" << (*I)->getValueAsString("Name") << "\", " + << LateParsed << ")\n"; + } + } + } +} + +// Emits code to instantiate dependent attributes on templates. +void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader("Template instantiation code for attributes", OS); + + std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); + + OS << "namespace clang {\n" + << "namespace sema {\n\n" + << "Attr *instantiateTemplateAttribute(const Attr *At, ASTContext &C, " + << "Sema &S,\n" + << " const MultiLevelTemplateArgumentList &TemplateArgs) {\n" + << " switch (At->getKind()) {\n" + << " default:\n" + << " break;\n"; + + for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end(); + I != E; ++I) { + Record &R = **I; + if (!R.getValueAsBit("ASTNode")) + continue; + + OS << " case attr::" << R.getName() << ": {\n"; + bool ShouldClone = R.getValueAsBit("Clone"); + + if (!ShouldClone) { + OS << " return NULL;\n"; + OS << " }\n"; + continue; + } + + OS << " const " << R.getName() << "Attr *A = cast<" + << R.getName() << "Attr>(At);\n"; + bool TDependent = R.getValueAsBit("TemplateDependent"); + + if (!TDependent) { + OS << " return A->clone(C);\n"; + OS << " }\n"; + continue; + } + + 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); + } + ae = Args.end(); + + for (ai = Args.begin(); ai != ae; ++ai) { + (*ai)->writeTemplateInstantiation(OS); + } + OS << " return new (C) " << R.getName() << "Attr(A->getLocation(), C"; + for (ai = Args.begin(); ai != ae; ++ai) { + OS << ", "; + (*ai)->writeTemplateInstantiationArgs(OS); + } + OS << ");\n }\n"; + } + OS << " } // end switch\n" + << " llvm_unreachable(\"Unknown attribute!\");\n" + << " return 0;\n" + << "}\n\n" + << "} // end namespace sema\n" + << "} // end namespace clang\n"; +} + +// Emits the list of parsed attributes. +void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader("List of all attributes that Clang recognizes", OS); + + OS << "#ifndef PARSED_ATTR\n"; + OS << "#define PARSED_ATTR(NAME) NAME\n"; + OS << "#endif\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 SemaHandler = Attr.getValueAsBit("SemaHandler"); + bool DistinctSpellings = Attr.getValueAsBit("DistinctSpellings"); + + if (SemaHandler) { + if (DistinctSpellings) { + std::vector<Record*> Spellings = Attr.getValueAsListOfDefs("Spellings"); + + for (std::vector<Record*>::const_iterator I = Spellings.begin(), + E = Spellings.end(); I != E; ++I) { + std::string AttrName = (*I)->getValueAsString("Name"); + + StringRef Spelling = NormalizeAttrName(AttrName); + + OS << "PARSED_ATTR(" << Spelling << ")\n"; + } + } else { + StringRef AttrName = Attr.getName(); + AttrName = NormalizeAttrName(AttrName); + OS << "PARSED_ATTR(" << AttrName << ")\n"; + } + } + } +} + +// Emits the kind list of parsed attributes +void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader("Attribute name matcher", OS); + + std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); + + std::vector<StringMatcher::StringPair> Matches; + for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end(); + I != E; ++I) { + Record &Attr = **I; + + bool SemaHandler = Attr.getValueAsBit("SemaHandler"); + bool Ignored = Attr.getValueAsBit("Ignored"); + bool DistinctSpellings = Attr.getValueAsBit("DistinctSpellings"); + if (SemaHandler || Ignored) { + std::vector<Record*> Spellings = Attr.getValueAsListOfDefs("Spellings"); + + for (std::vector<Record*>::const_iterator I = Spellings.begin(), + E = Spellings.end(); I != E; ++I) { + std::string RawSpelling = (*I)->getValueAsString("Name"); + StringRef AttrName = NormalizeAttrName(DistinctSpellings + ? StringRef(RawSpelling) + : StringRef(Attr.getName())); + + SmallString<64> Spelling; + if ((*I)->getValueAsString("Variety") == "CXX11") { + Spelling += (*I)->getValueAsString("Namespace"); + Spelling += "::"; + } + Spelling += NormalizeAttrSpelling(RawSpelling); + + if (SemaHandler) + Matches.push_back( + StringMatcher::StringPair( + StringRef(Spelling), + "return AttributeList::AT_" + AttrName.str() + ";")); + else + Matches.push_back( + StringMatcher::StringPair( + StringRef(Spelling), + "return AttributeList::IgnoredAttribute;")); + } + } + } + + OS << "static AttributeList::Kind getAttrKind(StringRef Name) {\n"; + StringMatcher("Name", Matches, OS).Emit(); + OS << "return AttributeList::UnknownAttribute;\n" + << "}\n"; +} + +// Emits the code to dump an attribute. +void EmitClangAttrDump(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader("Attribute dumper", OS); + + OS << + " switch (A->getKind()) {\n" + " default:\n" + " llvm_unreachable(\"Unknown attribute kind!\");\n" + " break;\n"; + std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), Args; + for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end(); + I != E; ++I) { + Record &R = **I; + if (!R.getValueAsBit("ASTNode")) + continue; + OS << " case attr::" << R.getName() << ": {\n"; + Args = R.getValueAsListOfDefs("Args"); + if (!Args.empty()) { + OS << " const " << R.getName() << "Attr *SA = cast<" << R.getName() + << "Attr>(A);\n"; + for (std::vector<Record*>::iterator I = Args.begin(), E = Args.end(); + I != E; ++I) + createArgument(**I, R.getName())->writeDump(OS); + + // Code for detecting the last child. + OS << " bool OldMoreChildren = hasMoreChildren();\n"; + OS << " bool MoreChildren = OldMoreChildren;\n"; + + for (std::vector<Record*>::iterator I = Args.begin(), E = Args.end(); + I != E; ++I) { + // More code for detecting the last child. + OS << " MoreChildren = OldMoreChildren"; + for (std::vector<Record*>::iterator Next = I + 1; Next != E; ++Next) { + OS << " || "; + createArgument(**Next, R.getName())->writeHasChildren(OS); + } + OS << ";\n"; + OS << " setMoreChildren(MoreChildren);\n"; + + createArgument(**I, R.getName())->writeDumpChildren(OS); + } + + // Reset the last child. + OS << " setMoreChildren(OldMoreChildren);\n"; + } + OS << + " break;\n" + " }\n"; + } + OS << " }\n"; +} + +} // end namespace clang diff --git a/contrib/llvm/tools/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp new file mode 100644 index 0000000..ebb0427 --- /dev/null +++ b/contrib/llvm/tools/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp @@ -0,0 +1,122 @@ +//===--- ClangCommentCommandInfoEmitter.cpp - Generate command lists -----====// +// +// 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 command lists and efficient matchers for command +// names that are used in documentation comments. +// +//===----------------------------------------------------------------------===// + +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/StringMatcher.h" +#include "llvm/TableGen/TableGenBackend.h" +#include <vector> + +using namespace llvm; + +namespace clang { +void EmitClangCommentCommandInfo(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader("A list of commands useable in documentation " + "comments", OS); + + OS << "namespace {\n" + "const CommandInfo Commands[] = {\n"; + std::vector<Record *> Tags = Records.getAllDerivedDefinitions("Command"); + for (size_t i = 0, e = Tags.size(); i != e; ++i) { + Record &Tag = *Tags[i]; + OS << " { " + << "\"" << Tag.getValueAsString("Name") << "\", " + << "\"" << Tag.getValueAsString("EndCommandName") << "\", " + << i << ", " + << Tag.getValueAsInt("NumArgs") << ", " + << Tag.getValueAsBit("IsInlineCommand") << ", " + << Tag.getValueAsBit("IsBlockCommand") << ", " + << Tag.getValueAsBit("IsBriefCommand") << ", " + << Tag.getValueAsBit("IsReturnsCommand") << ", " + << Tag.getValueAsBit("IsParamCommand") << ", " + << Tag.getValueAsBit("IsTParamCommand") << ", " + << Tag.getValueAsBit("IsDeprecatedCommand") << ", " + << Tag.getValueAsBit("IsHeaderfileCommand") << ", " + << Tag.getValueAsBit("IsEmptyParagraphAllowed") << ", " + << Tag.getValueAsBit("IsVerbatimBlockCommand") << ", " + << Tag.getValueAsBit("IsVerbatimBlockEndCommand") << ", " + << Tag.getValueAsBit("IsVerbatimLineCommand") << ", " + << Tag.getValueAsBit("IsDeclarationCommand") << ", " + << Tag.getValueAsBit("IsFunctionDeclarationCommand") << ", " + << Tag.getValueAsBit("IsRecordLikeDetailCommand") << ", " + << Tag.getValueAsBit("IsRecordLikeDeclarationCommand") << ", " + << /* IsUnknownCommand = */ "0" + << " }"; + if (i + 1 != e) + OS << ","; + OS << "\n"; + } + OS << "};\n" + "} // unnamed namespace\n\n"; + + std::vector<StringMatcher::StringPair> Matches; + for (size_t i = 0, e = Tags.size(); i != e; ++i) { + Record &Tag = *Tags[i]; + std::string Name = Tag.getValueAsString("Name"); + std::string Return; + raw_string_ostream(Return) << "return &Commands[" << i << "];"; + Matches.push_back(StringMatcher::StringPair(Name, Return)); + } + + OS << "const CommandInfo *CommandTraits::getBuiltinCommandInfo(\n" + << " StringRef Name) {\n"; + StringMatcher("Name", Matches, OS).Emit(); + OS << " return NULL;\n" + << "}\n\n"; +} + +static std::string MangleName(StringRef Str) { + std::string Mangled; + for (unsigned i = 0, e = Str.size(); i != e; ++i) { + switch (Str[i]) { + default: + Mangled += Str[i]; + break; + case '[': + Mangled += "lsquare"; + break; + case ']': + Mangled += "rsquare"; + break; + case '{': + Mangled += "lbrace"; + break; + case '}': + Mangled += "rbrace"; + break; + case '$': + Mangled += "dollar"; + break; + } + } + return Mangled; +} + +void EmitClangCommentCommandList(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader("A list of commands useable in documentation " + "comments", OS); + + OS << "#ifndef COMMENT_COMMAND\n" + << "# define COMMENT_COMMAND(NAME)\n" + << "#endif\n"; + + std::vector<Record *> Tags = Records.getAllDerivedDefinitions("Command"); + for (size_t i = 0, e = Tags.size(); i != e; ++i) { + Record &Tag = *Tags[i]; + std::string MangledName = MangleName(Tag.getValueAsString("Name")); + + OS << "COMMENT_COMMAND(" << MangledName << ")\n"; + } +} +} // end namespace clang + diff --git a/contrib/llvm/tools/clang/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp new file mode 100644 index 0000000..bfdb268 --- /dev/null +++ b/contrib/llvm/tools/clang/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp @@ -0,0 +1,85 @@ +//===--- ClangCommentHTMLNamedCharacterReferenceEmitter.cpp -----------------=// +// +// 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 an fficient function to translate HTML named +// character references to UTF-8 sequences. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/StringMatcher.h" +#include "llvm/TableGen/TableGenBackend.h" +#include <vector> + +using namespace llvm; + +/// \brief Convert a code point to the corresponding UTF-8 sequence represented +/// as a C string literal. +/// +/// \returns true on success. +static bool translateCodePointToUTF8(unsigned CodePoint, + SmallVectorImpl<char> &CLiteral) { + char Translated[UNI_MAX_UTF8_BYTES_PER_CODE_POINT]; + char *TranslatedPtr = Translated; + if (!ConvertCodePointToUTF8(CodePoint, TranslatedPtr)) + return false; + + StringRef UTF8(Translated, TranslatedPtr - Translated); + + raw_svector_ostream OS(CLiteral); + OS << "\""; + for (size_t i = 0, e = UTF8.size(); i != e; ++i) { + OS << "\\x"; + OS.write_hex(static_cast<unsigned char>(UTF8[i])); + } + OS << "\""; + + return true; +} + +namespace clang { +void EmitClangCommentHTMLNamedCharacterReferences(RecordKeeper &Records, + raw_ostream &OS) { + std::vector<Record *> Tags = Records.getAllDerivedDefinitions("NCR"); + std::vector<StringMatcher::StringPair> NameToUTF8; + SmallString<32> CLiteral; + for (std::vector<Record *>::iterator I = Tags.begin(), E = Tags.end(); + I != E; ++I) { + Record &Tag = **I; + std::string Spelling = Tag.getValueAsString("Spelling"); + uint64_t CodePoint = Tag.getValueAsInt("CodePoint"); + CLiteral.clear(); + CLiteral.append("return "); + if (!translateCodePointToUTF8(CodePoint, CLiteral)) { + SrcMgr.PrintMessage(Tag.getLoc().front(), + SourceMgr::DK_Error, + Twine("invalid code point")); + continue; + } + CLiteral.append(";"); + + StringMatcher::StringPair Match(Spelling, CLiteral.str()); + NameToUTF8.push_back(Match); + } + + emitSourceFileHeader("HTML named character reference to UTF-8 " + "translation", OS); + + OS << "StringRef translateHTMLNamedCharacterReferenceToUTF8(\n" + " StringRef Name) {\n"; + StringMatcher("Name", NameToUTF8, OS).Emit(); + OS << " return StringRef();\n" + << "}\n\n"; +} + +} // end namespace clang + diff --git a/contrib/llvm/tools/clang/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp new file mode 100644 index 0000000..bfcd2cf --- /dev/null +++ b/contrib/llvm/tools/clang/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp @@ -0,0 +1,70 @@ +//===--- ClangCommentHTMLTagsEmitter.cpp - Generate HTML tag list for Clang -=// +// +// 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 efficient matchers for HTML tags that are used +// in documentation comments. +// +//===----------------------------------------------------------------------===// + +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/StringMatcher.h" +#include "llvm/TableGen/TableGenBackend.h" +#include <vector> + +using namespace llvm; + +namespace clang { +void EmitClangCommentHTMLTags(RecordKeeper &Records, raw_ostream &OS) { + std::vector<Record *> Tags = Records.getAllDerivedDefinitions("Tag"); + std::vector<StringMatcher::StringPair> Matches; + for (std::vector<Record *>::iterator I = Tags.begin(), E = Tags.end(); + I != E; ++I) { + Record &Tag = **I; + std::string Spelling = Tag.getValueAsString("Spelling"); + Matches.push_back(StringMatcher::StringPair(Spelling, "return true;")); + } + + emitSourceFileHeader("HTML tag name matcher", OS); + + OS << "bool isHTMLTagName(StringRef Name) {\n"; + StringMatcher("Name", Matches, OS).Emit(); + OS << " return false;\n" + << "}\n\n"; +} + +void EmitClangCommentHTMLTagsProperties(RecordKeeper &Records, + raw_ostream &OS) { + std::vector<Record *> Tags = Records.getAllDerivedDefinitions("Tag"); + std::vector<StringMatcher::StringPair> MatchesEndTagOptional; + std::vector<StringMatcher::StringPair> MatchesEndTagForbidden; + for (std::vector<Record *>::iterator I = Tags.begin(), E = Tags.end(); + I != E; ++I) { + Record &Tag = **I; + std::string Spelling = Tag.getValueAsString("Spelling"); + StringMatcher::StringPair Match(Spelling, "return true;"); + if (Tag.getValueAsBit("EndTagOptional")) + MatchesEndTagOptional.push_back(Match); + if (Tag.getValueAsBit("EndTagForbidden")) + MatchesEndTagForbidden.push_back(Match); + } + + emitSourceFileHeader("HTML tag properties", OS); + + OS << "bool isHTMLEndTagOptional(StringRef Name) {\n"; + StringMatcher("Name", MatchesEndTagOptional, OS).Emit(); + OS << " return false;\n" + << "}\n\n"; + + OS << "bool isHTMLEndTagForbidden(StringRef Name) {\n"; + StringMatcher("Name", MatchesEndTagForbidden, OS).Emit(); + OS << " return false;\n" + << "}\n\n"; +} +} // end namespace clang + diff --git a/contrib/llvm/tools/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp new file mode 100644 index 0000000..291eb75 --- /dev/null +++ b/contrib/llvm/tools/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp @@ -0,0 +1,760 @@ +//=- 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 "llvm/ADT/DenseSet.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" +#include <algorithm> +#include <cctype> +#include <functional> +#include <map> +#include <set> +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 = dyn_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(); } + }; + + struct GroupInfo { + std::vector<const Record*> DiagsInGroup; + std::vector<std::string> SubGroups; + unsigned IDNo; + + const Record *ExplicitDef; + + GroupInfo() : ExplicitDef(0) {} + }; +} // end anonymous namespace. + +static bool beforeThanCompare(const Record *LHS, const Record *RHS) { + assert(!LHS->getLoc().empty() && !RHS->getLoc().empty()); + return + LHS->getLoc().front().getPointer() < RHS->getLoc().front().getPointer(); +} + +static bool beforeThanCompareGroups(const GroupInfo *LHS, const GroupInfo *RHS){ + assert(!LHS->DiagsInGroup.empty() && !RHS->DiagsInGroup.empty()); + return beforeThanCompare(LHS->DiagsInGroup.front(), + RHS->DiagsInGroup.front()); +} + +static SMRange findSuperClassRange(const Record *R, StringRef SuperName) { + ArrayRef<Record *> Supers = R->getSuperClasses(); + + for (size_t i = 0, e = Supers.size(); i < e; ++i) + if (Supers[i]->getName() == SuperName) + return R->getSuperClassRanges()[i]; + + return SMRange(); +} + +/// \brief Invert the 1-[0/1] mapping of diags to group into a one to many +/// mapping of groups to diags in the group. +static void groupDiagnostics(const std::vector<Record*> &Diags, + const std::vector<Record*> &DiagGroups, + std::map<std::string, GroupInfo> &DiagsInGroup) { + + for (unsigned i = 0, e = Diags.size(); i != e; ++i) { + const Record *R = Diags[i]; + DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group")); + if (DI == 0) continue; + assert(R->getValueAsDef("Class")->getName() != "CLASS_NOTE" && + "Note can't be in a DiagGroup"); + std::string GroupName = DI->getDef()->getValueAsString("GroupName"); + DiagsInGroup[GroupName].DiagsInGroup.push_back(R); + } + + typedef SmallPtrSet<GroupInfo *, 16> GroupSetTy; + GroupSetTy ImplicitGroups; + + // 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). + for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) { + Record *Group = DiagGroups[i]; + GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")]; + if (Group->isAnonymous()) { + if (GI.DiagsInGroup.size() > 1) + ImplicitGroups.insert(&GI); + } else { + if (GI.ExplicitDef) + assert(GI.ExplicitDef == Group); + else + GI.ExplicitDef = Group; + } + + 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; + + // Sort the implicit groups, so we can warn about them deterministically. + SmallVector<GroupInfo *, 16> SortedGroups(ImplicitGroups.begin(), + ImplicitGroups.end()); + for (SmallVectorImpl<GroupInfo *>::iterator I = SortedGroups.begin(), + E = SortedGroups.end(); + I != E; ++I) { + MutableArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup; + std::sort(GroupDiags.begin(), GroupDiags.end(), beforeThanCompare); + } + std::sort(SortedGroups.begin(), SortedGroups.end(), beforeThanCompareGroups); + + // Warn about the same group being used anonymously in multiple places. + for (SmallVectorImpl<GroupInfo *>::const_iterator I = SortedGroups.begin(), + E = SortedGroups.end(); + I != E; ++I) { + ArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup; + + if ((*I)->ExplicitDef) { + std::string Name = (*I)->ExplicitDef->getValueAsString("GroupName"); + for (ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(), + DE = GroupDiags.end(); + DI != DE; ++DI) { + const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group")); + const Record *NextDiagGroup = GroupInit->getDef(); + if (NextDiagGroup == (*I)->ExplicitDef) + continue; + + SMRange InGroupRange = findSuperClassRange(*DI, "InGroup"); + SmallString<64> Replacement; + if (InGroupRange.isValid()) { + Replacement += "InGroup<"; + Replacement += (*I)->ExplicitDef->getName(); + Replacement += ">"; + } + SMFixIt FixIt(InGroupRange, Replacement.str()); + + SrcMgr.PrintMessage(NextDiagGroup->getLoc().front(), + SourceMgr::DK_Error, + Twine("group '") + Name + + "' is referred to anonymously", + ArrayRef<SMRange>(), + InGroupRange.isValid() ? FixIt + : ArrayRef<SMFixIt>()); + SrcMgr.PrintMessage((*I)->ExplicitDef->getLoc().front(), + SourceMgr::DK_Note, "group defined here"); + } + } else { + // If there's no existing named group, we should just warn once and use + // notes to list all the other cases. + ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(), + DE = GroupDiags.end(); + assert(DI != DE && "We only care about groups with multiple uses!"); + + const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group")); + const Record *NextDiagGroup = GroupInit->getDef(); + std::string Name = NextDiagGroup->getValueAsString("GroupName"); + + SMRange InGroupRange = findSuperClassRange(*DI, "InGroup"); + SrcMgr.PrintMessage(NextDiagGroup->getLoc().front(), + SourceMgr::DK_Error, + Twine("group '") + Name + + "' is referred to anonymously", + InGroupRange); + + for (++DI; DI != DE; ++DI) { + GroupInit = cast<DefInit>((*DI)->getValueInit("Group")); + InGroupRange = findSuperClassRange(*DI, "InGroup"); + SrcMgr.PrintMessage(GroupInit->getDef()->getLoc().front(), + SourceMgr::DK_Note, "also referenced here", + InGroupRange); + } + } + } +} + +//===----------------------------------------------------------------------===// +// Infer members of -Wpedantic. +//===----------------------------------------------------------------------===// + +typedef std::vector<const Record *> RecordVec; +typedef llvm::DenseSet<const Record *> RecordSet; +typedef llvm::PointerUnion<RecordVec*, RecordSet*> VecOrSet; + +namespace { +class InferPedantic { + typedef llvm::DenseMap<const Record*, + std::pair<unsigned, Optional<unsigned> > > GMap; + + DiagGroupParentMap &DiagGroupParents; + const std::vector<Record*> &Diags; + const std::vector<Record*> DiagGroups; + std::map<std::string, GroupInfo> &DiagsInGroup; + llvm::DenseSet<const Record*> DiagsSet; + GMap GroupCount; +public: + InferPedantic(DiagGroupParentMap &DiagGroupParents, + const std::vector<Record*> &Diags, + const std::vector<Record*> &DiagGroups, + std::map<std::string, GroupInfo> &DiagsInGroup) + : DiagGroupParents(DiagGroupParents), + Diags(Diags), + DiagGroups(DiagGroups), + DiagsInGroup(DiagsInGroup) {} + + /// Compute the set of diagnostics and groups that are immediately + /// in -Wpedantic. + void compute(VecOrSet DiagsInPedantic, + VecOrSet GroupsInPedantic); + +private: + /// Determine whether a group is a subgroup of another group. + bool isSubGroupOfGroup(const Record *Group, + llvm::StringRef RootGroupName); + + /// Determine if the diagnostic is an extension. + bool isExtension(const Record *Diag); + + /// Determine if the diagnostic is off by default. + bool isOffByDefault(const Record *Diag); + + /// Increment the count for a group, and transitively marked + /// parent groups when appropriate. + void markGroup(const Record *Group); + + /// Return true if the diagnostic is in a pedantic group. + bool groupInPedantic(const Record *Group, bool increment = false); +}; +} // end anonymous namespace + +bool InferPedantic::isSubGroupOfGroup(const Record *Group, + llvm::StringRef GName) { + + const std::string &GroupName = Group->getValueAsString("GroupName"); + if (GName == GroupName) + return true; + + const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); + for (unsigned i = 0, e = Parents.size(); i != e; ++i) + if (isSubGroupOfGroup(Parents[i], GName)) + return true; + + return false; +} + +/// Determine if the diagnostic is an extension. +bool InferPedantic::isExtension(const Record *Diag) { + const std::string &ClsName = Diag->getValueAsDef("Class")->getName(); + return ClsName == "CLASS_EXTENSION"; +} + +bool InferPedantic::isOffByDefault(const Record *Diag) { + const std::string &DefMap = Diag->getValueAsDef("DefaultMapping")->getName(); + return DefMap == "MAP_IGNORE"; +} + +bool InferPedantic::groupInPedantic(const Record *Group, bool increment) { + GMap::mapped_type &V = GroupCount[Group]; + // Lazily compute the threshold value for the group count. + if (!V.second.hasValue()) { + const GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")]; + V.second = GI.SubGroups.size() + GI.DiagsInGroup.size(); + } + + if (increment) + ++V.first; + + // Consider a group in -Wpendatic IFF if has at least one diagnostic + // or subgroup AND all of those diagnostics and subgroups are covered + // by -Wpedantic via our computation. + return V.first != 0 && V.first == V.second.getValue(); +} + +void InferPedantic::markGroup(const Record *Group) { + // If all the diagnostics and subgroups have been marked as being + // covered by -Wpedantic, increment the count of parent groups. Once the + // group's count is equal to the number of subgroups and diagnostics in + // that group, we can safely add this group to -Wpedantic. + if (groupInPedantic(Group, /* increment */ true)) { + const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); + for (unsigned i = 0, e = Parents.size(); i != e; ++i) + markGroup(Parents[i]); + } +} + +void InferPedantic::compute(VecOrSet DiagsInPedantic, + VecOrSet GroupsInPedantic) { + // All extensions that are not on by default are implicitly in the + // "pedantic" group. For those that aren't explicitly included in -Wpedantic, + // mark them for consideration to be included in -Wpedantic directly. + for (unsigned i = 0, e = Diags.size(); i != e; ++i) { + Record *R = Diags[i]; + if (isExtension(R) && isOffByDefault(R)) { + DiagsSet.insert(R); + if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) { + const Record *GroupRec = Group->getDef(); + if (!isSubGroupOfGroup(GroupRec, "pedantic")) { + markGroup(GroupRec); + } + } + } + } + + // Compute the set of diagnostics that are directly in -Wpedantic. We + // march through Diags a second time to ensure the results are emitted + // in deterministic order. + for (unsigned i = 0, e = Diags.size(); i != e; ++i) { + Record *R = Diags[i]; + if (!DiagsSet.count(R)) + continue; + // Check if the group is implicitly in -Wpedantic. If so, + // the diagnostic should not be directly included in the -Wpedantic + // diagnostic group. + if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) + if (groupInPedantic(Group->getDef())) + continue; + + // The diagnostic is not included in a group that is (transitively) in + // -Wpedantic. Include it in -Wpedantic directly. + if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>()) + V->push_back(R); + else { + DiagsInPedantic.get<RecordSet*>()->insert(R); + } + } + + if (!GroupsInPedantic) + return; + + // Compute the set of groups that are directly in -Wpedantic. We + // march through the groups to ensure the results are emitted + /// in a deterministc order. + for (unsigned i = 0, ei = DiagGroups.size(); i != ei; ++i) { + Record *Group = DiagGroups[i]; + if (!groupInPedantic(Group)) + continue; + + unsigned ParentsInPedantic = 0; + const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); + for (unsigned j = 0, ej = Parents.size(); j != ej; ++j) { + if (groupInPedantic(Parents[j])) + ++ParentsInPedantic; + } + // If all the parents are in -Wpedantic, this means that this diagnostic + // group will be indirectly included by -Wpedantic already. In that + // case, do not add it directly to -Wpedantic. If the group has no + // parents, obviously it should go into -Wpedantic. + if (Parents.size() > 0 && ParentsInPedantic == Parents.size()) + continue; + + if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>()) + V->push_back(Group); + else { + GroupsInPedantic.get<RecordSet*>()->insert(Group); + } + } +} + +//===----------------------------------------------------------------------===// +// Warning Tables (.inc file) generation. +//===----------------------------------------------------------------------===// + +static bool isError(const Record &Diag) { + const std::string &ClsName = Diag.getValueAsDef("Class")->getName(); + return ClsName == "CLASS_ERROR"; +} + +/// ClangDiagsDefsEmitter - The top-level class emits .def files containing +/// declarations of Clang diagnostics. +namespace clang { +void EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS, + const std::string &Component) { + // Write the #if guard + if (!Component.empty()) { + std::string ComponentName = StringRef(Component).upper(); + 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"); + + std::vector<Record*> DiagGroups + = Records.getAllDerivedDefinitions("DiagGroup"); + + std::map<std::string, GroupInfo> DiagsInGroup; + groupDiagnostics(Diags, DiagGroups, DiagsInGroup); + + DiagCategoryIDMap CategoryIDs(Records); + DiagGroupParentMap DGParentMap(Records); + + // Compute the set of diagnostics that are in -Wpedantic. + RecordSet DiagsInPedantic; + InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); + inferPedantic.compute(&DiagsInPedantic, (RecordVec*)0); + + for (unsigned i = 0, e = Diags.size(); i != e; ++i) { + const Record &R = *Diags[i]; + + // Check if this is an error that is accidentally in a warning + // group. + if (isError(R)) { + if (DefInit *Group = dyn_cast<DefInit>(R.getValueInit("Group"))) { + const Record *GroupRec = Group->getDef(); + const std::string &GroupName = GroupRec->getValueAsString("GroupName"); + PrintFatalError(R.getLoc(), "Error " + R.getName() + + " cannot be in a warning group [" + GroupName + "]"); + } + } + + // 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. This is stored as an index into + // the alphabetically sorted warning table. + if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) { + std::map<std::string, GroupInfo>::iterator I = + DiagsInGroup.find(DI->getDef()->getValueAsString("GroupName")); + assert(I != DiagsInGroup.end()); + OS << ", " << I->second.IDNo; + } else if (DiagsInPedantic.count(&R)) { + std::map<std::string, GroupInfo>::iterator I = + DiagsInGroup.find("pedantic"); + assert(I != DiagsInGroup.end() && "pedantic group not defined"); + OS << ", " << I->second.IDNo; + } else { + OS << ", 0"; + } + + // 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)); + OS << ")\n"; + } +} +} // end namespace clang + +//===----------------------------------------------------------------------===// +// Warning Group Tables generation +//===----------------------------------------------------------------------===// + +static std::string getDiagCategoryEnum(llvm::StringRef name) { + if (name.empty()) + return "DiagCat_None"; + 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 clang { +void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) { + // Compute a mapping from a DiagGroup to all of its parents. + DiagGroupParentMap DGParentMap(Records); + + std::vector<Record*> Diags = + Records.getAllDerivedDefinitions("Diagnostic"); + + std::vector<Record*> DiagGroups + = Records.getAllDerivedDefinitions("DiagGroup"); + + std::map<std::string, GroupInfo> DiagsInGroup; + groupDiagnostics(Diags, DiagGroups, DiagsInGroup); + + // All extensions are implicitly in the "pedantic" group. Record the + // implicit set of groups in the "pedantic" group, and use this information + // later when emitting the group information for Pedantic. + RecordVec DiagsInPedantic; + RecordVec GroupsInPedantic; + InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); + inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic); + + // 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()); + const bool IsPedantic = I->first == "pedantic"; + + std::vector<const Record*> &V = I->second.DiagsInGroup; + if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) { + OS << "static const short DiagArray" << I->second.IDNo << "[] = { "; + for (unsigned i = 0, e = V.size(); i != e; ++i) + OS << "diag::" << V[i]->getName() << ", "; + // Emit the diagnostics implicitly in "pedantic". + if (IsPedantic) { + for (unsigned i = 0, e = DiagsInPedantic.size(); i != e; ++i) + OS << "diag::" << DiagsInPedantic[i]->getName() << ", "; + } + OS << "-1 };\n"; + } + + const std::vector<std::string> &SubGroups = I->second.SubGroups; + if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.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 << ", "; + } + // Emit the groups implicitly in "pedantic". + if (IsPedantic) { + for (unsigned i = 0, e = GroupsInPedantic.size(); i != e; ++i) { + const std::string &GroupName = + GroupsInPedantic[i]->getValueAsString("GroupName"); + std::map<std::string, GroupInfo>::iterator RI = + DiagsInGroup.find(GroupName); + 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 << "\""; + if (I->first.find_first_not_of("abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789!@#$%^*-+=:?")!=std::string::npos) + PrintFatalError("Invalid character in diagnostic group '" + + I->first + "'"); + OS.write_escaped(I->first) << "\"," + << std::string(MaxLen-I->first.size()+1, ' '); + + // Special handling for 'pedantic'. + const bool IsPedantic = I->first == "pedantic"; + + // Diagnostics in the group. + const bool hasDiags = !I->second.DiagsInGroup.empty() || + (IsPedantic && !DiagsInPedantic.empty()); + if (!hasDiags) + OS << "0, "; + else + OS << "DiagArray" << I->second.IDNo << ", "; + + // Subgroups. + const bool hasSubGroups = !I->second.SubGroups.empty() || + (IsPedantic && !GroupsInPedantic.empty()); + if (!hasSubGroups) + 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"; +} +} // end namespace clang + +//===----------------------------------------------------------------------===// +// 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. + +namespace clang { +void EmitClangDiagsIndexName(RecordKeeper &Records, 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"; + } +} +} // end namespace clang diff --git a/contrib/llvm/tools/clang/utils/TableGen/ClangSACheckersEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/ClangSACheckersEmitter.cpp new file mode 100644 index 0000000..8c74064 --- /dev/null +++ b/contrib/llvm/tools/clang/utils/TableGen/ClangSACheckersEmitter.cpp @@ -0,0 +1,322 @@ +//=- 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 "llvm/ADT/DenseSet.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.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 = dyn_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 = dyn_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 = dyn_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); +} + +namespace clang { +void EmitClangSACheckers(RecordKeeper &Records, 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 = dyn_cast<DefInit>(R->getValueInit("ParentPackage"))) + package = DI->getDef(); + if (!isCheckerNamed(R) && !package) + PrintFatalError(R->getLoc(), "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 + = dyn_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 = dyn_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 = dyn_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 = dyn_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 = dyn_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"; +} +} // end namespace clang diff --git a/contrib/llvm/tools/clang/utils/TableGen/NeonEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/NeonEmitter.cpp new file mode 100644 index 0000000..d453ede --- /dev/null +++ b/contrib/llvm/tools/clang/utils/TableGen/NeonEmitter.cpp @@ -0,0 +1,1781 @@ +//===- NeonEmitter.cpp - 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. +// +// Each NEON instruction is implemented in terms of 1 or more functions which +// are suffixed with the element type of the input vectors. Functions may be +// implemented in terms of generic vector operations such as +, *, -, etc. or +// by calling a __builtin_-prefixed function which will be handled by clang's +// CodeGen library. +// +// Additional validation code can be generated by this file when runHeader() is +// called, rather than the normal run() entry point. A complete set of tests +// for Neon intrinsics can be generated by calling the runTests() entry point. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" +#include <string> +using namespace llvm; + +enum OpKind { + OpNone, + OpUnavailable, + 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 +}; + +/// NeonTypeFlags - Flags to identify the types for overloaded Neon +/// builtins. These must be kept in sync with the flags in +/// include/clang/Basic/TargetBuiltins.h. +namespace { +class NeonTypeFlags { + enum { + EltTypeMask = 0xf, + UnsignedFlag = 0x10, + QuadFlag = 0x20 + }; + uint32_t Flags; + +public: + enum EltType { + Int8, + Int16, + Int32, + Int64, + Poly8, + Poly16, + Float16, + Float32 + }; + + NeonTypeFlags(unsigned F) : Flags(F) {} + NeonTypeFlags(EltType ET, bool IsUnsigned, bool IsQuad) : Flags(ET) { + if (IsUnsigned) + Flags |= UnsignedFlag; + if (IsQuad) + Flags |= QuadFlag; + } + + uint32_t getFlags() const { return Flags; } +}; +} // end anonymous namespace + +namespace { +class NeonEmitter { + RecordKeeper &Records; + StringMap<OpKind> OpMap; + DenseMap<Record*, ClassKind> ClassMap; + +public: + NeonEmitter(RecordKeeper &R) : Records(R) { + OpMap["OP_NONE"] = OpNone; + OpMap["OP_UNAVAILABLE"] = OpUnavailable; + 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 anonymous namespace + +/// ParseTypes - break down a string such as "fQf" into a vector of StringRefs, +/// which each StringRef representing a single type declared in the string. +/// for "fQf" we would end up with 2 StringRefs, "f", and "Qf", representing +/// 2xfloat and 4xfloat respectively. +static void ParseTypes(Record *r, std::string &s, + SmallVectorImpl<StringRef> &TV) { + const char *data = s.data(); + int len = 0; + + for (unsigned i = 0, e = s.size(); i != e; ++i, ++len) { + if (data[len] == 'P' || data[len] == 'Q' || data[len] == 'U') + continue; + + switch (data[len]) { + case 'c': + case 's': + case 'i': + case 'l': + case 'h': + case 'f': + break; + default: + PrintFatalError(r->getLoc(), + "Unexpected letter: " + std::string(data + len, 1)); + } + TV.push_back(StringRef(data, len + 1)); + data += len + 1; + len = -1; + } +} + +/// Widen - Convert a type code into the next wider type. char -> short, +/// short -> int, etc. +static char Widen(const char t) { + switch (t) { + case 'c': + return 's'; + case 's': + return 'i'; + case 'i': + return 'l'; + case 'h': + return 'f'; + default: + PrintFatalError("unhandled type in widen!"); + } +} + +/// Narrow - Convert a type code into the next smaller type. short -> char, +/// float -> half float, etc. +static char Narrow(const char t) { + switch (t) { + case 's': + return 'c'; + case 'i': + return 's'; + case 'l': + return 'i'; + case 'f': + return 'h'; + default: + PrintFatalError("unhandled type in narrow!"); + } +} + +/// For a particular StringRef, return the base type code, and whether it has +/// the quad-vector, polynomial, or unsigned modifiers set. +static char ClassifyType(StringRef ty, bool &quad, bool &poly, bool &usgn) { + unsigned off = 0; + + // remember quad. + if (ty[off] == 'Q') { + quad = true; + ++off; + } + + // remember poly. + if (ty[off] == 'P') { + poly = true; + ++off; + } + + // remember unsigned. + if (ty[off] == 'U') { + usgn = true; + ++off; + } + + // base type to get the type string for. + return ty[off]; +} + +/// ModType - Transform a type code and its modifiers based on a mod code. The +/// mod code definitions may be found at the top of arm_neon.td. +static char ModType(const char mod, char type, bool &quad, bool &poly, + bool &usgn, bool &scal, bool &cnst, bool &pntr) { + switch (mod) { + case 't': + if (poly) { + poly = false; + usgn = true; + } + break; + case 'u': + usgn = true; + poly = false; + if (type == 'f') + type = 'i'; + break; + case 'x': + usgn = false; + poly = false; + if (type == 'f') + type = 'i'; + break; + case 'f': + if (type == 'h') + quad = true; + type = 'f'; + usgn = false; + break; + case 'g': + quad = false; + break; + case 'w': + type = Widen(type); + quad = true; + break; + case 'n': + type = Widen(type); + break; + case 'i': + type = 'i'; + scal = true; + break; + case 'l': + type = 'l'; + scal = true; + usgn = true; + break; + case 's': + case 'a': + scal = true; + break; + case 'k': + quad = true; + break; + case 'c': + cnst = true; + case 'p': + pntr = true; + scal = true; + break; + case 'h': + type = Narrow(type); + if (type == 'h') + quad = false; + break; + case 'e': + type = Narrow(type); + usgn = true; + break; + default: + break; + } + return type; +} + +/// TypeString - for a modifier and type, generate the name of the typedef for +/// that type. QUc -> uint8x8_t. +static std::string TypeString(const char mod, StringRef typestr) { + bool quad = false; + bool poly = false; + bool usgn = false; + bool scal = false; + bool cnst = false; + bool pntr = false; + + if (mod == 'v') + return "void"; + if (mod == 'i') + return "int"; + + // base type to get the type string for. + char type = ClassifyType(typestr, quad, poly, usgn); + + // Based on the modifying character, change the type and width if necessary. + type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr); + + SmallString<128> s; + + if (usgn) + s.push_back('u'); + + switch (type) { + case 'c': + s += poly ? "poly8" : "int8"; + if (scal) + break; + s += quad ? "x16" : "x8"; + break; + case 's': + s += poly ? "poly16" : "int16"; + if (scal) + break; + s += quad ? "x8" : "x4"; + break; + case 'i': + s += "int32"; + if (scal) + break; + s += quad ? "x4" : "x2"; + break; + case 'l': + s += "int64"; + if (scal) + break; + s += quad ? "x2" : "x1"; + break; + case 'h': + s += "float16"; + if (scal) + break; + s += quad ? "x8" : "x4"; + break; + case 'f': + s += "float32"; + if (scal) + break; + s += quad ? "x4" : "x2"; + break; + default: + PrintFatalError("unhandled type!"); + } + + if (mod == '2') + s += "x2"; + if (mod == '3') + s += "x3"; + if (mod == '4') + s += "x4"; + + // Append _t, finishing the type string typedef type. + s += "_t"; + + if (cnst) + s += " const"; + + if (pntr) + s += " *"; + + return s.str(); +} + +/// BuiltinTypeString - for a modifier and type, generate the clang +/// BuiltinsARM.def prototype code for the function. See the top of clang's +/// Builtins.def for a description of the type strings. +static std::string BuiltinTypeString(const char mod, StringRef typestr, + ClassKind ck, bool ret) { + bool quad = false; + bool poly = false; + bool usgn = false; + bool scal = false; + bool cnst = false; + bool pntr = false; + + if (mod == 'v') + return "v"; // void + if (mod == 'i') + return "i"; // int + + // base type to get the type string for. + char type = ClassifyType(typestr, quad, poly, usgn); + + // Based on the modifying character, change the type and width if necessary. + type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr); + + // All pointers are void* pointers. Change type to 'v' now. + if (pntr) { + usgn = false; + poly = false; + type = 'v'; + } + // Treat half-float ('h') types as unsigned short ('s') types. + if (type == 'h') { + type = 's'; + usgn = true; + } + usgn = usgn | poly | ((ck == ClassI || ck == ClassW) && scal && type != 'f'); + + if (scal) { + SmallString<128> s; + + if (usgn) + s.push_back('U'); + else if (type == 'c') + s.push_back('S'); // make chars explicitly signed + + if (type == 'l') // 64-bit long + s += "LLi"; + else + s.push_back(type); + + if (cnst) + s.push_back('C'); + if (pntr) + s.push_back('*'); + return s.str(); + } + + // Since the return value must be one type, return a vector type of the + // appropriate width which we will bitcast. An exception is made for + // returning structs of 2, 3, or 4 vectors which are returned in a sret-like + // fashion, storing them to a pointer arg. + if (ret) { + if (mod >= '2' && mod <= '4') + return "vv*"; // void result with void* first argument + if (mod == 'f' || (ck != ClassB && type == 'f')) + return quad ? "V4f" : "V2f"; + if (ck != ClassB && type == 's') + return quad ? "V8s" : "V4s"; + if (ck != ClassB && type == 'i') + return quad ? "V4i" : "V2i"; + if (ck != ClassB && type == 'l') + return quad ? "V2LLi" : "V1LLi"; + + return quad ? "V16Sc" : "V8Sc"; + } + + // Non-return array types are passed as individual vectors. + if (mod == '2') + return quad ? "V16ScV16Sc" : "V8ScV8Sc"; + if (mod == '3') + return quad ? "V16ScV16ScV16Sc" : "V8ScV8ScV8Sc"; + if (mod == '4') + return quad ? "V16ScV16ScV16ScV16Sc" : "V8ScV8ScV8ScV8Sc"; + + if (mod == 'f' || (ck != ClassB && type == 'f')) + return quad ? "V4f" : "V2f"; + if (ck != ClassB && type == 's') + return quad ? "V8s" : "V4s"; + if (ck != ClassB && type == 'i') + return quad ? "V4i" : "V2i"; + if (ck != ClassB && type == 'l') + return quad ? "V2LLi" : "V1LLi"; + + return quad ? "V16Sc" : "V8Sc"; +} + +/// MangleName - Append a type or width suffix to a base neon function name, +/// and insert a 'q' in the appropriate location if the operation works on +/// 128b rather than 64b. E.g. turn "vst2_lane" into "vst2q_lane_f32", etc. +static std::string MangleName(const std::string &name, StringRef typestr, + ClassKind ck) { + if (name == "vcvt_f32_f16") + return name; + + bool quad = false; + bool poly = false; + bool usgn = false; + char type = ClassifyType(typestr, quad, poly, usgn); + + std::string s = name; + + switch (type) { + case 'c': + switch (ck) { + case ClassS: s += poly ? "_p8" : usgn ? "_u8" : "_s8"; break; + case ClassI: s += "_i8"; break; + case ClassW: s += "_8"; break; + default: break; + } + break; + case 's': + switch (ck) { + case ClassS: s += poly ? "_p16" : usgn ? "_u16" : "_s16"; break; + case ClassI: s += "_i16"; break; + case ClassW: s += "_16"; break; + default: break; + } + break; + case 'i': + switch (ck) { + case ClassS: s += usgn ? "_u32" : "_s32"; break; + case ClassI: s += "_i32"; break; + case ClassW: s += "_32"; break; + default: break; + } + break; + case 'l': + switch (ck) { + case ClassS: s += usgn ? "_u64" : "_s64"; break; + case ClassI: s += "_i64"; break; + case ClassW: s += "_64"; break; + default: break; + } + break; + case 'h': + switch (ck) { + case ClassS: + case ClassI: s += "_f16"; break; + case ClassW: s += "_16"; break; + default: break; + } + break; + case 'f': + switch (ck) { + case ClassS: + case ClassI: s += "_f32"; break; + case ClassW: s += "_32"; break; + default: break; + } + break; + default: + PrintFatalError("unhandled type!"); + } + if (ck == ClassB) + s += "_v"; + + // Insert a 'q' before the first '_' character so that it ends up before + // _lane or _n on vector-scalar operations. + if (quad) { + size_t pos = s.find('_'); + s = s.insert(pos, "q"); + } + return s; +} + +/// UseMacro - Examine the prototype string to determine if the intrinsic +/// should be defined as a preprocessor macro instead of an inline function. +static bool UseMacro(const std::string &proto) { + // If this builtin takes an immediate argument, we need to #define it rather + // than use a standard declaration, so that SemaChecking can range check + // the immediate passed by the user. + if (proto.find('i') != std::string::npos) + return true; + + // Pointer arguments need to use macros to avoid hiding aligned attributes + // from the pointer type. + if (proto.find('p') != std::string::npos || + proto.find('c') != std::string::npos) + return true; + + return false; +} + +/// MacroArgUsedDirectly - Return true if argument i for an intrinsic that is +/// defined as a macro should be accessed directly instead of being first +/// assigned to a local temporary. +static bool MacroArgUsedDirectly(const std::string &proto, unsigned i) { + // True for constant ints (i), pointers (p) and const pointers (c). + return (proto[i] == 'i' || proto[i] == 'p' || proto[i] == 'c'); +} + +// Generate the string "(argtype a, argtype b, ...)" +static std::string GenArgs(const std::string &proto, StringRef typestr) { + bool define = UseMacro(proto); + char arg = 'a'; + + std::string s; + s += "("; + + for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { + if (define) { + // Some macro arguments are used directly instead of being assigned + // to local temporaries; prepend an underscore prefix to make their + // names consistent with the local temporaries. + if (MacroArgUsedDirectly(proto, i)) + s += "__"; + } else { + s += TypeString(proto[i], typestr) + " __"; + } + s.push_back(arg); + if ((i + 1) < e) + s += ", "; + } + + s += ")"; + return s; +} + +// Macro arguments are not type-checked like inline function arguments, so +// assign them to local temporaries to get the right type checking. +static std::string GenMacroLocals(const std::string &proto, StringRef typestr) { + char arg = 'a'; + std::string s; + bool generatedLocal = false; + + for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { + // Do not create a temporary for an immediate argument. + // That would defeat the whole point of using a macro! + if (MacroArgUsedDirectly(proto, i)) + continue; + generatedLocal = true; + + s += TypeString(proto[i], typestr) + " __"; + s.push_back(arg); + s += " = ("; + s.push_back(arg); + s += "); "; + } + + if (generatedLocal) + s += "\\\n "; + return s; +} + +// Use the vmovl builtin to sign-extend or zero-extend a vector. +static std::string Extend(StringRef typestr, const std::string &a) { + std::string s; + s = MangleName("vmovl", typestr, ClassS); + s += "(" + a + ")"; + return s; +} + +static std::string Duplicate(unsigned nElts, StringRef typestr, + const std::string &a) { + std::string s; + + s = "(" + TypeString('d', typestr) + "){ "; + for (unsigned i = 0; i != nElts; ++i) { + s += a; + if ((i + 1) < nElts) + s += ", "; + } + s += " }"; + + return s; +} + +static std::string SplatLane(unsigned nElts, const std::string &vec, + const std::string &lane) { + std::string s = "__builtin_shufflevector(" + vec + ", " + vec; + for (unsigned i = 0; i < nElts; ++i) + s += ", " + lane; + s += ")"; + return s; +} + +static unsigned GetNumElements(StringRef typestr, bool &quad) { + quad = false; + bool dummy = false; + char type = ClassifyType(typestr, quad, dummy, dummy); + unsigned nElts = 0; + switch (type) { + case 'c': nElts = 8; break; + case 's': nElts = 4; break; + case 'i': nElts = 2; break; + case 'l': nElts = 1; break; + case 'h': nElts = 4; break; + case 'f': nElts = 2; break; + default: + PrintFatalError("unhandled type!"); + } + if (quad) nElts <<= 1; + return nElts; +} + +// Generate the definition for this intrinsic, e.g. "a + b" for OpAdd. +static std::string GenOpString(OpKind op, const std::string &proto, + StringRef typestr) { + bool quad; + unsigned nElts = GetNumElements(typestr, quad); + bool define = UseMacro(proto); + + std::string ts = TypeString(proto[0], typestr); + std::string s; + if (!define) { + s = "return "; + } + + switch(op) { + case OpAdd: + s += "__a + __b;"; + break; + case OpAddl: + s += Extend(typestr, "__a") + " + " + Extend(typestr, "__b") + ";"; + break; + case OpAddw: + s += "__a + " + Extend(typestr, "__b") + ";"; + break; + case OpSub: + s += "__a - __b;"; + break; + case OpSubl: + s += Extend(typestr, "__a") + " - " + Extend(typestr, "__b") + ";"; + break; + case OpSubw: + s += "__a - " + Extend(typestr, "__b") + ";"; + break; + case OpMulN: + s += "__a * " + Duplicate(nElts, typestr, "__b") + ";"; + break; + case OpMulLane: + s += "__a * " + SplatLane(nElts, "__b", "__c") + ";"; + break; + case OpMul: + s += "__a * __b;"; + break; + case OpMullLane: + s += MangleName("vmull", typestr, ClassS) + "(__a, " + + SplatLane(nElts, "__b", "__c") + ");"; + break; + case OpMlaN: + s += "__a + (__b * " + Duplicate(nElts, typestr, "__c") + ");"; + break; + case OpMlaLane: + s += "__a + (__b * " + SplatLane(nElts, "__c", "__d") + ");"; + break; + case OpMla: + s += "__a + (__b * __c);"; + break; + case OpMlalN: + s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " + + Duplicate(nElts, typestr, "__c") + ");"; + break; + case OpMlalLane: + s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " + + SplatLane(nElts, "__c", "__d") + ");"; + break; + case OpMlal: + s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, __c);"; + break; + case OpMlsN: + s += "__a - (__b * " + Duplicate(nElts, typestr, "__c") + ");"; + break; + case OpMlsLane: + s += "__a - (__b * " + SplatLane(nElts, "__c", "__d") + ");"; + break; + case OpMls: + s += "__a - (__b * __c);"; + break; + case OpMlslN: + s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " + + Duplicate(nElts, typestr, "__c") + ");"; + break; + case OpMlslLane: + s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " + + SplatLane(nElts, "__c", "__d") + ");"; + break; + case OpMlsl: + s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, __c);"; + break; + case OpQDMullLane: + s += MangleName("vqdmull", typestr, ClassS) + "(__a, " + + SplatLane(nElts, "__b", "__c") + ");"; + break; + case OpQDMlalLane: + s += MangleName("vqdmlal", typestr, ClassS) + "(__a, __b, " + + SplatLane(nElts, "__c", "__d") + ");"; + break; + case OpQDMlslLane: + s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, __b, " + + SplatLane(nElts, "__c", "__d") + ");"; + break; + case OpQDMulhLane: + s += MangleName("vqdmulh", typestr, ClassS) + "(__a, " + + SplatLane(nElts, "__b", "__c") + ");"; + break; + case OpQRDMulhLane: + s += MangleName("vqrdmulh", typestr, ClassS) + "(__a, " + + SplatLane(nElts, "__b", "__c") + ");"; + break; + case OpEq: + s += "(" + ts + ")(__a == __b);"; + break; + case OpGe: + s += "(" + ts + ")(__a >= __b);"; + break; + case OpLe: + s += "(" + ts + ")(__a <= __b);"; + break; + case OpGt: + s += "(" + ts + ")(__a > __b);"; + break; + case OpLt: + s += "(" + ts + ")(__a < __b);"; + break; + case OpNeg: + s += " -__a;"; + break; + case OpNot: + s += " ~__a;"; + break; + case OpAnd: + s += "__a & __b;"; + break; + case OpOr: + s += "__a | __b;"; + break; + case OpXor: + s += "__a ^ __b;"; + break; + case OpAndNot: + s += "__a & ~__b;"; + break; + case OpOrNot: + s += "__a | ~__b;"; + break; + case OpCast: + s += "(" + ts + ")__a;"; + break; + case OpConcat: + s += "(" + ts + ")__builtin_shufflevector((int64x1_t)__a"; + s += ", (int64x1_t)__b, 0, 1);"; + break; + case OpHi: + s += "(" + ts + + ")__builtin_shufflevector((int64x2_t)__a, (int64x2_t)__a, 1);"; + break; + case OpLo: + s += "(" + ts + + ")__builtin_shufflevector((int64x2_t)__a, (int64x2_t)__a, 0);"; + break; + case OpDup: + s += Duplicate(nElts, typestr, "__a") + ";"; + break; + case OpDupLane: + s += SplatLane(nElts, "__a", "__b") + ";"; + break; + case OpSelect: + // ((0 & 1) | (~0 & 2)) + s += "(" + ts + ")"; + ts = TypeString(proto[1], typestr); + s += "((__a & (" + ts + ")__b) | "; + s += "(~__a & (" + ts + ")__c));"; + break; + case OpRev16: + s += "__builtin_shufflevector(__a, __a"; + for (unsigned i = 2; i <= nElts; i += 2) + for (unsigned j = 0; j != 2; ++j) + s += ", " + utostr(i - j - 1); + s += ");"; + break; + case OpRev32: { + unsigned WordElts = nElts >> (1 + (int)quad); + s += "__builtin_shufflevector(__a, __a"; + for (unsigned i = WordElts; i <= nElts; i += WordElts) + for (unsigned j = 0; j != WordElts; ++j) + s += ", " + utostr(i - j - 1); + s += ");"; + break; + } + case OpRev64: { + unsigned DblWordElts = nElts >> (int)quad; + s += "__builtin_shufflevector(__a, __a"; + for (unsigned i = DblWordElts; i <= nElts; i += DblWordElts) + for (unsigned j = 0; j != DblWordElts; ++j) + s += ", " + utostr(i - j - 1); + s += ");"; + break; + } + case OpAbdl: { + std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; + if (typestr[0] != 'U') { + // vabd results are always unsigned and must be zero-extended. + std::string utype = "U" + typestr.str(); + s += "(" + TypeString(proto[0], typestr) + ")"; + abd = "(" + TypeString('d', utype) + ")" + abd; + s += Extend(utype, abd) + ";"; + } else { + s += Extend(typestr, abd) + ";"; + } + break; + } + case OpAba: + s += "__a + " + MangleName("vabd", typestr, ClassS) + "(__b, __c);"; + break; + case OpAbal: { + s += "__a + "; + std::string abd = MangleName("vabd", typestr, ClassS) + "(__b, __c)"; + if (typestr[0] != 'U') { + // vabd results are always unsigned and must be zero-extended. + std::string utype = "U" + typestr.str(); + s += "(" + TypeString(proto[0], typestr) + ")"; + abd = "(" + TypeString('d', utype) + ")" + abd; + s += Extend(utype, abd) + ";"; + } else { + s += Extend(typestr, abd) + ";"; + } + break; + } + default: + PrintFatalError("unknown OpKind!"); + } + return s; +} + +static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) { + unsigned mod = proto[0]; + + if (mod == 'v' || mod == 'f') + mod = proto[1]; + + bool quad = false; + bool poly = false; + bool usgn = false; + bool scal = false; + bool cnst = false; + bool pntr = false; + + // Base type to get the type string for. + char type = ClassifyType(typestr, quad, poly, usgn); + + // Based on the modifying character, change the type and width if necessary. + type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr); + + NeonTypeFlags::EltType ET; + switch (type) { + case 'c': + ET = poly ? NeonTypeFlags::Poly8 : NeonTypeFlags::Int8; + break; + case 's': + ET = poly ? NeonTypeFlags::Poly16 : NeonTypeFlags::Int16; + break; + case 'i': + ET = NeonTypeFlags::Int32; + break; + case 'l': + ET = NeonTypeFlags::Int64; + break; + case 'h': + ET = NeonTypeFlags::Float16; + break; + case 'f': + ET = NeonTypeFlags::Float32; + break; + default: + PrintFatalError("unhandled type!"); + } + NeonTypeFlags Flags(ET, usgn, quad && proto[1] != 'g'); + return Flags.getFlags(); +} + +// Generate the definition for this intrinsic, e.g. __builtin_neon_cls(a) +static std::string GenBuiltin(const std::string &name, const std::string &proto, + StringRef typestr, ClassKind ck) { + std::string s; + + // If this builtin returns a struct 2, 3, or 4 vectors, pass it as an implicit + // sret-like argument. + bool sret = (proto[0] >= '2' && proto[0] <= '4'); + + bool define = UseMacro(proto); + + // Check if the prototype has a scalar operand with the type of the vector + // elements. If not, bitcasting the args will take care of arg checking. + // The actual signedness etc. will be taken care of with special enums. + if (proto.find('s') == std::string::npos) + ck = ClassB; + + if (proto[0] != 'v') { + std::string ts = TypeString(proto[0], typestr); + + if (define) { + if (sret) + s += ts + " r; "; + else + s += "(" + ts + ")"; + } else if (sret) { + s += ts + " r; "; + } else { + s += "return (" + ts + ")"; + } + } + + bool splat = proto.find('a') != std::string::npos; + + s += "__builtin_neon_"; + if (splat) { + // Call the non-splat builtin: chop off the "_n" suffix from the name. + std::string vname(name, 0, name.size()-2); + s += MangleName(vname, typestr, ck); + } else { + s += MangleName(name, typestr, ck); + } + s += "("; + + // Pass the address of the return variable as the first argument to sret-like + // builtins. + if (sret) + s += "&r, "; + + char arg = 'a'; + for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { + std::string args = std::string(&arg, 1); + + // Use the local temporaries instead of the macro arguments. + args = "__" + args; + + bool argQuad = false; + bool argPoly = false; + bool argUsgn = false; + bool argScalar = false; + bool dummy = false; + char argType = ClassifyType(typestr, argQuad, argPoly, argUsgn); + argType = ModType(proto[i], argType, argQuad, argPoly, argUsgn, argScalar, + dummy, dummy); + + // Handle multiple-vector values specially, emitting each subvector as an + // argument to the __builtin. + if (proto[i] >= '2' && proto[i] <= '4') { + // Check if an explicit cast is needed. + if (argType != 'c' || argPoly || argUsgn) + args = (argQuad ? "(int8x16_t)" : "(int8x8_t)") + args; + + for (unsigned vi = 0, ve = proto[i] - '0'; vi != ve; ++vi) { + s += args + ".val[" + utostr(vi) + "]"; + if ((vi + 1) < ve) + s += ", "; + } + if ((i + 1) < e) + s += ", "; + + continue; + } + + if (splat && (i + 1) == e) + args = Duplicate(GetNumElements(typestr, argQuad), typestr, args); + + // Check if an explicit cast is needed. + if ((splat || !argScalar) && + ((ck == ClassB && argType != 'c') || argPoly || argUsgn)) { + std::string argTypeStr = "c"; + if (ck != ClassB) + argTypeStr = argType; + if (argQuad) + argTypeStr = "Q" + argTypeStr; + args = "(" + TypeString('d', argTypeStr) + ")" + args; + } + + s += args; + if ((i + 1) < e) + s += ", "; + } + + // Extra constant integer to hold type class enum for this function, e.g. s8 + if (ck == ClassB) + s += ", " + utostr(GetNeonEnum(proto, typestr)); + + s += ");"; + + if (proto[0] != 'v' && sret) { + if (define) + s += " r;"; + else + s += " return r;"; + } + return s; +} + +static std::string GenBuiltinDef(const std::string &name, + const std::string &proto, + StringRef typestr, ClassKind ck) { + std::string s("BUILTIN(__builtin_neon_"); + + // If all types are the same size, bitcasting the args will take care + // of arg checking. The actual signedness etc. will be taken care of with + // special enums. + if (proto.find('s') == std::string::npos) + ck = ClassB; + + s += MangleName(name, typestr, ck); + s += ", \""; + + for (unsigned i = 0, e = proto.size(); i != e; ++i) + s += BuiltinTypeString(proto[i], typestr, ck, i == 0); + + // Extra constant integer to hold type class enum for this function, e.g. s8 + if (ck == ClassB) + s += "i"; + + s += "\", \"n\")"; + return s; +} + +static std::string GenIntrinsic(const std::string &name, + const std::string &proto, + StringRef outTypeStr, StringRef inTypeStr, + OpKind kind, ClassKind classKind) { + assert(!proto.empty() && ""); + bool define = UseMacro(proto) && kind != OpUnavailable; + std::string s; + + // static always inline + return type + if (define) + s += "#define "; + else + s += "__ai " + TypeString(proto[0], outTypeStr) + " "; + + // Function name with type suffix + std::string mangledName = MangleName(name, outTypeStr, ClassS); + if (outTypeStr != inTypeStr) { + // If the input type is different (e.g., for vreinterpret), append a suffix + // for the input type. String off a "Q" (quad) prefix so that MangleName + // does not insert another "q" in the name. + unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0); + StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff); + mangledName = MangleName(mangledName, inTypeNoQuad, ClassS); + } + s += mangledName; + + // Function arguments + s += GenArgs(proto, inTypeStr); + + // Definition. + if (define) { + s += " __extension__ ({ \\\n "; + s += GenMacroLocals(proto, inTypeStr); + } else if (kind == OpUnavailable) { + s += " __attribute__((unavailable));\n"; + return s; + } else + s += " {\n "; + + if (kind != OpNone) + s += GenOpString(kind, proto, outTypeStr); + else + s += GenBuiltin(name, proto, outTypeStr, classKind); + if (define) + s += " })"; + else + s += " }"; + s += "\n"; + return s; +} + +/// run - Read the records in arm_neon.td and output arm_neon.h. arm_neon.h +/// is comprised of type definitions and function declarations. +void NeonEmitter::run(raw_ostream &OS) { + OS << + "/*===---- arm_neon.h - ARM Neon intrinsics ------------------------------" + "---===\n" + " *\n" + " * Permission is hereby granted, free of charge, to any person obtaining " + "a copy\n" + " * of this software and associated documentation files (the \"Software\")," + " to deal\n" + " * in the Software without restriction, including without limitation the " + "rights\n" + " * to use, copy, modify, merge, publish, distribute, sublicense, " + "and/or sell\n" + " * copies of the Software, and to permit persons to whom the Software is\n" + " * furnished to do so, subject to the following conditions:\n" + " *\n" + " * The above copyright notice and this permission notice shall be " + "included in\n" + " * all copies or substantial portions of the Software.\n" + " *\n" + " * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, " + "EXPRESS OR\n" + " * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF " + "MERCHANTABILITY,\n" + " * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT " + "SHALL THE\n" + " * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR " + "OTHER\n" + " * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, " + "ARISING FROM,\n" + " * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER " + "DEALINGS IN\n" + " * THE SOFTWARE.\n" + " *\n" + " *===--------------------------------------------------------------------" + "---===\n" + " */\n\n"; + + OS << "#ifndef __ARM_NEON_H\n"; + OS << "#define __ARM_NEON_H\n\n"; + + OS << "#ifndef __ARM_NEON__\n"; + OS << "#error \"NEON support not enabled\"\n"; + OS << "#endif\n\n"; + + OS << "#include <stdint.h>\n\n"; + + // Emit NEON-specific scalar typedefs. + OS << "typedef float float32_t;\n"; + OS << "typedef int8_t poly8_t;\n"; + OS << "typedef int16_t poly16_t;\n"; + OS << "typedef uint16_t float16_t;\n"; + + // Emit Neon vector typedefs. + std::string TypedefTypes("cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfPcQPcPsQPs"); + SmallVector<StringRef, 24> TDTypeVec; + ParseTypes(0, TypedefTypes, TDTypeVec); + + // Emit vector typedefs. + for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) { + bool dummy, quad = false, poly = false; + (void) ClassifyType(TDTypeVec[i], quad, poly, dummy); + if (poly) + OS << "typedef __attribute__((neon_polyvector_type("; + else + OS << "typedef __attribute__((neon_vector_type("; + + unsigned nElts = GetNumElements(TDTypeVec[i], quad); + OS << utostr(nElts) << "))) "; + if (nElts < 10) + OS << " "; + + OS << TypeString('s', TDTypeVec[i]); + OS << " " << TypeString('d', TDTypeVec[i]) << ";\n"; + } + OS << "\n"; + + // Emit struct typedefs. + for (unsigned vi = 2; vi != 5; ++vi) { + for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) { + std::string ts = TypeString('d', TDTypeVec[i]); + std::string vs = TypeString('0' + vi, TDTypeVec[i]); + OS << "typedef struct " << vs << " {\n"; + OS << " " << ts << " val"; + OS << "[" << utostr(vi) << "]"; + OS << ";\n} "; + OS << vs << ";\n\n"; + } + } + + OS<<"#define __ai static __attribute__((__always_inline__, __nodebug__))\n\n"; + + std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst"); + + // Emit vmovl, vmull and vabd intrinsics first so they can be used by other + // intrinsics. (Some of the saturating multiply instructions are also + // used to implement the corresponding "_lane" variants, but tablegen + // sorts the records into alphabetical order so that the "_lane" variants + // come after the intrinsics they use.) + emitIntrinsic(OS, Records.getDef("VMOVL")); + emitIntrinsic(OS, Records.getDef("VMULL")); + emitIntrinsic(OS, Records.getDef("VABD")); + + for (unsigned i = 0, e = RV.size(); i != e; ++i) { + Record *R = RV[i]; + if (R->getName() != "VMOVL" && + R->getName() != "VMULL" && + R->getName() != "VABD") + emitIntrinsic(OS, R); + } + + OS << "#undef __ai\n\n"; + OS << "#endif /* __ARM_NEON_H */\n"; +} + +/// emitIntrinsic - Write out the arm_neon.h header file definitions for the +/// intrinsics specified by record R. +void NeonEmitter::emitIntrinsic(raw_ostream &OS, Record *R) { + std::string name = R->getValueAsString("Name"); + std::string Proto = R->getValueAsString("Prototype"); + std::string Types = R->getValueAsString("Types"); + + SmallVector<StringRef, 16> TypeVec; + ParseTypes(R, Types, TypeVec); + + OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()]; + + ClassKind classKind = ClassNone; + if (R->getSuperClasses().size() >= 2) + classKind = ClassMap[R->getSuperClasses()[1]]; + if (classKind == ClassNone && kind == OpNone) + PrintFatalError(R->getLoc(), "Builtin has no class kind"); + + for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { + if (kind == OpReinterpret) { + bool outQuad = false; + bool dummy = false; + (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy); + for (unsigned srcti = 0, srcte = TypeVec.size(); + srcti != srcte; ++srcti) { + bool inQuad = false; + (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy); + if (srcti == ti || inQuad != outQuad) + continue; + OS << GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[srcti], + OpCast, ClassS); + } + } else { + OS << GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[ti], + kind, classKind); + } + } + OS << "\n"; +} + +static unsigned RangeFromType(const char mod, StringRef typestr) { + // base type to get the type string for. + bool quad = false, dummy = false; + char type = ClassifyType(typestr, quad, dummy, dummy); + type = ModType(mod, type, quad, dummy, dummy, dummy, dummy, dummy); + + switch (type) { + case 'c': + return (8 << (int)quad) - 1; + case 'h': + case 's': + return (4 << (int)quad) - 1; + case 'f': + case 'i': + return (2 << (int)quad) - 1; + case 'l': + return (1 << (int)quad) - 1; + default: + PrintFatalError("unhandled type!"); + } +} + +/// runHeader - Emit a file with sections defining: +/// 1. the NEON section of BuiltinsARM.def. +/// 2. the SemaChecking code for the type overload checking. +/// 3. the SemaChecking code for validation of intrinsic immediate arguments. +void NeonEmitter::runHeader(raw_ostream &OS) { + std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst"); + + StringMap<OpKind> EmittedMap; + + // Generate BuiltinsARM.def for NEON + OS << "#ifdef GET_NEON_BUILTINS\n"; + for (unsigned i = 0, e = RV.size(); i != e; ++i) { + Record *R = RV[i]; + OpKind k = OpMap[R->getValueAsDef("Operand")->getName()]; + if (k != OpNone) + continue; + + std::string Proto = R->getValueAsString("Prototype"); + + // Functions with 'a' (the splat code) in the type prototype should not get + // their own builtin as they use the non-splat variant. + if (Proto.find('a') != std::string::npos) + continue; + + std::string Types = R->getValueAsString("Types"); + SmallVector<StringRef, 16> TypeVec; + ParseTypes(R, Types, TypeVec); + + if (R->getSuperClasses().size() < 2) + PrintFatalError(R->getLoc(), "Builtin has no class kind"); + + std::string name = R->getValueAsString("Name"); + ClassKind ck = ClassMap[R->getSuperClasses()[1]]; + + for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { + // Generate the BuiltinsARM.def declaration for this builtin, ensuring + // that each unique BUILTIN() macro appears only once in the output + // stream. + std::string bd = GenBuiltinDef(name, Proto, TypeVec[ti], ck); + if (EmittedMap.count(bd)) + continue; + + EmittedMap[bd] = OpNone; + OS << bd << "\n"; + } + } + OS << "#endif\n\n"; + + // Generate the overloaded type checking code for SemaChecking.cpp + OS << "#ifdef GET_NEON_OVERLOAD_CHECK\n"; + for (unsigned i = 0, e = RV.size(); i != e; ++i) { + Record *R = RV[i]; + OpKind k = OpMap[R->getValueAsDef("Operand")->getName()]; + if (k != OpNone) + continue; + + std::string Proto = R->getValueAsString("Prototype"); + std::string Types = R->getValueAsString("Types"); + std::string name = R->getValueAsString("Name"); + + // Functions with 'a' (the splat code) in the type prototype should not get + // their own builtin as they use the non-splat variant. + if (Proto.find('a') != std::string::npos) + continue; + + // Functions which have a scalar argument cannot be overloaded, no need to + // check them if we are emitting the type checking code. + if (Proto.find('s') != std::string::npos) + continue; + + SmallVector<StringRef, 16> TypeVec; + ParseTypes(R, Types, TypeVec); + + if (R->getSuperClasses().size() < 2) + PrintFatalError(R->getLoc(), "Builtin has no class kind"); + + int si = -1, qi = -1; + uint64_t mask = 0, qmask = 0; + for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { + // Generate the switch case(s) for this builtin for the type validation. + bool quad = false, poly = false, usgn = false; + (void) ClassifyType(TypeVec[ti], quad, poly, usgn); + + if (quad) { + qi = ti; + qmask |= 1ULL << GetNeonEnum(Proto, TypeVec[ti]); + } else { + si = ti; + mask |= 1ULL << GetNeonEnum(Proto, TypeVec[ti]); + } + } + + // Check if the builtin function has a pointer or const pointer argument. + int PtrArgNum = -1; + bool HasConstPtr = false; + for (unsigned arg = 1, arge = Proto.size(); arg != arge; ++arg) { + char ArgType = Proto[arg]; + if (ArgType == 'c') { + HasConstPtr = true; + PtrArgNum = arg - 1; + break; + } + if (ArgType == 'p') { + PtrArgNum = arg - 1; + break; + } + } + // For sret builtins, adjust the pointer argument index. + if (PtrArgNum >= 0 && (Proto[0] >= '2' && Proto[0] <= '4')) + PtrArgNum += 1; + + // Omit type checking for the pointer arguments of vld1_lane, vld1_dup, + // and vst1_lane intrinsics. Using a pointer to the vector element + // type with one of those operations causes codegen to select an aligned + // load/store instruction. If you want an unaligned operation, + // the pointer argument needs to have less alignment than element type, + // so just accept any pointer type. + if (name == "vld1_lane" || name == "vld1_dup" || name == "vst1_lane") { + PtrArgNum = -1; + HasConstPtr = false; + } + + if (mask) { + OS << "case ARM::BI__builtin_neon_" + << MangleName(name, TypeVec[si], ClassB) + << ": mask = " << "0x" << utohexstr(mask) << "ULL"; + if (PtrArgNum >= 0) + OS << "; PtrArgNum = " << PtrArgNum; + if (HasConstPtr) + OS << "; HasConstPtr = true"; + OS << "; break;\n"; + } + if (qmask) { + OS << "case ARM::BI__builtin_neon_" + << MangleName(name, TypeVec[qi], ClassB) + << ": mask = " << "0x" << utohexstr(qmask) << "ULL"; + if (PtrArgNum >= 0) + OS << "; PtrArgNum = " << PtrArgNum; + if (HasConstPtr) + OS << "; HasConstPtr = true"; + OS << "; break;\n"; + } + } + OS << "#endif\n\n"; + + // Generate the intrinsic range checking code for shift/lane immediates. + OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n"; + for (unsigned i = 0, e = RV.size(); i != e; ++i) { + Record *R = RV[i]; + + OpKind k = OpMap[R->getValueAsDef("Operand")->getName()]; + if (k != OpNone) + continue; + + std::string name = R->getValueAsString("Name"); + std::string Proto = R->getValueAsString("Prototype"); + std::string Types = R->getValueAsString("Types"); + + // Functions with 'a' (the splat code) in the type prototype should not get + // their own builtin as they use the non-splat variant. + if (Proto.find('a') != std::string::npos) + continue; + + // Functions which do not have an immediate do not need to have range + // checking code emitted. + size_t immPos = Proto.find('i'); + if (immPos == std::string::npos) + continue; + + SmallVector<StringRef, 16> TypeVec; + ParseTypes(R, Types, TypeVec); + + if (R->getSuperClasses().size() < 2) + PrintFatalError(R->getLoc(), "Builtin has no class kind"); + + ClassKind ck = ClassMap[R->getSuperClasses()[1]]; + + for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { + std::string namestr, shiftstr, rangestr; + + if (R->getValueAsBit("isVCVT_N")) { + // VCVT between floating- and fixed-point values takes an immediate + // in the range 1 to 32. + ck = ClassB; + rangestr = "l = 1; u = 31"; // upper bound = l + u + } else if (Proto.find('s') == std::string::npos) { + // Builtins which are overloaded by type will need to have their upper + // bound computed at Sema time based on the type constant. + ck = ClassB; + if (R->getValueAsBit("isShift")) { + shiftstr = ", true"; + + // Right shifts have an 'r' in the name, left shifts do not. + if (name.find('r') != std::string::npos) + rangestr = "l = 1; "; + } + rangestr += "u = RFT(TV" + shiftstr + ")"; + } else { + // The immediate generally refers to a lane in the preceding argument. + assert(immPos > 0 && "unexpected immediate operand"); + rangestr = "u = " + utostr(RangeFromType(Proto[immPos-1], TypeVec[ti])); + } + // Make sure cases appear only once by uniquing them in a string map. + namestr = MangleName(name, TypeVec[ti], ck); + if (EmittedMap.count(namestr)) + continue; + EmittedMap[namestr] = OpNone; + + // Calculate the index of the immediate that should be range checked. + unsigned immidx = 0; + + // Builtins that return a struct of multiple vectors have an extra + // leading arg for the struct return. + if (Proto[0] >= '2' && Proto[0] <= '4') + ++immidx; + + // Add one to the index for each argument until we reach the immediate + // to be checked. Structs of vectors are passed as multiple arguments. + for (unsigned ii = 1, ie = Proto.size(); ii != ie; ++ii) { + switch (Proto[ii]) { + default: immidx += 1; break; + case '2': immidx += 2; break; + case '3': immidx += 3; break; + case '4': immidx += 4; break; + case 'i': ie = ii + 1; break; + } + } + OS << "case ARM::BI__builtin_neon_" << MangleName(name, TypeVec[ti], ck) + << ": i = " << immidx << "; " << rangestr << "; break;\n"; + } + } + OS << "#endif\n\n"; +} + +/// GenTest - Write out a test for the intrinsic specified by the name and +/// type strings, including the embedded patterns for FileCheck to match. +static std::string GenTest(const std::string &name, + const std::string &proto, + StringRef outTypeStr, StringRef inTypeStr, + bool isShift) { + assert(!proto.empty() && ""); + std::string s; + + // Function name with type suffix + std::string mangledName = MangleName(name, outTypeStr, ClassS); + if (outTypeStr != inTypeStr) { + // If the input type is different (e.g., for vreinterpret), append a suffix + // for the input type. String off a "Q" (quad) prefix so that MangleName + // does not insert another "q" in the name. + unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0); + StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff); + mangledName = MangleName(mangledName, inTypeNoQuad, ClassS); + } + + // Emit the FileCheck patterns. + s += "// CHECK: test_" + mangledName + "\n"; + // s += "// CHECK: \n"; // FIXME: + expected instruction opcode. + + // Emit the start of the test function. + s += TypeString(proto[0], outTypeStr) + " test_" + mangledName + "("; + char arg = 'a'; + std::string comma; + for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { + // Do not create arguments for values that must be immediate constants. + if (proto[i] == 'i') + continue; + s += comma + TypeString(proto[i], inTypeStr) + " "; + s.push_back(arg); + comma = ", "; + } + s += ") {\n "; + + if (proto[0] != 'v') + s += "return "; + s += mangledName + "("; + arg = 'a'; + for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { + if (proto[i] == 'i') { + // For immediate operands, test the maximum value. + if (isShift) + s += "1"; // FIXME + else + // The immediate generally refers to a lane in the preceding argument. + s += utostr(RangeFromType(proto[i-1], inTypeStr)); + } else { + s.push_back(arg); + } + if ((i + 1) < e) + s += ", "; + } + s += ");\n}\n\n"; + return s; +} + +/// runTests - Write out a complete set of tests for all of the Neon +/// intrinsics. +void NeonEmitter::runTests(raw_ostream &OS) { + OS << + "// RUN: %clang_cc1 -triple thumbv7-apple-darwin \\\n" + "// RUN: -target-cpu cortex-a9 -ffreestanding -S -o - %s | FileCheck %s\n" + "\n" + "#include <arm_neon.h>\n" + "\n"; + + std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst"); + for (unsigned i = 0, e = RV.size(); i != e; ++i) { + Record *R = RV[i]; + std::string name = R->getValueAsString("Name"); + std::string Proto = R->getValueAsString("Prototype"); + std::string Types = R->getValueAsString("Types"); + bool isShift = R->getValueAsBit("isShift"); + + SmallVector<StringRef, 16> TypeVec; + ParseTypes(R, Types, TypeVec); + + OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()]; + if (kind == OpUnavailable) + continue; + for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { + if (kind == OpReinterpret) { + bool outQuad = false; + bool dummy = false; + (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy); + for (unsigned srcti = 0, srcte = TypeVec.size(); + srcti != srcte; ++srcti) { + bool inQuad = false; + (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy); + if (srcti == ti || inQuad != outQuad) + continue; + OS << GenTest(name, Proto, TypeVec[ti], TypeVec[srcti], isShift); + } + } else { + OS << GenTest(name, Proto, TypeVec[ti], TypeVec[ti], isShift); + } + } + OS << "\n"; + } +} + +namespace clang { +void EmitNeon(RecordKeeper &Records, raw_ostream &OS) { + NeonEmitter(Records).run(OS); +} +void EmitNeonSema(RecordKeeper &Records, raw_ostream &OS) { + NeonEmitter(Records).runHeader(OS); +} +void EmitNeonTest(RecordKeeper &Records, raw_ostream &OS) { + NeonEmitter(Records).runTests(OS); +} +} // End namespace clang diff --git a/contrib/llvm/tools/clang/utils/TableGen/OptParserEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/OptParserEmitter.cpp new file mode 100644 index 0000000..0553b1f --- /dev/null +++ b/contrib/llvm/tools/clang/utils/TableGen/OptParserEmitter.cpp @@ -0,0 +1,275 @@ +//===- 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 "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" +#include <map> + +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 = *(const Record*const*) Av; + const Record *B = *(const Record*const*) 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; + + if (!ASent) { + std::vector<std::string> APrefixes = A->getValueAsListOfStrings("Prefixes"); + std::vector<std::string> BPrefixes = B->getValueAsListOfStrings("Prefixes"); + + for (std::vector<std::string>::const_iterator APre = APrefixes.begin(), + AEPre = APrefixes.end(), + BPre = BPrefixes.begin(), + BEPre = BPrefixes.end(); + APre != AEPre && + BPre != BEPre; + ++APre, ++BPre) { + if (int Cmp = StrCmpOptionName(APre->c_str(), BPre->c_str())) + return Cmp; + } + } + + // Then by the kind precedence; + int APrec = A->getValueAsDef("Kind")->getValueAsInt("Precedence"); + int BPrec = B->getValueAsDef("Kind")->getValueAsInt("Precedence"); + if (APrec == BPrec && + A->getValueAsListOfStrings("Prefixes") == + B->getValueAsListOfStrings("Prefixes")) { + PrintError(A->getLoc(), Twine("Option is equivilent to")); + PrintError(B->getLoc(), Twine("Other defined here")); + PrintFatalError("Equivalent Options found."); + } + return APrec < BPrec ? -1 : 1; +} + +static const std::string getOptionName(const Record &R) { + // Use the record name unless EnumName is defined. + if (isa<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; +} + +/// 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. +namespace clang { +void EmitOptParser(RecordKeeper &Records, raw_ostream &OS, bool GenDefs) { + // 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) { + // Generate prefix groups. + typedef SmallVector<SmallString<2>, 2> PrefixKeyT; + typedef std::map<PrefixKeyT, std::string> PrefixesT; + PrefixesT Prefixes; + Prefixes.insert(std::make_pair(PrefixKeyT(), "prefix_0")); + unsigned CurPrefix = 0; + for (unsigned i = 0, e = Opts.size(); i != e; ++i) { + const Record &R = *Opts[i]; + std::vector<std::string> prf = R.getValueAsListOfStrings("Prefixes"); + PrefixKeyT prfkey(prf.begin(), prf.end()); + unsigned NewPrefix = CurPrefix + 1; + if (Prefixes.insert(std::make_pair(prfkey, (Twine("prefix_") + + Twine(NewPrefix)).str())).second) + CurPrefix = NewPrefix; + } + + OS << "#ifndef PREFIX\n"; + OS << "#error \"Define PREFIX prior to including this file!\"\n"; + OS << "#endif\n\n"; + + // Dump prefixes. + OS << "/////////\n"; + OS << "// Prefixes\n\n"; + OS << "#define COMMA ,\n"; + for (PrefixesT::const_iterator I = Prefixes.begin(), E = Prefixes.end(); + I != E; ++I) { + OS << "PREFIX("; + + // Prefix name. + OS << I->second; + + // Prefix values. + OS << ", {"; + for (PrefixKeyT::const_iterator PI = I->first.begin(), + PE = I->first.end(); PI != PE; ++PI) { + OS << "\"" << *PI << "\" COMMA "; + } + OS << "0})\n"; + } + OS << "#undef COMMA\n"; + OS << "\n"; + + 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 prefix; + OS << "0"; + + // 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 = dyn_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 (!isa<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 prefix; + std::vector<std::string> prf = R.getValueAsListOfStrings("Prefixes"); + OS << Prefixes[PrefixKeyT(prf.begin(), prf.end())] << ", "; + + // 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 = dyn_cast<DefInit>(R.getValueInit("Group"))) + OS << getOptionName(*DI->getDef()); + else + OS << "INVALID"; + + // The option alias (if any). + OS << ", "; + if (const DefInit *DI = dyn_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 << cast<DefInit>(LI->getElement(i))->getDef()->getName(); + } + } + + // The option parameter field. + OS << ", " << R.getValueAsInt("NumArgs"); + + // The option help text. + if (!isa<UnsetInit>(R.getValueInit("HelpText"))) { + OS << ",\n"; + OS << " "; + write_cstring(OS, R.getValueAsString("HelpText")); + } else + OS << ", 0"; + + // The option meta-variable name. + OS << ", "; + if (!isa<UnsetInit>(R.getValueInit("MetaVarName"))) + write_cstring(OS, R.getValueAsString("MetaVarName")); + else + OS << "0"; + + OS << ")\n"; + } + } +} +} // end namespace clang diff --git a/contrib/llvm/tools/clang/utils/TableGen/TableGen.cpp b/contrib/llvm/tools/clang/utils/TableGen/TableGen.cpp new file mode 100644 index 0000000..3df8940 --- /dev/null +++ b/contrib/llvm/tools/clang/utils/TableGen/TableGen.cpp @@ -0,0 +1,243 @@ +//===- 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 "TableGenBackends.h" // Declares all backends. +#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" + +using namespace llvm; +using namespace clang; + +enum ActionType { + GenClangAttrClasses, + GenClangAttrImpl, + GenClangAttrList, + GenClangAttrPCHRead, + GenClangAttrPCHWrite, + GenClangAttrSpellingList, + GenClangAttrSpellingListIndex, + GenClangAttrLateParsedList, + GenClangAttrTemplateInstantiate, + GenClangAttrParsedAttrList, + GenClangAttrParsedAttrKinds, + GenClangAttrDump, + GenClangDiagsDefs, + GenClangDiagGroups, + GenClangDiagsIndexName, + GenClangCommentNodes, + GenClangDeclNodes, + GenClangStmtNodes, + GenClangSACheckers, + GenClangCommentHTMLTags, + GenClangCommentHTMLTagsProperties, + GenClangCommentHTMLNamedCharacterReferences, + GenClangCommentCommandInfo, + GenClangCommentCommandList, + 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(GenClangAttrSpellingListIndex, + "gen-clang-attr-spelling-index", + "Generate a clang attribute spelling index"), + clEnumValN(GenClangAttrLateParsedList, + "gen-clang-attr-late-parsed-list", + "Generate a clang attribute LateParsed list"), + clEnumValN(GenClangAttrTemplateInstantiate, + "gen-clang-attr-template-instantiate", + "Generate a clang template instantiate code"), + clEnumValN(GenClangAttrParsedAttrList, + "gen-clang-attr-parsed-attr-list", + "Generate a clang parsed attribute list"), + clEnumValN(GenClangAttrParsedAttrKinds, + "gen-clang-attr-parsed-attr-kinds", + "Generate a clang parsed attribute kinds"), + clEnumValN(GenClangAttrDump, "gen-clang-attr-dump", + "Generate clang attribute dumper"), + 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(GenClangCommentNodes, "gen-clang-comment-nodes", + "Generate Clang AST comment nodes"), + 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(GenClangCommentHTMLTags, + "gen-clang-comment-html-tags", + "Generate efficient matchers for HTML tag " + "names that are used in documentation comments"), + clEnumValN(GenClangCommentHTMLTagsProperties, + "gen-clang-comment-html-tags-properties", + "Generate efficient matchers for HTML tag " + "properties"), + clEnumValN(GenClangCommentHTMLNamedCharacterReferences, + "gen-clang-comment-html-named-character-references", + "Generate function to translate named character " + "references to UTF-8 sequences"), + clEnumValN(GenClangCommentCommandInfo, + "gen-clang-comment-command-info", + "Generate command properties for commands that " + "are used in documentation comments"), + clEnumValN(GenClangCommentCommandList, + "gen-clang-comment-command-list", + "Generate list of commands that are used in " + "documentation comments"), + 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); + +bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) { + switch (Action) { + case GenClangAttrClasses: + EmitClangAttrClass(Records, OS); + break; + case GenClangAttrImpl: + EmitClangAttrImpl(Records, OS); + break; + case GenClangAttrList: + EmitClangAttrList(Records, OS); + break; + case GenClangAttrPCHRead: + EmitClangAttrPCHRead(Records, OS); + break; + case GenClangAttrPCHWrite: + EmitClangAttrPCHWrite(Records, OS); + break; + case GenClangAttrSpellingList: + EmitClangAttrSpellingList(Records, OS); + break; + case GenClangAttrSpellingListIndex: + EmitClangAttrSpellingListIndex(Records, OS); + break; + case GenClangAttrLateParsedList: + EmitClangAttrLateParsedList(Records, OS); + break; + case GenClangAttrTemplateInstantiate: + EmitClangAttrTemplateInstantiate(Records, OS); + break; + case GenClangAttrParsedAttrList: + EmitClangAttrParsedAttrList(Records, OS); + break; + case GenClangAttrParsedAttrKinds: + EmitClangAttrParsedAttrKinds(Records, OS); + break; + case GenClangAttrDump: + EmitClangAttrDump(Records, OS); + break; + case GenClangDiagsDefs: + EmitClangDiagsDefs(Records, OS, ClangComponent); + break; + case GenClangDiagGroups: + EmitClangDiagGroups(Records, OS); + break; + case GenClangDiagsIndexName: + EmitClangDiagsIndexName(Records, OS); + break; + case GenClangCommentNodes: + EmitClangASTNodes(Records, OS, "Comment", ""); + break; + case GenClangDeclNodes: + EmitClangASTNodes(Records, OS, "Decl", "Decl"); + EmitClangDeclContext(Records, OS); + break; + case GenClangStmtNodes: + EmitClangASTNodes(Records, OS, "Stmt", ""); + break; + case GenClangSACheckers: + EmitClangSACheckers(Records, OS); + break; + case GenClangCommentHTMLTags: + EmitClangCommentHTMLTags(Records, OS); + break; + case GenClangCommentHTMLTagsProperties: + EmitClangCommentHTMLTagsProperties(Records, OS); + break; + case GenClangCommentHTMLNamedCharacterReferences: + EmitClangCommentHTMLNamedCharacterReferences(Records, OS); + break; + case GenClangCommentCommandInfo: + EmitClangCommentCommandInfo(Records, OS); + break; + case GenClangCommentCommandList: + EmitClangCommentCommandList(Records, OS); + break; + case GenOptParserDefs: + EmitOptParser(Records, OS, true); + break; + case GenOptParserImpl: + EmitOptParser(Records, OS, false); + break; + case GenArmNeon: + EmitNeon(Records, OS); + break; + case GenArmNeonSema: + EmitNeonSema(Records, OS); + break; + case GenArmNeonTest: + EmitNeonTest(Records, OS); + break; + } + + return false; +} +} + +int main(int argc, char **argv) { + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + cl::ParseCommandLineOptions(argc, argv); + + return TableGenMain(argv[0], &ClangTableGenMain); +} diff --git a/contrib/llvm/tools/clang/utils/TableGen/TableGenBackends.h b/contrib/llvm/tools/clang/utils/TableGen/TableGenBackends.h new file mode 100644 index 0000000..03708b6 --- /dev/null +++ b/contrib/llvm/tools/clang/utils/TableGen/TableGenBackends.h @@ -0,0 +1,65 @@ +//===- TableGenBackends.h - Declarations for Clang TableGen Backends ------===// +// +// 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 declarations for all of the Clang TableGen +// backends. A "TableGen backend" is just a function. See +// "$LLVM_ROOT/utils/TableGen/TableGenBackends.h" for more info. +// +//===----------------------------------------------------------------------===// + +#include <string> + +namespace llvm { + class raw_ostream; + class RecordKeeper; +} + +using llvm::raw_ostream; +using llvm::RecordKeeper; + +namespace clang { + +void EmitClangDeclContext(RecordKeeper &RK, raw_ostream &OS); +void EmitClangASTNodes(RecordKeeper &RK, raw_ostream &OS, + const std::string &N, const std::string &S); + +void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS); +void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS); +void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS); +void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS); +void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS); +void EmitClangAttrSpellingList(RecordKeeper &Records, raw_ostream &OS); +void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS); +void EmitClangAttrLateParsedList(RecordKeeper &Records, raw_ostream &OS); +void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS); +void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS); +void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS); +void EmitClangAttrDump(RecordKeeper &Records, raw_ostream &OS); + +void EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS, + const std::string &Component); +void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS); +void EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS); + +void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS); + +void EmitClangCommentHTMLTags(RecordKeeper &Records, raw_ostream &OS); +void EmitClangCommentHTMLTagsProperties(RecordKeeper &Records, raw_ostream &OS); +void EmitClangCommentHTMLNamedCharacterReferences(RecordKeeper &Records, raw_ostream &OS); + +void EmitClangCommentCommandInfo(RecordKeeper &Records, raw_ostream &OS); +void EmitClangCommentCommandList(RecordKeeper &Records, raw_ostream &OS); + +void EmitNeon(RecordKeeper &Records, raw_ostream &OS); +void EmitNeonSema(RecordKeeper &Records, raw_ostream &OS); +void EmitNeonTest(RecordKeeper &Records, raw_ostream &OS); + +void EmitOptParser(RecordKeeper &Records, raw_ostream &OS, bool GenDefs); + +} // end namespace clang |