diff options
| author | Carlo Zancanaro <carlo@pc-4w14-0.cs.usyd.edu.au> | 2012-10-15 17:10:06 +1100 | 
|---|---|---|
| committer | Carlo Zancanaro <carlo@pc-4w14-0.cs.usyd.edu.au> | 2012-10-15 17:10:06 +1100 | 
| commit | be1de4be954c80875ad4108e0a33e8e131b2f2c0 (patch) | |
| tree | 1fbbecf276bf7c7bdcbb4dd446099d6d90eaa516 /clang/utils/TableGen | |
| parent | c4626a62754862d20b41e8a46a3574264ea80e6d (diff) | |
| parent | f1bd2e48c5324d3f7cda4090c87f8a5b6f463ce2 (diff) | |
Merge branch 'master' of ssh://bitbucket.org/czan/honours
Diffstat (limited to 'clang/utils/TableGen')
| -rw-r--r-- | clang/utils/TableGen/CMakeLists.txt | 13 | ||||
| -rw-r--r-- | clang/utils/TableGen/ClangASTNodesEmitter.cpp | 168 | ||||
| -rw-r--r-- | clang/utils/TableGen/ClangASTNodesEmitter.h | 84 | ||||
| -rw-r--r-- | clang/utils/TableGen/ClangAttrEmitter.cpp | 1092 | ||||
| -rw-r--r-- | clang/utils/TableGen/ClangAttrEmitter.h | 153 | ||||
| -rw-r--r-- | clang/utils/TableGen/ClangDiagnosticsEmitter.cpp | 385 | ||||
| -rw-r--r-- | clang/utils/TableGen/ClangDiagnosticsEmitter.h | 54 | ||||
| -rw-r--r-- | clang/utils/TableGen/ClangSACheckersEmitter.cpp | 319 | ||||
| -rw-r--r-- | clang/utils/TableGen/ClangSACheckersEmitter.h | 31 | ||||
| -rw-r--r-- | clang/utils/TableGen/Makefile | 19 | ||||
| -rw-r--r-- | clang/utils/TableGen/NeonEmitter.cpp | 1574 | ||||
| -rw-r--r-- | clang/utils/TableGen/NeonEmitter.h | 210 | ||||
| -rw-r--r-- | clang/utils/TableGen/OptParserEmitter.cpp | 194 | ||||
| -rw-r--r-- | clang/utils/TableGen/OptParserEmitter.h | 34 | ||||
| -rw-r--r-- | clang/utils/TableGen/TableGen.cpp | 194 | 
15 files changed, 4524 insertions, 0 deletions
| diff --git a/clang/utils/TableGen/CMakeLists.txt b/clang/utils/TableGen/CMakeLists.txt new file mode 100644 index 0000000..0d87921 --- /dev/null +++ b/clang/utils/TableGen/CMakeLists.txt @@ -0,0 +1,13 @@ +set(LLVM_REQUIRES_EH 1) +set(LLVM_REQUIRES_RTTI 1) +set(LLVM_LINK_COMPONENTS Support) + +add_tablegen(clang-tblgen CLANG +  ClangASTNodesEmitter.cpp +  ClangAttrEmitter.cpp +  ClangDiagnosticsEmitter.cpp +  ClangSACheckersEmitter.cpp +  NeonEmitter.cpp +  OptParserEmitter.cpp +  TableGen.cpp +  ) diff --git a/clang/utils/TableGen/ClangASTNodesEmitter.cpp b/clang/utils/TableGen/ClangASTNodesEmitter.cpp new file mode 100644 index 0000000..d9d5a3c --- /dev/null +++ b/clang/utils/TableGen/ClangASTNodesEmitter.cpp @@ -0,0 +1,168 @@ +//=== ClangASTNodesEmitter.cpp - Generate Clang AST node tables -*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// These tablegen backends emit Clang AST node tables +// +//===----------------------------------------------------------------------===// + +#include "ClangASTNodesEmitter.h" +#include <set> +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Statement Node Tables (.inc file) generation. +//===----------------------------------------------------------------------===// + +// Returns the first and last non-abstract subrecords +// Called recursively to ensure that nodes remain contiguous +std::pair<Record *, Record *> ClangASTNodesEmitter::EmitNode( +                                                           const ChildMap &Tree, +                                                           raw_ostream &OS, +                                                           Record *Base) { +  std::string BaseName = macroName(Base->getName()); + +  ChildIterator i = Tree.lower_bound(Base), e = Tree.upper_bound(Base); + +  Record *First = 0, *Last = 0; +  // This might be the pseudo-node for Stmt; don't assume it has an Abstract +  // bit +  if (Base->getValue("Abstract") && !Base->getValueAsBit("Abstract")) +    First = Last = Base; + +  for (; i != e; ++i) { +    Record *R = i->second; +    bool Abstract = R->getValueAsBit("Abstract"); +    std::string NodeName = macroName(R->getName()); + +    OS << "#ifndef " << NodeName << "\n"; +    OS << "#  define " << NodeName << "(Type, Base) " +        << BaseName << "(Type, Base)\n"; +    OS << "#endif\n"; + +    if (Abstract) +      OS << "ABSTRACT_" << macroName(Root.getName()) << "(" << NodeName << "(" +          << R->getName() << ", " << baseName(*Base) << "))\n"; +    else +      OS << NodeName << "(" << R->getName() << ", " +          << baseName(*Base) << ")\n"; + +    if (Tree.find(R) != Tree.end()) { +      const std::pair<Record *, Record *> &Result +        = EmitNode(Tree, OS, R); +      if (!First && Result.first) +        First = Result.first; +      if (Result.second) +        Last = Result.second; +    } else { +      if (!Abstract) { +        Last = R; + +        if (!First) +          First = R; +      } +    } + +    OS << "#undef " << NodeName << "\n\n"; +  } + +  if (First) { +    assert (Last && "Got a first node but not a last node for a range!"); +    if (Base == &Root) +      OS << "LAST_" << macroName(Root.getName()) << "_RANGE("; +    else +      OS << macroName(Root.getName()) << "_RANGE("; +    OS << Base->getName() << ", " << First->getName() << ", " +       << Last->getName() << ")\n\n"; +  } + +  return std::make_pair(First, Last); +} + +void ClangASTNodesEmitter::run(raw_ostream &OS) { +  // Write the preamble +  OS << "#ifndef ABSTRACT_" << macroName(Root.getName()) << "\n"; +  OS << "#  define ABSTRACT_" << macroName(Root.getName()) << "(Type) Type\n"; +  OS << "#endif\n"; + +  OS << "#ifndef " << macroName(Root.getName()) << "_RANGE\n"; +  OS << "#  define " +     << macroName(Root.getName()) << "_RANGE(Base, First, Last)\n"; +  OS << "#endif\n\n"; + +  OS << "#ifndef LAST_" << macroName(Root.getName()) << "_RANGE\n"; +  OS << "#  define LAST_"  +     << macroName(Root.getName()) << "_RANGE(Base, First, Last) "  +     << macroName(Root.getName()) << "_RANGE(Base, First, Last)\n"; +  OS << "#endif\n\n"; +  +  // Emit statements +  const std::vector<Record*> Stmts +    = Records.getAllDerivedDefinitions(Root.getName()); + +  ChildMap Tree; + +  for (unsigned i = 0, e = Stmts.size(); i != e; ++i) { +    Record *R = Stmts[i]; + +    if (R->getValue("Base")) +      Tree.insert(std::make_pair(R->getValueAsDef("Base"), R)); +    else +      Tree.insert(std::make_pair(&Root, R)); +  } + +  EmitNode(Tree, OS, &Root); + +  OS << "#undef " << macroName(Root.getName()) << "\n"; +  OS << "#undef " << macroName(Root.getName()) << "_RANGE\n"; +  OS << "#undef LAST_" << macroName(Root.getName()) << "_RANGE\n"; +  OS << "#undef ABSTRACT_" << macroName(Root.getName()) << "\n"; +} + +void ClangDeclContextEmitter::run(raw_ostream &OS) { +  // FIXME: Find a .td file format to allow for this to be represented better. + +  OS << "#ifndef DECL_CONTEXT\n"; +  OS << "#  define DECL_CONTEXT(DECL)\n"; +  OS << "#endif\n"; +   +  OS << "#ifndef DECL_CONTEXT_BASE\n"; +  OS << "#  define DECL_CONTEXT_BASE(DECL) DECL_CONTEXT(DECL)\n"; +  OS << "#endif\n"; +   +  typedef std::set<Record*> RecordSet; +  typedef std::vector<Record*> RecordVector; +   +  RecordVector DeclContextsVector +    = Records.getAllDerivedDefinitions("DeclContext"); +  RecordVector Decls = Records.getAllDerivedDefinitions("Decl"); +  RecordSet DeclContexts (DeclContextsVector.begin(), DeclContextsVector.end()); +    +  for (RecordVector::iterator i = Decls.begin(), e = Decls.end(); i != e; ++i) { +    Record *R = *i; + +    if (R->getValue("Base")) { +      Record *B = R->getValueAsDef("Base"); +      if (DeclContexts.find(B) != DeclContexts.end()) { +        OS << "DECL_CONTEXT_BASE(" << B->getName() << ")\n"; +        DeclContexts.erase(B); +      } +    } +  } + +  // To keep identical order, RecordVector may be used +  // instead of RecordSet. +  for (RecordVector::iterator +         i = DeclContextsVector.begin(), e = DeclContextsVector.end(); +       i != e; ++i) +    if (DeclContexts.find(*i) != DeclContexts.end()) +      OS << "DECL_CONTEXT(" << (*i)->getName() << ")\n"; + +  OS << "#undef DECL_CONTEXT\n"; +  OS << "#undef DECL_CONTEXT_BASE\n"; +} diff --git a/clang/utils/TableGen/ClangASTNodesEmitter.h b/clang/utils/TableGen/ClangASTNodesEmitter.h new file mode 100644 index 0000000..edd9316 --- /dev/null +++ b/clang/utils/TableGen/ClangASTNodesEmitter.h @@ -0,0 +1,84 @@ +//===- ClangASTNodesEmitter.h - Generate Clang AST node tables -*- C++ -*--===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// These tablegen backends emit Clang AST node tables +// +//===----------------------------------------------------------------------===// + +#ifndef CLANGAST_EMITTER_H +#define CLANGAST_EMITTER_H + +#include "llvm/TableGen/TableGenBackend.h" +#include "llvm/TableGen/Record.h" +#include <string> +#include <cctype> +#include <map> + +namespace llvm { + +/// ClangASTNodesEmitter - The top-level class emits .inc files containing +///  declarations of Clang statements. +/// +class ClangASTNodesEmitter : public TableGenBackend { +  // A map from a node to each of its derived nodes. +  typedef std::multimap<Record*, Record*> ChildMap; +  typedef ChildMap::const_iterator ChildIterator; + +  RecordKeeper &Records; +  Record Root; +  const std::string &BaseSuffix; + +  // Create a macro-ized version of a name +  static std::string macroName(std::string S) { +    for (unsigned i = 0; i < S.size(); ++i) +      S[i] = std::toupper(S[i]); + +    return S; +  } + +  // Return the name to be printed in the base field. Normally this is +  // the record's name plus the base suffix, but if it is the root node and +  // the suffix is non-empty, it's just the suffix. +  std::string baseName(Record &R) { +    if (&R == &Root && !BaseSuffix.empty()) +      return BaseSuffix; +     +    return R.getName() + BaseSuffix; +  } + +  std::pair<Record *, Record *> EmitNode (const ChildMap &Tree, raw_ostream& OS, +                                          Record *Base); +public: +  explicit ClangASTNodesEmitter(RecordKeeper &R, const std::string &N, +                                const std::string &S) +    : Records(R), Root(N, SMLoc(), R), BaseSuffix(S) +    {} + +  // run - Output the .inc file contents +  void run(raw_ostream &OS); +}; + +/// ClangDeclContextEmitter - Emits an addendum to a .inc file to enumerate the +/// clang declaration contexts. +/// +class ClangDeclContextEmitter : public TableGenBackend { +  RecordKeeper &Records; + +public: +  explicit ClangDeclContextEmitter(RecordKeeper &R) +    : Records(R) +  {} + +  // run - Output the .inc file contents +  void run(raw_ostream &OS); +}; + +} // End llvm namespace + +#endif diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp new file mode 100644 index 0000000..7951fc4 --- /dev/null +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -0,0 +1,1092 @@ +//===- ClangAttrEmitter.cpp - Generate Clang attribute handling =-*- C++ -*--=// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// These tablegen backends emit Clang attribute processing code +// +//===----------------------------------------------------------------------===// + +#include "ClangAttrEmitter.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/TableGen/Record.h" +#include <algorithm> +#include <cctype> +#include <set> + +using namespace llvm; + +static const std::vector<StringRef> +getValueAsListOfStrings(Record &R, StringRef FieldName) { +  ListInit *List = R.getValueAsListInit(FieldName); +  assert (List && "Got a null ListInit"); + +  std::vector<StringRef> Strings; +  Strings.reserve(List->getSize()); + +  for (ListInit::const_iterator i = List->begin(), e = List->end(); +       i != e; +       ++i) { +    assert(*i && "Got a null element in a ListInit"); +    if (StringInit *S = dynamic_cast<StringInit *>(*i)) +      Strings.push_back(S->getValue()); +    else +      assert(false && "Got a non-string, non-code element in a ListInit"); +  } + +  return Strings; +} + +static std::string ReadPCHRecord(StringRef type) { +  return StringSwitch<std::string>(type) +    .EndsWith("Decl *", "GetLocalDeclAs<"  +              + std::string(type, 0, type.size()-1) + ">(F, Record[Idx++])") +    .Case("QualType", "getLocalType(F, Record[Idx++])") +    .Case("Expr *", "ReadSubExpr()") +    .Case("IdentifierInfo *", "GetIdentifierInfo(F, Record, Idx)") +    .Case("SourceLocation", "ReadSourceLocation(F, Record, Idx)") +    .Default("Record[Idx++]"); +} + +// Assumes that the way to get the value is SA->getname() +static std::string WritePCHRecord(StringRef type, StringRef name) { +  return StringSwitch<std::string>(type) +    .EndsWith("Decl *", "AddDeclRef(" + std::string(name) + +                        ", Record);\n") +    .Case("QualType", "AddTypeRef(" + std::string(name) + ", Record);\n") +    .Case("Expr *", "AddStmt(" + std::string(name) + ");\n") +    .Case("IdentifierInfo *",  +          "AddIdentifierRef(" + std::string(name) + ", Record);\n") +    .Case("SourceLocation",  +          "AddSourceLocation(" + std::string(name) + ", Record);\n") +    .Default("Record.push_back(" + std::string(name) + ");\n"); +} + +// 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; +  }; + +  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() << "() << \""; +      } +    } +  }; + +  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() << "() << \"\\\""; +    } +  }; + +  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 << "\" << get" << getUpperName() << "(Ctx) << \""; +    } +  }; + +  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 << "  llvm::SmallVector<" << type << ", 4> " << getLowerName() +         << ";\n"; +      OS << "  " << getLowerName() << ".reserve(" << getLowerName() +         << "Size);\n"; +      OS << "  for (unsigned i = " << getLowerName() << "Size; i; --i)\n"; +       +      std::string read = ReadPCHRecord(type); +      OS << "    " << getLowerName() << ".push_back(" << read << ");\n"; +    } +    void writePCHReadArgs(raw_ostream &OS) const { +      OS << getLowerName() << ".data(), " << getLowerName() << "Size"; +    } +    void writePCHWrite(raw_ostream &OS) const{ +      OS << "    Record.push_back(SA->" << getLowerName() << "_size());\n"; +      OS << "    for (" << getAttrName() << "Attr::" << getLowerName() +         << "_iterator i = SA->" << getLowerName() << "_begin(), e = SA->" +         << getLowerName() << "_end(); i != e; ++i)\n"; +      OS << "      " << WritePCHRecord(type, "(*i)"); +    } +    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 << \""; +    } +  }; + +  class EnumArgument : public Argument { +    std::string type; +    std::vector<StringRef> values, enums; +  public: +    EnumArgument(Record &Arg, StringRef Attr) +      : Argument(Arg, Attr), type(Arg.getValueAsString("Type")), +        values(getValueAsListOfStrings(Arg, "Values")), +        enums(getValueAsListOfStrings(Arg, "Enums")) +    {} + +    void writeAccessors(raw_ostream &OS) const { +      OS << "  " << type << " get" << getUpperName() << "() const {\n"; +      OS << "    return " << getLowerName() << ";\n"; +      OS << "  }"; +    } +    void writeCloneArgs(raw_ostream &OS) const { +      OS << getLowerName(); +    } +    void 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 { +      // Calculate the various enum values +      std::vector<StringRef> uniques(enums); +      std::sort(uniques.begin(), uniques.end()); +      uniques.erase(std::unique(uniques.begin(), uniques.end()), +                    uniques.end()); +      // FIXME: Emit a proper error +      assert(!uniques.empty()); + +      std::vector<StringRef>::iterator i = uniques.begin(), +                                       e = uniques.end(); +      // The last one needs to not have a comma. +      --e; + +      OS << "public:\n"; +      OS << "  enum " << type << " {\n"; +      for (; i != e; ++i) +        OS << "    " << *i << ",\n"; +      OS << "    " << *e << "\n"; +      OS << "  };\n"; +      OS << "private:\n"; +      OS << "  " << type << " " << getLowerName() << ";"; +    } +    void writePCHReadDecls(raw_ostream &OS) const { +      OS << "    " << getAttrName() << "Attr::" << type << " " << getLowerName() +         << "(static_cast<" << getAttrName() << "Attr::" << type +         << ">(Record[Idx++]));\n"; +    } +    void writePCHReadArgs(raw_ostream &OS) const { +      OS << getLowerName(); +    } +    void writePCHWrite(raw_ostream &OS) const { +      OS << "Record.push_back(SA->get" << getUpperName() << "());\n"; +    } +    void writeValue(raw_ostream &OS) const { +      OS << "\" << get" << getUpperName() << "() << \""; +    } +  }; + +  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() << "() << \""; +    } +  }; + +  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"; +    } +  }; + +  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"; +    } +  }; +} + +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 << \""; +} + +void ClangAttrClassEmitter::run(raw_ostream &OS) { +  OS << "// This file is generated by TableGen. Do not edit.\n\n"; +  OS << "#ifndef LLVM_CLANG_ATTR_CLASSES_INC\n"; +  OS << "#define LLVM_CLANG_ATTR_CLASSES_INC\n\n"; + +  std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); + +  for (std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(); +       i != e; ++i) { +    Record &R = **i; +    const std::string &SuperName = R.getSuperClasses().back()->getName(); + +    OS << "class " << R.getName() << "Attr : public " << SuperName << " {\n"; + +    std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args"); +    std::vector<Argument*> Args; +    std::vector<Argument*>::iterator ai, ae; +    Args.reserve(ArgRecords.size()); + +    for (std::vector<Record*>::iterator ri = ArgRecords.begin(), +                                        re = ArgRecords.end(); +         ri != re; ++ri) { +      Record &ArgRecord = **ri; +      Argument *Arg = createArgument(ArgRecord, R.getName()); +      assert(Arg); +      Args.push_back(Arg); + +      Arg->writeDeclarations(OS); +      OS << "\n\n"; +    } + +    ae = Args.end(); + +    OS << "\n public:\n"; +    OS << "  " << R.getName() << "Attr(SourceRange R, ASTContext &Ctx\n"; +     +    for (ai = Args.begin(); ai != ae; ++ai) { +      OS << "              , "; +      (*ai)->writeCtorParameters(OS); +      OS << "\n"; +    } +     +    OS << "             )\n"; +    OS << "    : " << SuperName << "(attr::" << R.getName() << ", R)\n"; + +    for (ai = Args.begin(); ai != ae; ++ai) { +      OS << "              , "; +      (*ai)->writeCtorInitializers(OS); +      OS << "\n"; +    } + +    OS << "  {\n"; +   +    for (ai = Args.begin(); ai != ae; ++ai) { +      (*ai)->writeCtorBody(OS); +      OS << "\n"; +    } +    OS << "  }\n\n"; + +    OS << "  virtual " << R.getName() << "Attr *clone (ASTContext &C) const;\n"; +    OS << "  virtual void printPretty(llvm::raw_ostream &OS, ASTContext &Ctx) const;\n"; + +    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"; +    OS << "  static bool classof(const " << R.getName() +       << "Attr *) { return true; }\n"; + +    bool LateParsed = R.getValueAsBit("LateParsed"); +    OS << "  virtual bool isLateParsed() const { return " +       << LateParsed << "; }\n"; + +    OS << "};\n\n"; +  } + +  OS << "#endif\n"; +} + +void ClangAttrImplEmitter::run(raw_ostream &OS) { +  OS << "// This file is generated by TableGen. Do not edit.\n\n"; + +  std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); +  std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(), ri, re; +  std::vector<Argument*>::iterator ai, ae; + +  for (; i != e; ++i) { +    Record &R = **i; +    std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args"); +    std::vector<StringRef> Spellings = getValueAsListOfStrings(R, "Spellings"); +    std::vector<Argument*> Args; +    for (ri = ArgRecords.begin(), re = ArgRecords.end(); ri != re; ++ri) +      Args.push_back(createArgument(**ri, R.getName())); + +    for (ai = Args.begin(), ae = Args.end(); ai != ae; ++ai) +      (*ai)->writeAccessorDefinitions(OS); + +    OS << R.getName() << "Attr *" << R.getName() +       << "Attr::clone(ASTContext &C) const {\n"; +    OS << "  return new (C) " << R.getName() << "Attr(getLocation(), C"; +    for (ai = Args.begin(); ai != ae; ++ai) { +      OS << ", "; +      (*ai)->writeCloneArgs(OS); +    } +    OS << ");\n}\n\n"; + +    OS << "void " << R.getName() << "Attr::printPretty(" +       << "llvm::raw_ostream &OS, ASTContext &Ctx) const {\n"; +    if (Spellings.begin() != Spellings.end()) { +      OS << "  OS << \" __attribute__((" << *Spellings.begin(); +      if (Args.size()) OS << "("; +      if (*Spellings.begin()=="availability") { +        writeAvailabilityValue(OS); +      } else { +        for (ai = Args.begin(); ai != ae; ++ai) { +          if (ai!=Args.begin()) OS <<", "; +          (*ai)->writeValue(OS); +        } +      } +      if (Args.size()) OS << ")"; +      OS << "))\";\n"; +    } +    OS << "}\n\n"; +  } +} + +static void EmitAttrList(raw_ostream &OS, StringRef Class, +                         const std::vector<Record*> &AttrList) { +  std::vector<Record*>::const_iterator i = AttrList.begin(), e = AttrList.end(); + +  if (i != e) { +    // Move the end iterator back to emit the last attribute. +    for(--e; i != e; ++i) +      OS << Class << "(" << (*i)->getName() << ")\n"; +     +    OS << "LAST_" << Class << "(" << (*i)->getName() << ")\n\n"; +  } +} + +void ClangAttrListEmitter::run(raw_ostream &OS) { +  OS << "// This file is generated by TableGen. Do not edit.\n\n"; + +  OS << "#ifndef LAST_ATTR\n"; +  OS << "#define LAST_ATTR(NAME) ATTR(NAME)\n"; +  OS << "#endif\n\n"; + +  OS << "#ifndef INHERITABLE_ATTR\n"; +  OS << "#define INHERITABLE_ATTR(NAME) ATTR(NAME)\n"; +  OS << "#endif\n\n"; + +  OS << "#ifndef LAST_INHERITABLE_ATTR\n"; +  OS << "#define LAST_INHERITABLE_ATTR(NAME) INHERITABLE_ATTR(NAME)\n"; +  OS << "#endif\n\n"; + +  OS << "#ifndef INHERITABLE_PARAM_ATTR\n"; +  OS << "#define INHERITABLE_PARAM_ATTR(NAME) ATTR(NAME)\n"; +  OS << "#endif\n\n"; + +  OS << "#ifndef LAST_INHERITABLE_PARAM_ATTR\n"; +  OS << "#define LAST_INHERITABLE_PARAM_ATTR(NAME)" +        " INHERITABLE_PARAM_ATTR(NAME)\n"; +  OS << "#endif\n\n"; + +  Record *InhClass = Records.getClass("InheritableAttr"); +  Record *InhParamClass = Records.getClass("InheritableParamAttr"); +  std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), +                       NonInhAttrs, InhAttrs, InhParamAttrs; +  for (std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(); +       i != e; ++i) { +    if ((*i)->isSubClassOf(InhParamClass)) +      InhParamAttrs.push_back(*i); +    else if ((*i)->isSubClassOf(InhClass)) +      InhAttrs.push_back(*i); +    else +      NonInhAttrs.push_back(*i); +  } + +  EmitAttrList(OS, "INHERITABLE_PARAM_ATTR", InhParamAttrs); +  EmitAttrList(OS, "INHERITABLE_ATTR", InhAttrs); +  EmitAttrList(OS, "ATTR", NonInhAttrs); + +  OS << "#undef LAST_ATTR\n"; +  OS << "#undef INHERITABLE_ATTR\n"; +  OS << "#undef LAST_INHERITABLE_ATTR\n"; +  OS << "#undef LAST_INHERITABLE_PARAM_ATTR\n"; +  OS << "#undef ATTR\n"; +} + +void ClangAttrPCHReadEmitter::run(raw_ostream &OS) { +  OS << "// This file is generated by TableGen. Do not edit.\n\n"; + +  Record *InhClass = Records.getClass("InheritableAttr"); +  std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), +                       ArgRecords; +  std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(), ai, ae; +  std::vector<Argument*> Args; +  std::vector<Argument*>::iterator ri, re; + +  OS << "  switch (Kind) {\n"; +  OS << "  default:\n"; +  OS << "    assert(0 && \"Unknown attribute!\");\n"; +  OS << "    break;\n"; +  for (; i != e; ++i) { +    Record &R = **i; +    OS << "  case attr::" << R.getName() << ": {\n"; +    if (R.isSubClassOf(InhClass)) +      OS << "    bool isInherited = Record[Idx++];\n"; +    ArgRecords = R.getValueAsListOfDefs("Args"); +    Args.clear(); +    for (ai = ArgRecords.begin(), ae = ArgRecords.end(); ai != ae; ++ai) { +      Argument *A = createArgument(**ai, R.getName()); +      Args.push_back(A); +      A->writePCHReadDecls(OS); +    } +    OS << "    New = new (Context) " << R.getName() << "Attr(Range, Context"; +    for (ri = Args.begin(), re = Args.end(); ri != re; ++ri) { +      OS << ", "; +      (*ri)->writePCHReadArgs(OS); +    } +    OS << ");\n"; +    if (R.isSubClassOf(InhClass)) +      OS << "    cast<InheritableAttr>(New)->setInherited(isInherited);\n"; +    OS << "    break;\n"; +    OS << "  }\n"; +  } +  OS << "  }\n"; +} + +void ClangAttrPCHWriteEmitter::run(raw_ostream &OS) { +  Record *InhClass = Records.getClass("InheritableAttr"); +  std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), Args; +  std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(), ai, ae; + +  OS << "  switch (A->getKind()) {\n"; +  OS << "  default:\n"; +  OS << "    llvm_unreachable(\"Unknown attribute kind!\");\n"; +  OS << "    break;\n"; +  for (; i != e; ++i) { +    Record &R = **i; +    OS << "  case attr::" << R.getName() << ": {\n"; +    Args = R.getValueAsListOfDefs("Args"); +    if (R.isSubClassOf(InhClass) || !Args.empty()) +      OS << "    const " << R.getName() << "Attr *SA = cast<" << R.getName() +         << "Attr>(A);\n"; +    if (R.isSubClassOf(InhClass)) +      OS << "    Record.push_back(SA->isInherited());\n"; +    for (ai = Args.begin(), ae = Args.end(); ai != ae; ++ai) +      createArgument(**ai, R.getName())->writePCHWrite(OS); +    OS << "    break;\n"; +    OS << "  }\n"; +  } +  OS << "  }\n"; +} + +void ClangAttrSpellingListEmitter::run(raw_ostream &OS) { +  OS << "// This file is generated by TableGen. Do not edit.\n\n"; + +  std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); +   +  for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end(); I != E; ++I) { +    Record &Attr = **I; + +    std::vector<StringRef> Spellings = getValueAsListOfStrings(Attr, "Spellings"); + +    for (std::vector<StringRef>::const_iterator I = Spellings.begin(), E = Spellings.end(); I != E; ++I) { +      StringRef Spelling = *I; +      OS << ".Case(\"" << Spelling << "\", true)\n"; +    } +  } + +} + +void ClangAttrLateParsedListEmitter::run(raw_ostream &OS) { +  OS << "// This file is generated by TableGen. Do not edit.\n\n"; + +  std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); + +  for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end(); +       I != E; ++I) { +    Record &Attr = **I; + +    bool LateParsed = Attr.getValueAsBit("LateParsed"); + +    if (LateParsed) { +      std::vector<StringRef> Spellings = +        getValueAsListOfStrings(Attr, "Spellings"); + +      for (std::vector<StringRef>::const_iterator I = Spellings.begin(), +           E = Spellings.end(); I != E; ++I) { +        OS << ".Case(\"" << (*I) << "\", " << LateParsed << ")\n"; +      } +    } +  } +} + + +void ClangAttrTemplateInstantiateEmitter::run(raw_ostream &OS) { +  OS << "// This file is generated by TableGen. Do not edit.\n\n"; + +  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; + +    OS << "    case attr::" << R.getName() << ": {\n"; +    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"; +} + +void ClangAttrParsedAttrListEmitter::run(raw_ostream &OS) { +  OS << "// This file is generated by TableGen. Do not edit.\n\n"; +   +  OS << "#ifndef PARSED_ATTR\n"; +  OS << "#define PARSED_ATTR(NAME) NAME\n"; +  OS << "#endif\n\n"; +   +  std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); +  std::set<StringRef> ProcessedAttrs; + +  for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end(); +       I != E; ++I) { +    Record &Attr = **I; +     +    bool SemaHandler = Attr.getValueAsBit("SemaHandler"); +     +    if (SemaHandler) { +      std::vector<StringRef> Spellings = +        getValueAsListOfStrings(Attr, "Spellings"); +       +      for (std::vector<StringRef>::const_iterator I = Spellings.begin(), +           E = Spellings.end(); I != E; ++I) { +        StringRef AttrName = *I; + +        AttrName = NormalizeAttrName(AttrName); +        // skip if a normalized version has been processed. +        if (ProcessedAttrs.find(AttrName) != ProcessedAttrs.end()) +          continue; +        else +          ProcessedAttrs.insert(AttrName); + +        OS << "PARSED_ATTR(" << AttrName << ")\n"; +      } +    } +  } +} + +void ClangAttrParsedAttrKindsEmitter::run(raw_ostream &OS) { +  OS << "// This file is generated by TableGen. Do not edit.\n\n"; + +  std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); + +  for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end(); +       I != E; ++I) { +    Record &Attr = **I; +     +    bool SemaHandler = Attr.getValueAsBit("SemaHandler"); +     +    if (SemaHandler) { +      std::vector<StringRef> Spellings = +        getValueAsListOfStrings(Attr, "Spellings"); + +      for (std::vector<StringRef>::const_iterator I = Spellings.begin(), +           E = Spellings.end(); I != E; ++I) { +       StringRef AttrName = *I, Spelling = *I; +        +       AttrName = NormalizeAttrName(AttrName); +       Spelling = NormalizeAttrSpelling(Spelling); + +       OS << ".Case(\"" << Spelling << "\", " << "AT_" << AttrName << ")\n"; +      } +    } +  } +} + + diff --git a/clang/utils/TableGen/ClangAttrEmitter.h b/clang/utils/TableGen/ClangAttrEmitter.h new file mode 100644 index 0000000..d119a09 --- /dev/null +++ b/clang/utils/TableGen/ClangAttrEmitter.h @@ -0,0 +1,153 @@ +//===- ClangAttrEmitter.h - Generate Clang attribute handling =-*- C++ -*--===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// These tablegen backends emit Clang attribute processing code +// +//===----------------------------------------------------------------------===// + +#ifndef CLANGATTR_EMITTER_H +#define CLANGATTR_EMITTER_H + +#include "llvm/TableGen/TableGenBackend.h" + +namespace llvm { + +/// ClangAttrClassEmitter - class emits the class defintions for attributes for +///   clang. +class ClangAttrClassEmitter : public TableGenBackend { +  RecordKeeper &Records; +  + public: +  explicit ClangAttrClassEmitter(RecordKeeper &R) +    : Records(R) +    {} + +  void run(raw_ostream &OS); +}; + +/// ClangAttrImplEmitter - class emits the class method defintions for +///   attributes for clang. +class ClangAttrImplEmitter : public TableGenBackend { +  RecordKeeper &Records; +  + public: +  explicit ClangAttrImplEmitter(RecordKeeper &R) +    : Records(R) +    {} + +  void run(raw_ostream &OS); +}; + +/// ClangAttrListEmitter - class emits the enumeration list for attributes for +///   clang. +class ClangAttrListEmitter : public TableGenBackend { +  RecordKeeper &Records; + + public: +  explicit ClangAttrListEmitter(RecordKeeper &R) +    : Records(R) +    {} + +  void run(raw_ostream &OS); +}; + +/// ClangAttrPCHReadEmitter - class emits the code to read an attribute from +///   a clang precompiled header. +class ClangAttrPCHReadEmitter : public TableGenBackend { +  RecordKeeper &Records; + +public: +  explicit ClangAttrPCHReadEmitter(RecordKeeper &R) +    : Records(R) +    {} + +  void run(raw_ostream &OS); +}; + +/// ClangAttrPCHWriteEmitter - class emits the code to read an attribute from +///   a clang precompiled header. +class ClangAttrPCHWriteEmitter : public TableGenBackend { +  RecordKeeper &Records; + +public: +  explicit ClangAttrPCHWriteEmitter(RecordKeeper &R) +    : Records(R) +    {} + +  void run(raw_ostream &OS); +}; + +/// ClangAttrSpellingListEmitter - class emits the list of spellings for attributes for +///   clang. +class ClangAttrSpellingListEmitter : public TableGenBackend { +  RecordKeeper &Records; + + public: +  explicit ClangAttrSpellingListEmitter(RecordKeeper &R) +    : Records(R) +    {} + +  void run(raw_ostream &OS); +}; + +/// ClangAttrLateParsedListEmitter emits the LateParsed property for attributes +/// for clang. +class ClangAttrLateParsedListEmitter : public TableGenBackend { +  RecordKeeper &Records; + + public: +  explicit ClangAttrLateParsedListEmitter(RecordKeeper &R) +    : Records(R) +    {} + +  void run(raw_ostream &OS); +}; + +/// ClangAttrTemplateInstantiateEmitter emits code to instantiate dependent +/// attributes on templates. +class ClangAttrTemplateInstantiateEmitter : public TableGenBackend { +  RecordKeeper &Records; + + public: +  explicit ClangAttrTemplateInstantiateEmitter(RecordKeeper &R) +    : Records(R) +    {} + +  void run(raw_ostream &OS); +}; + +/// ClangAttrParsedAttrListEmitter emits the list of parsed attributes +/// for clang. +class ClangAttrParsedAttrListEmitter : public TableGenBackend { +  RecordKeeper &Records; + +public: +  explicit ClangAttrParsedAttrListEmitter(RecordKeeper &R) +    : Records(R) +    {} + +  void run(raw_ostream &OS); +}; + +/// ClangAttrParsedAttrKindsEmitter emits the kind list of parsed attributes +/// for clang. +class ClangAttrParsedAttrKindsEmitter : public TableGenBackend { +  RecordKeeper &Records; + +public: +  explicit ClangAttrParsedAttrKindsEmitter(RecordKeeper &R) +    : Records(R) +    {} + +  void run(raw_ostream &OS); +}; + +} + +#endif diff --git a/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp b/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp new file mode 100644 index 0000000..8a49619 --- /dev/null +++ b/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp @@ -0,0 +1,385 @@ +//=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- C++ -*- +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// These tablegen backends emit Clang diagnostics tables. +// +//===----------------------------------------------------------------------===// + +#include "ClangDiagnosticsEmitter.h" +#include "llvm/TableGen/Record.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Compiler.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/SmallString.h" +#include <map> +#include <algorithm> +#include <functional> +#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 = dynamic_cast<DefInit*>(R->getValueInit("Group"))) { +    // Check the diagnostic's diag group for a category. +    std::string CatName = getCategoryFromDiagGroup(Group->getDef(), +                                                   DiagGroupParents); +    if (!CatName.empty()) return CatName; +  } +   +  // If the diagnostic itself has a category, get it. +  return R->getValueAsString("CategoryName"); +} + +namespace { +  class DiagCategoryIDMap { +    RecordKeeper &Records; +    StringMap<unsigned> CategoryIDs; +    std::vector<std::string> CategoryStrings; +  public: +    DiagCategoryIDMap(RecordKeeper &records) : Records(records) { +      DiagGroupParentMap ParentInfo(Records); +       +      // The zero'th category is "". +      CategoryStrings.push_back(""); +      CategoryIDs[""] = 0; +       +      std::vector<Record*> Diags = +      Records.getAllDerivedDefinitions("Diagnostic"); +      for (unsigned i = 0, e = Diags.size(); i != e; ++i) { +        std::string Category = getDiagnosticCategory(Diags[i], ParentInfo); +        if (Category.empty()) continue;  // Skip diags with no category. +         +        unsigned &ID = CategoryIDs[Category]; +        if (ID != 0) continue;  // Already seen. +         +        ID = CategoryStrings.size(); +        CategoryStrings.push_back(Category); +      } +    } +     +    unsigned getID(StringRef CategoryString) { +      return CategoryIDs[CategoryString]; +    } +     +    typedef std::vector<std::string>::iterator iterator; +    iterator begin() { return CategoryStrings.begin(); } +    iterator end() { return CategoryStrings.end(); } +  }; + +  struct GroupInfo { +    std::vector<const Record*> DiagsInGroup; +    std::vector<std::string> SubGroups; +    unsigned IDNo; +  }; +} // end anonymous namespace. + +/// \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 = dynamic_cast<DefInit*>(R->getValueInit("Group")); +    if (DI == 0) continue; +    std::string GroupName = DI->getDef()->getValueAsString("GroupName"); +    DiagsInGroup[GroupName].DiagsInGroup.push_back(R); +  } +   +  // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty +  // groups (these are warnings that GCC supports that clang never produces). +  for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) { +    Record *Group = DiagGroups[i]; +    GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")]; +     +    std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups"); +    for (unsigned j = 0, e = SubGroups.size(); j != e; ++j) +      GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName")); +  } +   +  // Assign unique ID numbers to the groups. +  unsigned IDNo = 0; +  for (std::map<std::string, GroupInfo>::iterator +       I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo) +    I->second.IDNo = IDNo; +} + +//===----------------------------------------------------------------------===// +// Warning Tables (.inc file) generation. +//===----------------------------------------------------------------------===// + +void ClangDiagsDefsEmitter::run(raw_ostream &OS) { +  // 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); + +  for (unsigned i = 0, e = Diags.size(); i != e; ++i) { +    const Record &R = *Diags[i]; +    // Filter by component. +    if (!Component.empty() && Component != R.getValueAsString("Component")) +      continue; + +    OS << "DIAG(" << R.getName() << ", "; +    OS << R.getValueAsDef("Class")->getName(); +    OS << ", diag::" << R.getValueAsDef("DefaultMapping")->getName(); +     +    // Description string. +    OS << ", \""; +    OS.write_escaped(R.getValueAsString("Text")) << '"'; +     +    // Warning associated with the diagnostic. This is stored as an index into +    // the alphabetically sorted warning table. +    if (DefInit *DI = dynamic_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 { +      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"; +  } +} + +//===----------------------------------------------------------------------===// +// 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(); +} + +void ClangDiagGroupsEmitter::run(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); +   +  // Walk through the groups emitting an array for each diagnostic of the diags +  // that are mapped to. +  OS << "\n#ifdef GET_DIAG_ARRAYS\n"; +  unsigned MaxLen = 0; +  for (std::map<std::string, GroupInfo>::iterator +       I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { +    MaxLen = std::max(MaxLen, (unsigned)I->first.size()); +     +    std::vector<const Record*> &V = I->second.DiagsInGroup; +    if (!V.empty()) { +      OS << "static const short DiagArray" << I->second.IDNo << "[] = { "; +      for (unsigned i = 0, e = V.size(); i != e; ++i) +        OS << "diag::" << V[i]->getName() << ", "; +      OS << "-1 };\n"; +    } +     +    const std::vector<std::string> &SubGroups = I->second.SubGroups; +    if (!SubGroups.empty()) { +      OS << "static const short DiagSubGroup" << I->second.IDNo << "[] = { "; +      for (unsigned i = 0, e = SubGroups.size(); i != e; ++i) { +        std::map<std::string, GroupInfo>::iterator RI = +          DiagsInGroup.find(SubGroups[i]); +        assert(RI != DiagsInGroup.end() && "Referenced without existing?"); +        OS << RI->second.IDNo << ", "; +      } +      OS << "-1 };\n"; +    } +  } +  OS << "#endif // GET_DIAG_ARRAYS\n\n"; +   +  // Emit the table now. +  OS << "\n#ifdef GET_DIAG_TABLE\n"; +  for (std::map<std::string, GroupInfo>::iterator +       I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { +    // Group option string. +    OS << "  { "; +    OS << I->first.size() << ", "; +    OS << "\""; +    if (I->first.find_first_not_of("abcdefghijklmnopqrstuvwxyz" +                                   "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +                                   "0123456789!@#$%^*-+=:?")!=std::string::npos) +      throw "Invalid character in diagnostic group '" + I->first + "'"; +    OS.write_escaped(I->first) << "\"," +                               << std::string(MaxLen-I->first.size()+1, ' '); +     +    // Diagnostics in the group. +    if (I->second.DiagsInGroup.empty()) +      OS << "0, "; +    else +      OS << "DiagArray" << I->second.IDNo << ", "; +     +    // Subgroups. +    if (I->second.SubGroups.empty()) +      OS << 0; +    else +      OS << "DiagSubGroup" << I->second.IDNo; +    OS << " },\n"; +  } +  OS << "#endif // GET_DIAG_TABLE\n\n"; +   +  // Emit the category table next. +  DiagCategoryIDMap CategoriesByID(Records); +  OS << "\n#ifdef GET_CATEGORY_TABLE\n"; +  for (DiagCategoryIDMap::iterator I = CategoriesByID.begin(), +       E = CategoriesByID.end(); I != E; ++I) +    OS << "CATEGORY(\"" << *I << "\", " << getDiagCategoryEnum(*I) << ")\n"; +  OS << "#endif // GET_CATEGORY_TABLE\n\n"; +} + +//===----------------------------------------------------------------------===// +// Diagnostic name index generation +//===----------------------------------------------------------------------===// + +namespace { +struct RecordIndexElement +{ +  RecordIndexElement() {} +  explicit RecordIndexElement(Record const &R): +    Name(R.getName()) {} +   +  std::string Name; +}; + +struct RecordIndexElementSorter : +  public std::binary_function<RecordIndexElement, RecordIndexElement, bool> { +   +  bool operator()(RecordIndexElement const &Lhs, +                  RecordIndexElement const &Rhs) const { +    return Lhs.Name < Rhs.Name; +  } +   +}; + +} // end anonymous namespace. + +void ClangDiagsIndexNameEmitter::run(raw_ostream &OS) { +  const std::vector<Record*> &Diags = +    Records.getAllDerivedDefinitions("Diagnostic"); +   +  std::vector<RecordIndexElement> Index; +  Index.reserve(Diags.size()); +  for (unsigned i = 0, e = Diags.size(); i != e; ++i) { +    const Record &R = *(Diags[i]);     +    Index.push_back(RecordIndexElement(R)); +  } +   +  std::sort(Index.begin(), Index.end(), RecordIndexElementSorter()); +   +  for (unsigned i = 0, e = Index.size(); i != e; ++i) { +    const RecordIndexElement &R = Index[i]; +     +    OS << "DIAG_NAME_INDEX(" << R.Name << ")\n"; +  } +} diff --git a/clang/utils/TableGen/ClangDiagnosticsEmitter.h b/clang/utils/TableGen/ClangDiagnosticsEmitter.h new file mode 100644 index 0000000..73d3c4d --- /dev/null +++ b/clang/utils/TableGen/ClangDiagnosticsEmitter.h @@ -0,0 +1,54 @@ +//===- ClangDiagnosticsEmitter.h - Generate Clang diagnostics tables -*- C++ -*- +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// These tablegen backends emit Clang diagnostics tables. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANGDIAGS_EMITTER_H +#define CLANGDIAGS_EMITTER_H + +#include "llvm/TableGen/TableGenBackend.h" + +namespace llvm { + +/// ClangDiagsDefsEmitter - The top-level class emits .def files containing +///  declarations of Clang diagnostics. +/// +class ClangDiagsDefsEmitter : public TableGenBackend { +  RecordKeeper &Records; +  const std::string& Component; +public: +  explicit ClangDiagsDefsEmitter(RecordKeeper &R, const std::string& component) +    : Records(R), Component(component) {} + +  // run - Output the .def file contents +  void run(raw_ostream &OS); +}; + +class ClangDiagGroupsEmitter : public TableGenBackend { +  RecordKeeper &Records; +public: +  explicit ClangDiagGroupsEmitter(RecordKeeper &R) : Records(R) {} +     +  void run(raw_ostream &OS); +}; + +class ClangDiagsIndexNameEmitter : public TableGenBackend { +  RecordKeeper &Records; +public: +  explicit ClangDiagsIndexNameEmitter(RecordKeeper &R) : Records(R) {} +   +  void run(raw_ostream &OS); +}; + +   +} // End llvm namespace + +#endif diff --git a/clang/utils/TableGen/ClangSACheckersEmitter.cpp b/clang/utils/TableGen/ClangSACheckersEmitter.cpp new file mode 100644 index 0000000..423b68a --- /dev/null +++ b/clang/utils/TableGen/ClangSACheckersEmitter.cpp @@ -0,0 +1,319 @@ +//=- ClangSACheckersEmitter.cpp - Generate Clang SA checkers tables -*- C++ -*- +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend emits Clang Static Analyzer checkers tables. +// +//===----------------------------------------------------------------------===// + +#include "ClangSACheckersEmitter.h" +#include "llvm/TableGen/Record.h" +#include "llvm/ADT/DenseSet.h" +#include <map> +#include <string> +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Static Analyzer Checkers Tables generation +//===----------------------------------------------------------------------===// + +/// \brief True if it is specified hidden or a parent package is specified +/// as hidden, otherwise false. +static bool isHidden(const Record &R) { +  if (R.getValueAsBit("Hidden")) +    return true; +  // Not declared as hidden, check the parent package if it is hidden. +  if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("ParentPackage"))) +    return isHidden(*DI->getDef()); + +  return false; +} + +static bool isCheckerNamed(const Record *R) { +  return !R->getValueAsString("CheckerName").empty(); +} + +static std::string getPackageFullName(const Record *R); + +static std::string getParentPackageFullName(const Record *R) { +  std::string name; +  if (DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("ParentPackage"))) +    name = getPackageFullName(DI->getDef()); +  return name; +} + +static std::string getPackageFullName(const Record *R) { +  std::string name = getParentPackageFullName(R); +  if (!name.empty()) name += "."; +  return name + R->getValueAsString("PackageName"); +} + +static std::string getCheckerFullName(const Record *R) { +  std::string name = getParentPackageFullName(R); +  if (isCheckerNamed(R)) { +    if (!name.empty()) name += "."; +    name += R->getValueAsString("CheckerName"); +  } +  return name; +} + +static std::string getStringValue(const Record &R, StringRef field) { +  if (StringInit * +        SI = dynamic_cast<StringInit*>(R.getValueInit(field))) +    return SI->getValue(); +  return std::string(); +} + +namespace { +struct GroupInfo { +  llvm::DenseSet<const Record*> Checkers; +  llvm::DenseSet<const Record *> SubGroups; +  bool Hidden; +  unsigned Index; + +  GroupInfo() : Hidden(false) { } +}; +} + +static void addPackageToCheckerGroup(const Record *package, const Record *group, +                  llvm::DenseMap<const Record *, GroupInfo *> &recordGroupMap) { +  llvm::DenseSet<const Record *> &checkers = recordGroupMap[package]->Checkers; +  for (llvm::DenseSet<const Record *>::iterator +         I = checkers.begin(), E = checkers.end(); I != E; ++I) +    recordGroupMap[group]->Checkers.insert(*I); + +  llvm::DenseSet<const Record *> &subGroups = recordGroupMap[package]->SubGroups; +  for (llvm::DenseSet<const Record *>::iterator +         I = subGroups.begin(), E = subGroups.end(); I != E; ++I) +    addPackageToCheckerGroup(*I, group, recordGroupMap); +} + +void ClangSACheckersEmitter::run(raw_ostream &OS) { +  std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker"); +  llvm::DenseMap<const Record *, unsigned> checkerRecIndexMap; +  for (unsigned i = 0, e = checkers.size(); i != e; ++i) +    checkerRecIndexMap[checkers[i]] = i; + +  // Invert the mapping of checkers to package/group into a one to many +  // mapping of packages/groups to checkers. +  std::map<std::string, GroupInfo> groupInfoByName; +  llvm::DenseMap<const Record *, GroupInfo *> recordGroupMap; + +  std::vector<Record*> packages = Records.getAllDerivedDefinitions("Package"); +  for (unsigned i = 0, e = packages.size(); i != e; ++i) { +    Record *R = packages[i]; +    std::string fullName = getPackageFullName(R); +    if (!fullName.empty()) { +      GroupInfo &info = groupInfoByName[fullName]; +      info.Hidden = isHidden(*R); +      recordGroupMap[R] = &info; +    } +  } + +  std::vector<Record*> +      checkerGroups = Records.getAllDerivedDefinitions("CheckerGroup"); +  for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i) { +    Record *R = checkerGroups[i]; +    std::string name = R->getValueAsString("GroupName"); +    if (!name.empty()) { +      GroupInfo &info = groupInfoByName[name]; +      recordGroupMap[R] = &info; +    } +  } + +  for (unsigned i = 0, e = checkers.size(); i != e; ++i) { +    Record *R = checkers[i]; +    Record *package = 0; +    if (DefInit * +          DI = dynamic_cast<DefInit*>(R->getValueInit("ParentPackage"))) +      package = DI->getDef(); +    if (!isCheckerNamed(R) && !package) +      throw "Checker '" + R->getName() + "' is neither named, nor in a package!"; + +    if (isCheckerNamed(R)) { +      // Create a pseudo-group to hold this checker. +      std::string fullName = getCheckerFullName(R); +      GroupInfo &info = groupInfoByName[fullName]; +      info.Hidden = R->getValueAsBit("Hidden"); +      recordGroupMap[R] = &info; +      info.Checkers.insert(R); +    } else { +      recordGroupMap[package]->Checkers.insert(R); +    } + +    Record *currR = isCheckerNamed(R) ? R : package; +    // Insert the checker and its parent packages into the subgroups set of +    // the corresponding parent package. +    while (DefInit *DI +             = dynamic_cast<DefInit*>(currR->getValueInit("ParentPackage"))) { +      Record *parentPackage = DI->getDef(); +      recordGroupMap[parentPackage]->SubGroups.insert(currR); +      currR = parentPackage; +    } +    // Insert the checker into the set of its group. +    if (DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("Group"))) +      recordGroupMap[DI->getDef()]->Checkers.insert(R); +  } + +  // If a package is in group, add all its checkers and its sub-packages +  // checkers into the group. +  for (unsigned i = 0, e = packages.size(); i != e; ++i) +    if (DefInit *DI = dynamic_cast<DefInit*>(packages[i]->getValueInit("Group"))) +      addPackageToCheckerGroup(packages[i], DI->getDef(), recordGroupMap); + +  typedef std::map<std::string, const Record *> SortedRecords; +  typedef llvm::DenseMap<const Record *, unsigned> RecToSortIndex; + +  SortedRecords sortedGroups; +  RecToSortIndex groupToSortIndex; +  OS << "\n#ifdef GET_GROUPS\n"; +  { +    for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i) +      sortedGroups[checkerGroups[i]->getValueAsString("GroupName")] +                   = checkerGroups[i]; + +    unsigned sortIndex = 0; +    for (SortedRecords::iterator +           I = sortedGroups.begin(), E = sortedGroups.end(); I != E; ++I) { +      const Record *R = I->second; +   +      OS << "GROUP(" << "\""; +      OS.write_escaped(R->getValueAsString("GroupName")) << "\""; +      OS << ")\n"; + +      groupToSortIndex[R] = sortIndex++; +    } +  } +  OS << "#endif // GET_GROUPS\n\n"; + +  OS << "\n#ifdef GET_PACKAGES\n"; +  { +    SortedRecords sortedPackages; +    for (unsigned i = 0, e = packages.size(); i != e; ++i) +      sortedPackages[getPackageFullName(packages[i])] = packages[i]; +   +    for (SortedRecords::iterator +           I = sortedPackages.begin(), E = sortedPackages.end(); I != E; ++I) { +      const Record &R = *I->second; +   +      OS << "PACKAGE(" << "\""; +      OS.write_escaped(getPackageFullName(&R)) << "\", "; +      // Group index +      if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group"))) +        OS << groupToSortIndex[DI->getDef()] << ", "; +      else +        OS << "-1, "; +      // Hidden bit +      if (isHidden(R)) +        OS << "true"; +      else +        OS << "false"; +      OS << ")\n"; +    } +  } +  OS << "#endif // GET_PACKAGES\n\n"; +   +  OS << "\n#ifdef GET_CHECKERS\n"; +  for (unsigned i = 0, e = checkers.size(); i != e; ++i) { +    const Record &R = *checkers[i]; + +    OS << "CHECKER(" << "\""; +    std::string name; +    if (isCheckerNamed(&R)) +      name = getCheckerFullName(&R); +    OS.write_escaped(name) << "\", "; +    OS << R.getName() << ", "; +    OS << getStringValue(R, "DescFile") << ", "; +    OS << "\""; +    OS.write_escaped(getStringValue(R, "HelpText")) << "\", "; +    // Group index +    if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group"))) +      OS << groupToSortIndex[DI->getDef()] << ", "; +    else +      OS << "-1, "; +    // Hidden bit +    if (isHidden(R)) +      OS << "true"; +    else +      OS << "false"; +    OS << ")\n"; +  } +  OS << "#endif // GET_CHECKERS\n\n"; + +  unsigned index = 0; +  for (std::map<std::string, GroupInfo>::iterator +         I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) +    I->second.Index = index++; + +  // Walk through the packages/groups/checkers emitting an array for each +  // set of checkers and an array for each set of subpackages. + +  OS << "\n#ifdef GET_MEMBER_ARRAYS\n"; +  unsigned maxLen = 0; +  for (std::map<std::string, GroupInfo>::iterator +         I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) { +    maxLen = std::max(maxLen, (unsigned)I->first.size()); + +    llvm::DenseSet<const Record *> &checkers = I->second.Checkers; +    if (!checkers.empty()) { +      OS << "static const short CheckerArray" << I->second.Index << "[] = { "; +      // Make the output order deterministic. +      std::map<int, const Record *> sorted; +      for (llvm::DenseSet<const Record *>::iterator +             I = checkers.begin(), E = checkers.end(); I != E; ++I) +        sorted[(*I)->getID()] = *I; + +      for (std::map<int, const Record *>::iterator +             I = sorted.begin(), E = sorted.end(); I != E; ++I) +        OS << checkerRecIndexMap[I->second] << ", "; +      OS << "-1 };\n"; +    } +     +    llvm::DenseSet<const Record *> &subGroups = I->second.SubGroups; +    if (!subGroups.empty()) { +      OS << "static const short SubPackageArray" << I->second.Index << "[] = { "; +      // Make the output order deterministic. +      std::map<int, const Record *> sorted; +      for (llvm::DenseSet<const Record *>::iterator +             I = subGroups.begin(), E = subGroups.end(); I != E; ++I) +        sorted[(*I)->getID()] = *I; + +      for (std::map<int, const Record *>::iterator +             I = sorted.begin(), E = sorted.end(); I != E; ++I) { +        OS << recordGroupMap[I->second]->Index << ", "; +      } +      OS << "-1 };\n"; +    } +  } +  OS << "#endif // GET_MEMBER_ARRAYS\n\n"; + +  OS << "\n#ifdef GET_CHECKNAME_TABLE\n"; +  for (std::map<std::string, GroupInfo>::iterator +         I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) { +    // Group option string. +    OS << "  { \""; +    OS.write_escaped(I->first) << "\"," +                               << std::string(maxLen-I->first.size()+1, ' '); +     +    if (I->second.Checkers.empty()) +      OS << "0, "; +    else +      OS << "CheckerArray" << I->second.Index << ", "; +     +    // Subgroups. +    if (I->second.SubGroups.empty()) +      OS << "0, "; +    else +      OS << "SubPackageArray" << I->second.Index << ", "; + +    OS << (I->second.Hidden ? "true" : "false"); + +    OS << " },\n"; +  } +  OS << "#endif // GET_CHECKNAME_TABLE\n\n"; +} diff --git a/clang/utils/TableGen/ClangSACheckersEmitter.h b/clang/utils/TableGen/ClangSACheckersEmitter.h new file mode 100644 index 0000000..5a0e148 --- /dev/null +++ b/clang/utils/TableGen/ClangSACheckersEmitter.h @@ -0,0 +1,31 @@ +//===- ClangSACheckersEmitter.h - Generate Clang SA checkers tables -*- C++ -*- +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend emits Clang Static Analyzer checkers tables. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANGSACHECKERS_EMITTER_H +#define CLANGSACHECKERS_EMITTER_H + +#include "llvm/TableGen/TableGenBackend.h" + +namespace llvm { + +class ClangSACheckersEmitter : public TableGenBackend { +    RecordKeeper &Records; +public: +  explicit ClangSACheckersEmitter(RecordKeeper &R) : Records(R) {} + +  void run(raw_ostream &OS); +}; + +} // End llvm namespace + +#endif diff --git a/clang/utils/TableGen/Makefile b/clang/utils/TableGen/Makefile new file mode 100644 index 0000000..9790efc --- /dev/null +++ b/clang/utils/TableGen/Makefile @@ -0,0 +1,19 @@ +##===- utils/TableGen/Makefile -----------------------------*- Makefile -*-===## +# +#                     The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +TOOLNAME = clang-tblgen +USEDLIBS = LLVMTableGen.a LLVMSupport.a +REQUIRES_EH := 1 +REQUIRES_RTTI := 1 + +# This tool has no plugins, optimize startup time. +TOOL_NO_EXPORTS = 1 + +include $(LEVEL)/Makefile.common diff --git a/clang/utils/TableGen/NeonEmitter.cpp b/clang/utils/TableGen/NeonEmitter.cpp new file mode 100644 index 0000000..e6f2e53 --- /dev/null +++ b/clang/utils/TableGen/NeonEmitter.cpp @@ -0,0 +1,1574 @@ +//===- 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 "NeonEmitter.h" +#include "llvm/TableGen/Error.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/ErrorHandling.h" +#include <string> + +using namespace llvm; + +/// 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: +        throw TGError(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: throw "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: throw "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: +      throw "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: +    throw "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: +    throw "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: +    throw "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: +      throw "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); +  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 { +    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) +    throw TGError(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: +      throw "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 immedate 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) +      throw TGError(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) +      throw TGError(R->getLoc(), "Builtin has no class kind"); + +    int si = -1, qi = -1; +    unsigned 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 |= 1 << GetNeonEnum(Proto, TypeVec[ti]); +      } else { +        si = ti; +        mask |= 1 << 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); +      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); +      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) +      throw TGError(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()]; +    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"; +  } +} + diff --git a/clang/utils/TableGen/NeonEmitter.h b/clang/utils/TableGen/NeonEmitter.h new file mode 100644 index 0000000..dec7451 --- /dev/null +++ b/clang/utils/TableGen/NeonEmitter.h @@ -0,0 +1,210 @@ +//===- NeonEmitter.h - Generate arm_neon.h for use with clang ---*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend is responsible for emitting arm_neon.h, which includes +// a declaration and definition of each function specified by the ARM NEON +// compiler interface.  See ARM document DUI0348B. +// +//===----------------------------------------------------------------------===// + +#ifndef NEON_EMITTER_H +#define NEON_EMITTER_H + +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringMap.h" + +enum OpKind { +  OpNone, +  OpAdd, +  OpAddl, +  OpAddw, +  OpSub, +  OpSubl, +  OpSubw, +  OpMul, +  OpMla, +  OpMlal, +  OpMls, +  OpMlsl, +  OpMulN, +  OpMlaN, +  OpMlsN, +  OpMlalN, +  OpMlslN, +  OpMulLane, +  OpMullLane, +  OpMlaLane, +  OpMlsLane, +  OpMlalLane, +  OpMlslLane, +  OpQDMullLane, +  OpQDMlalLane, +  OpQDMlslLane, +  OpQDMulhLane, +  OpQRDMulhLane, +  OpEq, +  OpGe, +  OpLe, +  OpGt, +  OpLt, +  OpNeg, +  OpNot, +  OpAnd, +  OpOr, +  OpXor, +  OpAndNot, +  OpOrNot, +  OpCast, +  OpConcat, +  OpDup, +  OpDupLane, +  OpHi, +  OpLo, +  OpSelect, +  OpRev16, +  OpRev32, +  OpRev64, +  OpReinterpret, +  OpAbdl, +  OpAba, +  OpAbal +}; + +enum ClassKind { +  ClassNone, +  ClassI,           // generic integer instruction, e.g., "i8" suffix +  ClassS,           // signed/unsigned/poly, e.g., "s8", "u8" or "p8" suffix +  ClassW,           // width-specific instruction, e.g., "8" suffix +  ClassB            // bitcast arguments with enum argument to specify type +}; + +/// 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. +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; } +}; + +namespace llvm { + +  class NeonEmitter : public TableGenBackend { +    RecordKeeper &Records; +    StringMap<OpKind> OpMap; +    DenseMap<Record*, ClassKind> ClassMap; + +  public: +    NeonEmitter(RecordKeeper &R) : Records(R) { +      OpMap["OP_NONE"]  = OpNone; +      OpMap["OP_ADD"]   = OpAdd; +      OpMap["OP_ADDL"]  = OpAddl; +      OpMap["OP_ADDW"]  = OpAddw; +      OpMap["OP_SUB"]   = OpSub; +      OpMap["OP_SUBL"]  = OpSubl; +      OpMap["OP_SUBW"]  = OpSubw; +      OpMap["OP_MUL"]   = OpMul; +      OpMap["OP_MLA"]   = OpMla; +      OpMap["OP_MLAL"]  = OpMlal; +      OpMap["OP_MLS"]   = OpMls; +      OpMap["OP_MLSL"]  = OpMlsl; +      OpMap["OP_MUL_N"] = OpMulN; +      OpMap["OP_MLA_N"] = OpMlaN; +      OpMap["OP_MLS_N"] = OpMlsN; +      OpMap["OP_MLAL_N"] = OpMlalN; +      OpMap["OP_MLSL_N"] = OpMlslN; +      OpMap["OP_MUL_LN"]= OpMulLane; +      OpMap["OP_MULL_LN"] = OpMullLane; +      OpMap["OP_MLA_LN"]= OpMlaLane; +      OpMap["OP_MLS_LN"]= OpMlsLane; +      OpMap["OP_MLAL_LN"] = OpMlalLane; +      OpMap["OP_MLSL_LN"] = OpMlslLane; +      OpMap["OP_QDMULL_LN"] = OpQDMullLane; +      OpMap["OP_QDMLAL_LN"] = OpQDMlalLane; +      OpMap["OP_QDMLSL_LN"] = OpQDMlslLane; +      OpMap["OP_QDMULH_LN"] = OpQDMulhLane; +      OpMap["OP_QRDMULH_LN"] = OpQRDMulhLane; +      OpMap["OP_EQ"]    = OpEq; +      OpMap["OP_GE"]    = OpGe; +      OpMap["OP_LE"]    = OpLe; +      OpMap["OP_GT"]    = OpGt; +      OpMap["OP_LT"]    = OpLt; +      OpMap["OP_NEG"]   = OpNeg; +      OpMap["OP_NOT"]   = OpNot; +      OpMap["OP_AND"]   = OpAnd; +      OpMap["OP_OR"]    = OpOr; +      OpMap["OP_XOR"]   = OpXor; +      OpMap["OP_ANDN"]  = OpAndNot; +      OpMap["OP_ORN"]   = OpOrNot; +      OpMap["OP_CAST"]  = OpCast; +      OpMap["OP_CONC"]  = OpConcat; +      OpMap["OP_HI"]    = OpHi; +      OpMap["OP_LO"]    = OpLo; +      OpMap["OP_DUP"]   = OpDup; +      OpMap["OP_DUP_LN"] = OpDupLane; +      OpMap["OP_SEL"]   = OpSelect; +      OpMap["OP_REV16"] = OpRev16; +      OpMap["OP_REV32"] = OpRev32; +      OpMap["OP_REV64"] = OpRev64; +      OpMap["OP_REINT"] = OpReinterpret; +      OpMap["OP_ABDL"]  = OpAbdl; +      OpMap["OP_ABA"]   = OpAba; +      OpMap["OP_ABAL"]  = OpAbal; + +      Record *SI = R.getClass("SInst"); +      Record *II = R.getClass("IInst"); +      Record *WI = R.getClass("WInst"); +      ClassMap[SI] = ClassS; +      ClassMap[II] = ClassI; +      ClassMap[WI] = ClassW; +    } + +    // run - Emit arm_neon.h.inc +    void run(raw_ostream &o); + +    // runHeader - Emit all the __builtin prototypes used in arm_neon.h +    void runHeader(raw_ostream &o); + +    // runTests - Emit tests for all the Neon intrinsics. +    void runTests(raw_ostream &o); + +  private: +    void emitIntrinsic(raw_ostream &OS, Record *R); +  }; + +} // End llvm namespace + +#endif diff --git a/clang/utils/TableGen/OptParserEmitter.cpp b/clang/utils/TableGen/OptParserEmitter.cpp new file mode 100644 index 0000000..dea22d3 --- /dev/null +++ b/clang/utils/TableGen/OptParserEmitter.cpp @@ -0,0 +1,194 @@ +//===- OptParserEmitter.cpp - Table Driven Command Line Parsing -----------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "OptParserEmitter.h" +#include "llvm/TableGen/Record.h" +#include "llvm/ADT/STLExtras.h" +using namespace llvm; + +static int StrCmpOptionName(const char *A, const char *B) { +  char a = *A, b = *B; +  while (a == b) { +    if (a == '\0') +      return 0; + +    a = *++A; +    b = *++B; +  } + +  if (a == '\0') // A is a prefix of B. +    return 1; +  if (b == '\0') // B is a prefix of A. +    return -1; + +  // Otherwise lexicographic. +  return (a < b) ? -1 : 1; +} + +static int CompareOptionRecords(const void *Av, const void *Bv) { +  const Record *A = *(Record**) Av; +  const Record *B = *(Record**) Bv; + +  // Sentinel options precede all others and are only ordered by precedence. +  bool ASent = A->getValueAsDef("Kind")->getValueAsBit("Sentinel"); +  bool BSent = B->getValueAsDef("Kind")->getValueAsBit("Sentinel"); +  if (ASent != BSent) +    return ASent ? -1 : 1; + +  // Compare options by name, unless they are sentinels. +  if (!ASent) +    if (int Cmp = StrCmpOptionName(A->getValueAsString("Name").c_str(), +                                   B->getValueAsString("Name").c_str())) +    return Cmp; + +  // Then by the kind precedence; +  int APrec = A->getValueAsDef("Kind")->getValueAsInt("Precedence"); +  int BPrec = B->getValueAsDef("Kind")->getValueAsInt("Precedence"); +  assert(APrec != BPrec && "Options are equivalent!"); +  return APrec < BPrec ? -1 : 1; +} + +static const std::string getOptionName(const Record &R) { +  // Use the record name unless EnumName is defined. +  if (dynamic_cast<UnsetInit*>(R.getValueInit("EnumName"))) +    return R.getName(); + +  return R.getValueAsString("EnumName"); +} + +static raw_ostream &write_cstring(raw_ostream &OS, llvm::StringRef Str) { +  OS << '"'; +  OS.write_escaped(Str); +  OS << '"'; +  return OS; +} + +void OptParserEmitter::run(raw_ostream &OS) { +  // Get the option groups and options. +  const std::vector<Record*> &Groups = +    Records.getAllDerivedDefinitions("OptionGroup"); +  std::vector<Record*> Opts = Records.getAllDerivedDefinitions("Option"); + +  if (GenDefs) +    EmitSourceFileHeader("Option Parsing Definitions", OS); +  else +    EmitSourceFileHeader("Option Parsing Table", OS); + +  array_pod_sort(Opts.begin(), Opts.end(), CompareOptionRecords); +  if (GenDefs) { +    OS << "#ifndef OPTION\n"; +    OS << "#error \"Define OPTION prior to including this file!\"\n"; +    OS << "#endif\n\n"; + +    OS << "/////////\n"; +    OS << "// Groups\n\n"; +    for (unsigned i = 0, e = Groups.size(); i != e; ++i) { +      const Record &R = *Groups[i]; + +      // Start a single option entry. +      OS << "OPTION("; + +      // The option string. +      OS << '"' << R.getValueAsString("Name") << '"'; + +      // The option identifier name. +      OS  << ", "<< getOptionName(R); + +      // The option kind. +      OS << ", Group"; + +      // The containing option group (if any). +      OS << ", "; +      if (const DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group"))) +        OS << getOptionName(*DI->getDef()); +      else +        OS << "INVALID"; + +      // The other option arguments (unused for groups). +      OS << ", INVALID, 0, 0"; + +      // The option help text. +      if (!dynamic_cast<UnsetInit*>(R.getValueInit("HelpText"))) { +        OS << ",\n"; +        OS << "       "; +        write_cstring(OS, R.getValueAsString("HelpText")); +      } else +        OS << ", 0"; + +      // The option meta-variable name (unused). +      OS << ", 0)\n"; +    } +    OS << "\n"; + +    OS << "//////////\n"; +    OS << "// Options\n\n"; +    for (unsigned i = 0, e = Opts.size(); i != e; ++i) { +      const Record &R = *Opts[i]; + +      // Start a single option entry. +      OS << "OPTION("; + +      // The option string. +      write_cstring(OS, R.getValueAsString("Name")); + +      // The option identifier name. +      OS  << ", "<< getOptionName(R); + +      // The option kind. +      OS << ", " << R.getValueAsDef("Kind")->getValueAsString("Name"); + +      // The containing option group (if any). +      OS << ", "; +      if (const DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group"))) +        OS << getOptionName(*DI->getDef()); +      else +        OS << "INVALID"; + +      // The option alias (if any). +      OS << ", "; +      if (const DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Alias"))) +        OS << getOptionName(*DI->getDef()); +      else +        OS << "INVALID"; + +      // The option flags. +      const ListInit *LI = R.getValueAsListInit("Flags"); +      if (LI->empty()) { +        OS << ", 0"; +      } else { +        OS << ", "; +        for (unsigned i = 0, e = LI->size(); i != e; ++i) { +          if (i) +            OS << " | "; +          OS << dynamic_cast<DefInit*>(LI->getElement(i))->getDef()->getName(); +        } +      } + +      // The option parameter field. +      OS << ", " << R.getValueAsInt("NumArgs"); + +      // The option help text. +      if (!dynamic_cast<UnsetInit*>(R.getValueInit("HelpText"))) { +        OS << ",\n"; +        OS << "       "; +        write_cstring(OS, R.getValueAsString("HelpText")); +      } else +        OS << ", 0"; + +      // The option meta-variable name. +      OS << ", "; +      if (!dynamic_cast<UnsetInit*>(R.getValueInit("MetaVarName"))) +        write_cstring(OS, R.getValueAsString("MetaVarName")); +      else +        OS << "0"; + +      OS << ")\n"; +    } +  } +} diff --git a/clang/utils/TableGen/OptParserEmitter.h b/clang/utils/TableGen/OptParserEmitter.h new file mode 100644 index 0000000..ca667ca --- /dev/null +++ b/clang/utils/TableGen/OptParserEmitter.h @@ -0,0 +1,34 @@ +//===- OptParserEmitter.h - Table Driven Command Line Parsing ---*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef UTILS_TABLEGEN_OPTPARSEREMITTER_H +#define UTILS_TABLEGEN_OPTPARSEREMITTER_H + +#include "llvm/TableGen/TableGenBackend.h" + +namespace llvm { +  /// OptParserEmitter - This tablegen backend takes an input .td file +  /// describing a list of options and emits a data structure for parsing and +  /// working with those options when given an input command line. +  class OptParserEmitter : public TableGenBackend { +    RecordKeeper &Records; +    bool GenDefs; + +  public: +    OptParserEmitter(RecordKeeper &R, bool _GenDefs) +      : Records(R), GenDefs(_GenDefs) {} + +    /// run - Output the option parsing information. +    /// +    /// \param GenHeader - Generate the header describing the option IDs.x +    void run(raw_ostream &OS); +  }; +} + +#endif diff --git a/clang/utils/TableGen/TableGen.cpp b/clang/utils/TableGen/TableGen.cpp new file mode 100644 index 0000000..5ff88db --- /dev/null +++ b/clang/utils/TableGen/TableGen.cpp @@ -0,0 +1,194 @@ +//===- TableGen.cpp - Top-Level TableGen implementation for Clang ---------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the main function for Clang's TableGen. +// +//===----------------------------------------------------------------------===// + +#include "ClangASTNodesEmitter.h" +#include "ClangAttrEmitter.h" +#include "ClangDiagnosticsEmitter.h" +#include "ClangSACheckersEmitter.h" +#include "NeonEmitter.h" +#include "OptParserEmitter.h" + +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Signals.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Main.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenAction.h" + +using namespace llvm; + +enum ActionType { +  GenClangAttrClasses, +  GenClangAttrImpl, +  GenClangAttrList, +  GenClangAttrPCHRead, +  GenClangAttrPCHWrite, +  GenClangAttrSpellingList, +  GenClangAttrLateParsedList, +  GenClangAttrTemplateInstantiate, +  GenClangAttrParsedAttrList, +  GenClangAttrParsedAttrKinds, +  GenClangDiagsDefs, +  GenClangDiagGroups, +  GenClangDiagsIndexName, +  GenClangDeclNodes, +  GenClangStmtNodes, +  GenClangSACheckers, +  GenOptParserDefs, GenOptParserImpl, +  GenArmNeon, +  GenArmNeonSema, +  GenArmNeonTest +}; + +namespace { +  cl::opt<ActionType> +  Action(cl::desc("Action to perform:"), +         cl::values(clEnumValN(GenOptParserDefs, "gen-opt-parser-defs", +                               "Generate option definitions"), +                    clEnumValN(GenOptParserImpl, "gen-opt-parser-impl", +                               "Generate option parser implementation"), +                    clEnumValN(GenClangAttrClasses, "gen-clang-attr-classes", +                               "Generate clang attribute clases"), +                    clEnumValN(GenClangAttrImpl, "gen-clang-attr-impl", +                               "Generate clang attribute implementations"), +                    clEnumValN(GenClangAttrList, "gen-clang-attr-list", +                               "Generate a clang attribute list"), +                    clEnumValN(GenClangAttrPCHRead, "gen-clang-attr-pch-read", +                               "Generate clang PCH attribute reader"), +                    clEnumValN(GenClangAttrPCHWrite, "gen-clang-attr-pch-write", +                               "Generate clang PCH attribute writer"), +                    clEnumValN(GenClangAttrSpellingList, +                               "gen-clang-attr-spelling-list", +                               "Generate a clang attribute spelling list"), +                    clEnumValN(GenClangAttrLateParsedList, +                               "gen-clang-attr-late-parsed-list", +                               "Generate a clang attribute LateParsed list"), +                    clEnumValN(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(GenClangDiagsDefs, "gen-clang-diags-defs", +                               "Generate Clang diagnostics definitions"), +                    clEnumValN(GenClangDiagGroups, "gen-clang-diag-groups", +                               "Generate Clang diagnostic groups"), +                    clEnumValN(GenClangDiagsIndexName, +                               "gen-clang-diags-index-name", +                               "Generate Clang diagnostic name index"), +                    clEnumValN(GenClangDeclNodes, "gen-clang-decl-nodes", +                               "Generate Clang AST declaration nodes"), +                    clEnumValN(GenClangStmtNodes, "gen-clang-stmt-nodes", +                               "Generate Clang AST statement nodes"), +                    clEnumValN(GenClangSACheckers, "gen-clang-sa-checkers", +                               "Generate Clang Static Analyzer checkers"), +                    clEnumValN(GenArmNeon, "gen-arm-neon", +                               "Generate arm_neon.h for clang"), +                    clEnumValN(GenArmNeonSema, "gen-arm-neon-sema", +                               "Generate ARM NEON sema support for clang"), +                    clEnumValN(GenArmNeonTest, "gen-arm-neon-test", +                               "Generate ARM NEON tests for clang"), +                    clEnumValEnd)); + +  cl::opt<std::string> +  ClangComponent("clang-component", +                 cl::desc("Only use warnings from specified component"), +                 cl::value_desc("component"), cl::Hidden); + +class ClangTableGenAction : public TableGenAction { +public: +  bool operator()(raw_ostream &OS, RecordKeeper &Records) { +    switch (Action) { +    case GenClangAttrClasses: +      ClangAttrClassEmitter(Records).run(OS); +      break; +    case GenClangAttrImpl: +      ClangAttrImplEmitter(Records).run(OS); +      break; +    case GenClangAttrList: +      ClangAttrListEmitter(Records).run(OS); +      break; +    case GenClangAttrPCHRead: +      ClangAttrPCHReadEmitter(Records).run(OS); +      break; +    case GenClangAttrPCHWrite: +      ClangAttrPCHWriteEmitter(Records).run(OS); +      break; +    case GenClangAttrSpellingList: +      ClangAttrSpellingListEmitter(Records).run(OS); +      break; +    case GenClangAttrLateParsedList: +      ClangAttrLateParsedListEmitter(Records).run(OS); +      break; +    case GenClangAttrTemplateInstantiate: +      ClangAttrTemplateInstantiateEmitter(Records).run(OS); +      break; +    case GenClangAttrParsedAttrList: +      ClangAttrParsedAttrListEmitter(Records).run(OS); +      break; +    case GenClangAttrParsedAttrKinds: +      ClangAttrParsedAttrKindsEmitter(Records).run(OS); +      break; +    case GenClangDiagsDefs: +      ClangDiagsDefsEmitter(Records, ClangComponent).run(OS); +      break; +    case GenClangDiagGroups: +      ClangDiagGroupsEmitter(Records).run(OS); +      break; +    case GenClangDiagsIndexName: +      ClangDiagsIndexNameEmitter(Records).run(OS); +      break; +    case GenClangDeclNodes: +      ClangASTNodesEmitter(Records, "Decl", "Decl").run(OS); +      ClangDeclContextEmitter(Records).run(OS); +      break; +    case GenClangStmtNodes: +      ClangASTNodesEmitter(Records, "Stmt", "").run(OS); +      break; +    case GenClangSACheckers: +      ClangSACheckersEmitter(Records).run(OS); +      break; +    case GenOptParserDefs: +      OptParserEmitter(Records, true).run(OS); +      break; +    case GenOptParserImpl: +      OptParserEmitter(Records, false).run(OS); +      break; +    case GenArmNeon: +      NeonEmitter(Records).run(OS); +      break; +    case GenArmNeonSema: +      NeonEmitter(Records).runHeader(OS); +      break; +    case GenArmNeonTest: +      NeonEmitter(Records).runTests(OS); +      break; +    } + +    return false; +  } +}; +} + +int main(int argc, char **argv) { +  sys::PrintStackTraceOnErrorSignal(); +  PrettyStackTraceProgram X(argc, argv); +  cl::ParseCommandLineOptions(argc, argv); + +  ClangTableGenAction Action; +  return TableGenMain(argv[0], Action); +} | 
