diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt index f68159ab908..731cde92cfe 100644 --- a/utils/TableGen/CMakeLists.txt +++ b/utils/TableGen/CMakeLists.txt @@ -4,6 +4,7 @@ add_executable(tblgen AsmWriterEmitter.cpp AsmWriterInst.cpp CallingConvEmitter.cpp + ClangASTNodesEmitter.cpp ClangDiagnosticsEmitter.cpp CodeEmitterGen.cpp CodeGenDAGPatterns.cpp diff --git a/utils/TableGen/ClangASTNodesEmitter.cpp b/utils/TableGen/ClangASTNodesEmitter.cpp new file mode 100644 index 00000000000..f9366d9e0bc --- /dev/null +++ b/utils/TableGen/ClangASTNodesEmitter.cpp @@ -0,0 +1,126 @@ +#include "ClangASTNodesEmitter.h" +#include "Record.h" +#include +#include +#include +#include +#include +#include +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Statement Node Tables (.inc file) generation. +//===----------------------------------------------------------------------===// + +// Sort to create a tree-like structure based on the 'Base' field. +namespace { + // Create a macro-ized version of a name + std::string macroName(std::string S) { + for (unsigned i = 0; i < S.size(); ++i) + S[i] = std::toupper(S[i]); + + return S; + } + + // A map from a node to each of its derived nodes. + typedef std::multimap ChildMap; + typedef ChildMap::const_iterator ChildIterator; + + // Returns the first and last non-abstract subrecords + std::pair EmitStmtNode(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(" << NodeName << "(" << R->getName() << ", " + << Base->getName() << "))\n"; + else + OS << NodeName << "(" << R->getName() << ", " + << Base->getName() << ")\n"; + + if (Tree.find(R) != Tree.end()) { + const std::pair &Result = EmitStmtNode(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"; + } + + assert(!First == !Last && "Got a first or last node, but not the other"); + + if (First) { + OS << "#ifndef FIRST_" << BaseName << "\n"; + OS << "# define FIRST_" << BaseName << "(CLASS)\n"; + OS << "#endif\n"; + OS << "#ifndef LAST_" << BaseName << "\n"; + OS << "# define LAST_" << BaseName << "(CLASS)\n"; + OS << "#endif\n\n"; + + OS << "FIRST_" << BaseName << "(" << First->getName() << ")\n"; + OS << "LAST_" << BaseName << "(" << Last->getName() << ")\n\n"; + } + + OS << "#undef FIRST_" << BaseName << "\n"; + OS << "#undef LAST_" << BaseName << "\n\n"; + + return std::make_pair(First, Last); + } +} + +void ClangStmtNodesEmitter::run(raw_ostream &OS) { + // Write the preamble + OS << "#ifndef ABSTRACT\n"; + OS << "# define ABSTRACT(Stmt) Stmt\n"; + OS << "#endif\n\n"; + + // Emit statements + const std::vector Stmts = Records.getAllDerivedDefinitions("Stmt"); + + ChildMap Tree; + + // Create a pseudo-record to serve as the Stmt node, which isn't actually + // output. + Record Stmt ("Stmt", SMLoc()); + + 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(&Stmt, R)); + } + + EmitStmtNode(Tree, OS, &Stmt); + + OS << "#undef STMT\n"; + OS << "#undef ABSTRACT\n"; +} \ No newline at end of file diff --git a/utils/TableGen/ClangASTNodesEmitter.h b/utils/TableGen/ClangASTNodesEmitter.h new file mode 100644 index 00000000000..9f442c13251 --- /dev/null +++ b/utils/TableGen/ClangASTNodesEmitter.h @@ -0,0 +1,36 @@ +//===- 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 CLANGAST_EMITTER_H +#define CLANGAST_EMITTER_H + +#include "TableGenBackend.h" + +namespace llvm { + +/// ClangStmtNodesEmitter - The top-level class emits .def files containing +/// declarations of Clang statements. +/// +class ClangStmtNodesEmitter : public TableGenBackend { + RecordKeeper &Records; +public: + explicit ClangStmtNodesEmitter(RecordKeeper &R) + : Records(R) {} + + // run - Output the .def file contents + void run(raw_ostream &OS); +}; + +} // End llvm namespace + +#endif diff --git a/utils/TableGen/Makefile b/utils/TableGen/Makefile index 7ea88de0559..f27cd995783 100644 --- a/utils/TableGen/Makefile +++ b/utils/TableGen/Makefile @@ -1,10 +1,10 @@ ##===- 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 = ../.. diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp index 1c66399ce8b..17435f6d828 100644 --- a/utils/TableGen/TableGen.cpp +++ b/utils/TableGen/TableGen.cpp @@ -18,6 +18,7 @@ #include "AsmMatcherEmitter.h" #include "AsmWriterEmitter.h" #include "CallingConvEmitter.h" +#include "ClangASTNodesEmitter.h" #include "ClangDiagnosticsEmitter.h" #include "CodeEmitterGen.h" #include "DAGISelEmitter.h" @@ -53,6 +54,7 @@ enum ActionType { GenCallingConv, GenClangDiagsDefs, GenClangDiagGroups, + GenClangStmtNodes, GenDAGISel, GenFastISel, GenOptParserDefs, GenOptParserImpl, @@ -109,6 +111,8 @@ namespace { "Generate Clang diagnostics definitions"), clEnumValN(GenClangDiagGroups, "gen-clang-diag-groups", "Generate Clang diagnostic groups"), + clEnumValN(GenClangStmtNodes, "gen-clang-stmt-nodes", + "Generate Clang AST statement nodes"), clEnumValN(GenLLVMCConf, "gen-llvmc", "Generate LLVMC configuration library"), clEnumValN(GenEDHeader, "gen-enhanced-disassembly-header", @@ -133,7 +137,7 @@ namespace { cl::list IncludeDirs("I", cl::desc("Directory of include files"), cl::value_desc("directory"), cl::Prefix); - + cl::opt ClangComponent("clang-component", cl::desc("Only use warnings from specified component"), @@ -160,18 +164,18 @@ static bool ParseFile(const std::string &Filename, std::string ErrorStr; MemoryBuffer *F = MemoryBuffer::getFileOrSTDIN(Filename.c_str(), &ErrorStr); if (F == 0) { - errs() << "Could not open input file '" << Filename << "': " + errs() << "Could not open input file '" << Filename << "': " << ErrorStr <<"\n"; return true; } - + // Tell SrcMgr about this buffer, which is what TGParser will pick up. SrcMgr.AddNewSourceBuffer(F, SMLoc()); // Record the location of the include directory so that the lexer can find // it later. SrcMgr.setIncludeDirs(IncludeDirs); - + TGParser Parser(SrcMgr); return Parser.ParseFile(); @@ -182,7 +186,7 @@ int main(int argc, char **argv) { PrettyStackTraceProgram X(argc, argv); cl::ParseCommandLineOptions(argc, argv); - + // Parse the input file. if (ParseFile(InputFilename, IncludeDirs, SrcMgr)) return 1; @@ -193,7 +197,7 @@ int main(int argc, char **argv) { Out = new raw_fd_ostream(OutputFilename.c_str(), Error); if (!Error.empty()) { - errs() << argv[0] << ": error opening " << OutputFilename + errs() << argv[0] << ": error opening " << OutputFilename << ":" << Error << "\n"; return 1; } @@ -244,6 +248,9 @@ int main(int argc, char **argv) { case GenClangDiagGroups: ClangDiagGroupsEmitter(Records).run(*Out); break; + case GenClangStmtNodes: + ClangStmtNodesEmitter(Records).run(*Out); + break; case GenDisassembler: DisassemblerEmitter(Records).run(*Out); break; @@ -289,15 +296,15 @@ int main(int argc, char **argv) { assert(1 && "Invalid Action"); return 1; } - + if (Out != &outs()) delete Out; // Close the file return 0; - + } catch (const TGError &Error) { errs() << argv[0] << ": error:\n"; PrintError(Error.getLoc(), Error.getMessage()); - + } catch (const std::string &Error) { errs() << argv[0] << ": " << Error << "\n"; } catch (const char *Error) { @@ -305,7 +312,7 @@ int main(int argc, char **argv) { } catch (...) { errs() << argv[0] << ": Unknown unexpected exception occurred.\n"; } - + if (Out != &outs()) { delete Out; // Close the file std::remove(OutputFilename.c_str()); // Remove the file, it's broken