diff options
Diffstat (limited to 'contrib/llvm/utils/TableGen')
24 files changed, 2016 insertions, 305 deletions
diff --git a/contrib/llvm/utils/TableGen/ARMDecoderEmitter.cpp b/contrib/llvm/utils/TableGen/ARMDecoderEmitter.cpp index c879a54..5025691 100644 --- a/contrib/llvm/utils/TableGen/ARMDecoderEmitter.cpp +++ b/contrib/llvm/utils/TableGen/ARMDecoderEmitter.cpp @@ -1575,6 +1575,15 @@ bool ARMDecoderEmitter::ARMDEBackend::populateInstruction( if (Name == "BXr9" || Name == "BMOVPCRX" || Name == "BMOVPCRXr9") return false; + // Tail calls are other patterns that generate existing instructions. + if (Name == "TCRETURNdi" || Name == "TCRETURNdiND" || + Name == "TCRETURNri" || Name == "TCRETURNriND" || + Name == "TAILJMPd" || Name == "TAILJMPdt" || + Name == "TAILJMPdND" || Name == "TAILJMPdNDt" || + Name == "TAILJMPr" || Name == "TAILJMPrND" || + Name == "MOVr_TC") + return false; + // VLDMQ/VSTMQ can be hanlded with the more generic VLDMD/VSTMD. if (Name == "VLDMQ" || Name == "VLDMQ_UPD" || Name == "VSTMQ" || Name == "VSTMQ_UPD") diff --git a/contrib/llvm/utils/TableGen/ARMDecoderEmitter.h b/contrib/llvm/utils/TableGen/ARMDecoderEmitter.h index 107e085..571a947 100644 --- a/contrib/llvm/utils/TableGen/ARMDecoderEmitter.h +++ b/contrib/llvm/utils/TableGen/ARMDecoderEmitter.h @@ -31,7 +31,7 @@ public: ~ARMDecoderEmitter() { shutdownBackend(); } - + // run - Output the code emitter void run(raw_ostream &o); diff --git a/contrib/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/contrib/llvm/utils/TableGen/AsmMatcherEmitter.cpp index 4ba3df1..e1aa2bc 100644 --- a/contrib/llvm/utils/TableGen/AsmMatcherEmitter.cpp +++ b/contrib/llvm/utils/TableGen/AsmMatcherEmitter.cpp @@ -407,9 +407,9 @@ public: default: // This class preceeds the RHS if it is a proper subset of the RHS. if (isSubsetOf(RHS)) - return true; + return true; if (RHS.isSubsetOf(*this)) - return false; + return false; // Otherwise, order by name to ensure we have a total ordering. return ValueName < RHS.ValueName; diff --git a/contrib/llvm/utils/TableGen/CMakeLists.txt b/contrib/llvm/utils/TableGen/CMakeLists.txt index 731cde9..972989b 100644 --- a/contrib/llvm/utils/TableGen/CMakeLists.txt +++ b/contrib/llvm/utils/TableGen/CMakeLists.txt @@ -5,6 +5,7 @@ add_executable(tblgen AsmWriterInst.cpp CallingConvEmitter.cpp ClangASTNodesEmitter.cpp + ClangAttrEmitter.cpp ClangDiagnosticsEmitter.cpp CodeEmitterGen.cpp CodeGenDAGPatterns.cpp @@ -22,6 +23,7 @@ add_executable(tblgen InstrInfoEmitter.cpp IntrinsicEmitter.cpp LLVMCConfigurationEmitter.cpp + NeonEmitter.cpp OptParserEmitter.cpp Record.cpp RegisterInfoEmitter.cpp @@ -39,6 +41,6 @@ target_link_libraries(tblgen LLVMSupport LLVMSystem) if( MINGW ) target_link_libraries(tblgen imagehlp psapi) endif( MINGW ) -if( LLVM_ENABLE_THREADS AND HAVE_LIBPTHREAD ) +if( LLVM_ENABLE_THREADS AND HAVE_LIBPTHREAD AND NOT BEOS ) target_link_libraries(tblgen pthread) endif() diff --git a/contrib/llvm/utils/TableGen/ClangASTNodesEmitter.cpp b/contrib/llvm/utils/TableGen/ClangASTNodesEmitter.cpp index 5d6423d..187ab46 100644 --- a/contrib/llvm/utils/TableGen/ClangASTNodesEmitter.cpp +++ b/contrib/llvm/utils/TableGen/ClangASTNodesEmitter.cpp @@ -12,33 +12,19 @@ //===----------------------------------------------------------------------===// #include "ClangASTNodesEmitter.h" -#include "Record.h" -#include <map> -#include <cctype> +#include <set> using namespace llvm; //===----------------------------------------------------------------------===// // Statement Node Tables (.inc file) generation. //===----------------------------------------------------------------------===// -// 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; -} - -// A map from a node to each of its derived nodes. -typedef std::multimap<Record*, Record*> ChildMap; -typedef ChildMap::const_iterator ChildIterator; - // Returns the first and last non-abstract subrecords // Called recursively to ensure that nodes remain contiguous -static std::pair<Record *, Record *> EmitStmtNode(const ChildMap &Tree, - raw_ostream &OS, - Record *Base, - bool Root = true) { +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); @@ -60,15 +46,15 @@ static std::pair<Record *, Record *> EmitStmtNode(const ChildMap &Tree, OS << "#endif\n"; if (Abstract) - OS << "ABSTRACT_STMT(" << NodeName << "(" << R->getName() << ", " - << Base->getName() << "))\n"; + OS << "ABSTRACT_" << macroName(Root.getName()) << "(" << NodeName << "(" + << R->getName() << ", " << baseName(*Base) << "))\n"; else OS << NodeName << "(" << R->getName() << ", " - << Base->getName() << ")\n"; + << baseName(*Base) << ")\n"; if (Tree.find(R) != Tree.end()) { const std::pair<Record *, Record *> &Result - = EmitStmtNode(Tree, OS, R, false); + = EmitNode(Tree, OS, R); if (!First && Result.first) First = Result.first; if (Result.second) @@ -87,11 +73,10 @@ static std::pair<Record *, Record *> EmitStmtNode(const ChildMap &Tree, if (First) { assert (Last && "Got a first node but not a last node for a range!"); - if (Root) - OS << "LAST_STMT_RANGE("; + if (Base == &Root) + OS << "LAST_" << macroName(Root.getName()) << "_RANGE("; else - OS << "STMT_RANGE("; - + OS << macroName(Root.getName()) << "_RANGE("; OS << Base->getName() << ", " << First->getName() << ", " << Last->getName() << ")\n\n"; } @@ -99,43 +84,82 @@ static std::pair<Record *, Record *> EmitStmtNode(const ChildMap &Tree, return std::make_pair(First, Last); } -void ClangStmtNodesEmitter::run(raw_ostream &OS) { +void ClangASTNodesEmitter::run(raw_ostream &OS) { // Write the preamble - OS << "#ifndef ABSTRACT_STMT\n"; - OS << "# define ABSTRACT_STMT(Stmt) Stmt\n"; + OS << "#ifndef ABSTRACT_" << macroName(Root.getName()) << "\n"; + OS << "# define ABSTRACT_" << macroName(Root.getName()) << "(Type) Type\n"; OS << "#endif\n"; - OS << "#ifndef STMT_RANGE\n"; - OS << "# define STMT_RANGE(Base, First, Last)\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_STMT_RANGE\n"; - OS << "# define LAST_STMT_RANGE(Base, First, Last) " - "STMT_RANGE(Base, First, Last)\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("Stmt"); + const std::vector<Record*> Stmts + = Records.getAllDerivedDefinitions(Root.getName()); 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)); + Tree.insert(std::make_pair(&Root, R)); } - EmitStmtNode(Tree, OS, &Stmt); + 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); + } + } + } + + for (RecordSet::iterator i = DeclContexts.begin(), e = DeclContexts.end(); + i != e; ++i) { + OS << "DECL_CONTEXT(" << (*i)->getName() << ")\n"; + } - OS << "#undef STMT\n"; - OS << "#undef STMT_RANGE\n"; - OS << "#undef LAST_STMT_RANGE\n"; - OS << "#undef ABSTRACT_STMT\n"; + OS << "#undef DECL_CONTEXT\n"; + OS << "#undef DECL_CONTEXT_BASE\n"; } diff --git a/contrib/llvm/utils/TableGen/ClangASTNodesEmitter.h b/contrib/llvm/utils/TableGen/ClangASTNodesEmitter.h index c4ce9fa..abf9c9a 100644 --- a/contrib/llvm/utils/TableGen/ClangASTNodesEmitter.h +++ b/contrib/llvm/utils/TableGen/ClangASTNodesEmitter.h @@ -15,19 +15,67 @@ #define CLANGAST_EMITTER_H #include "TableGenBackend.h" +#include "Record.h" +#include <string> +#include <cctype> +#include <map> namespace llvm { -/// ClangStmtNodesEmitter - The top-level class emits .def files containing +/// ClangASTNodesEmitter - The top-level class emits .inc files containing /// declarations of Clang statements. /// -class ClangStmtNodesEmitter : public TableGenBackend { +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()), 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 ClangStmtNodesEmitter(RecordKeeper &R) - : Records(R) {} + explicit ClangDeclContextEmitter(RecordKeeper &R) + : Records(R) + {} - // run - Output the .def file contents + // run - Output the .inc file contents void run(raw_ostream &OS); }; diff --git a/contrib/llvm/utils/TableGen/ClangAttrEmitter.cpp b/contrib/llvm/utils/TableGen/ClangAttrEmitter.cpp new file mode 100644 index 0000000..fbdd2a7 --- /dev/null +++ b/contrib/llvm/utils/TableGen/ClangAttrEmitter.cpp @@ -0,0 +1,84 @@ +//===- 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 "Record.h" +#include <algorithm> + +using namespace llvm; + +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; + + if (R.getValueAsBit("DoNotEmit")) + continue; + + OS << "class " << R.getName() << "Attr : public Attr {\n"; + + std::vector<Record*> Args = R.getValueAsListOfDefs("Args"); + + // FIXME: Handle arguments + assert(Args.empty() && "Can't yet handle arguments"); + + OS << "\n public:\n"; + OS << " " << R.getName() << "Attr("; + + // Arguments go here + + OS << ")\n"; + OS << " : Attr(attr::" << R.getName() << ")"; + + // Arguments go here + + OS << " {}\n\n"; + + OS << " virtual Attr *clone (ASTContext &C) const;\n"; + OS << " static bool classof(const Attr *A) { return A->getKind() == " + << "attr::" << R.getName() << "; }\n"; + OS << " static bool classof(const " << R.getName() + << "Attr *) { return true; }\n"; + OS << "};\n\n"; + } + + OS << "#endif\n"; +} + +void 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"; + + std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); + std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(); + + if (i != e) { + // Move the end iterator back to emit the last attribute. + for(--e; i != e; ++i) + OS << "ATTR(" << (*i)->getName() << ")\n"; + + OS << "LAST_ATTR(" << (*i)->getName() << ")\n\n"; + } + + OS << "#undef LAST_ATTR\n"; + OS << "#undef ATTR\n"; +} diff --git a/contrib/llvm/utils/TableGen/ClangAttrEmitter.h b/contrib/llvm/utils/TableGen/ClangAttrEmitter.h new file mode 100644 index 0000000..5ce1c87 --- /dev/null +++ b/contrib/llvm/utils/TableGen/ClangAttrEmitter.h @@ -0,0 +1,49 @@ +//===- 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 "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); +}; + +/// 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); +}; + +} + +#endif diff --git a/contrib/llvm/utils/TableGen/CodeEmitterGen.cpp b/contrib/llvm/utils/TableGen/CodeEmitterGen.cpp index 2a2a4ef..ec702c2a5 100644 --- a/contrib/llvm/utils/TableGen/CodeEmitterGen.cpp +++ b/contrib/llvm/utils/TableGen/CodeEmitterGen.cpp @@ -24,19 +24,8 @@ void CodeEmitterGen::reverseBits(std::vector<Record*> &Insts) { for (std::vector<Record*>::iterator I = Insts.begin(), E = Insts.end(); I != E; ++I) { Record *R = *I; - if (R->getName() == "PHI" || - R->getName() == "INLINEASM" || - R->getName() == "DBG_LABEL" || - R->getName() == "EH_LABEL" || - R->getName() == "GC_LABEL" || - R->getName() == "KILL" || - R->getName() == "EXTRACT_SUBREG" || - R->getName() == "INSERT_SUBREG" || - R->getName() == "IMPLICIT_DEF" || - R->getName() == "SUBREG_TO_REG" || - R->getName() == "COPY_TO_REGCLASS" || - R->getName() == "DBG_VALUE" || - R->getName() == "REG_SEQUENCE") continue; + if (R->getValueAsString("Namespace") == "TargetOpcode") + continue; BitsInit *BI = R->getValueAsBitsInit("Inst"); @@ -103,19 +92,7 @@ void CodeEmitterGen::run(raw_ostream &o) { const CodeGenInstruction *CGI = *IN; Record *R = CGI->TheDef; - if (R->getName() == "PHI" || - R->getName() == "INLINEASM" || - R->getName() == "DBG_LABEL" || - R->getName() == "EH_LABEL" || - R->getName() == "GC_LABEL" || - R->getName() == "KILL" || - R->getName() == "EXTRACT_SUBREG" || - R->getName() == "INSERT_SUBREG" || - R->getName() == "IMPLICIT_DEF" || - R->getName() == "SUBREG_TO_REG" || - R->getName() == "COPY_TO_REGCLASS" || - R->getName() == "DBG_VALUE" || - R->getName() == "REG_SEQUENCE") { + if (R->getValueAsString("Namespace") == "TargetOpcode") { o << " 0U,\n"; continue; } @@ -140,22 +117,10 @@ void CodeEmitterGen::run(raw_ostream &o) { for (std::vector<Record*>::iterator IC = Insts.begin(), EC = Insts.end(); IC != EC; ++IC) { Record *R = *IC; + if (R->getValueAsString("Namespace") == "TargetOpcode") + continue; const std::string &InstName = R->getName(); std::string Case(""); - - if (InstName == "PHI" || - InstName == "INLINEASM" || - InstName == "DBG_LABEL"|| - InstName == "EH_LABEL"|| - InstName == "GC_LABEL"|| - InstName == "KILL"|| - InstName == "EXTRACT_SUBREG" || - InstName == "INSERT_SUBREG" || - InstName == "IMPLICIT_DEF" || - InstName == "SUBREG_TO_REG" || - InstName == "COPY_TO_REGCLASS" || - InstName == "DBG_VALUE" || - InstName == "REG_SEQUENCE") continue; BitsInit *BI = R->getValueAsBitsInit("Inst"); const std::vector<RecordVal> &Vals = R->getValues(); diff --git a/contrib/llvm/utils/TableGen/CodeGenInstruction.cpp b/contrib/llvm/utils/TableGen/CodeGenInstruction.cpp index 99d196c..35b54a5 100644 --- a/contrib/llvm/utils/TableGen/CodeGenInstruction.cpp +++ b/contrib/llvm/utils/TableGen/CodeGenInstruction.cpp @@ -107,7 +107,6 @@ CodeGenInstruction::CodeGenInstruction(Record *R, const std::string &AsmStr) canFoldAsLoad = R->getValueAsBit("canFoldAsLoad"); mayLoad = R->getValueAsBit("mayLoad"); mayStore = R->getValueAsBit("mayStore"); - bool isTwoAddress = R->getValueAsBit("isTwoAddress"); isPredicable = R->getValueAsBit("isPredicable"); isConvertibleToThreeAddress = R->getValueAsBit("isConvertibleToThreeAddress"); isCommutable = R->getValueAsBit("isCommutable"); @@ -212,16 +211,6 @@ CodeGenInstruction::CodeGenInstruction(Record *R, const std::string &AsmStr) // Parse Constraints. ParseConstraints(R->getValueAsString("Constraints"), this); - // For backward compatibility: isTwoAddress means operand 1 is tied to - // operand 0. - if (isTwoAddress) { - if (!OperandList[1].Constraints[0].isNone()) - throw R->getName() + ": cannot use isTwoAddress property: instruction " - "already has constraint set!"; - OperandList[1].Constraints[0] = - CodeGenInstruction::ConstraintInfo::getTied(0); - } - // Parse the DisableEncoding field. std::string DisableEncoding = R->getValueAsString("DisableEncoding"); while (1) { diff --git a/contrib/llvm/utils/TableGen/CodeGenTarget.cpp b/contrib/llvm/utils/TableGen/CodeGenTarget.cpp index 3797992..d8130fb 100644 --- a/contrib/llvm/utils/TableGen/CodeGenTarget.cpp +++ b/contrib/llvm/utils/TableGen/CodeGenTarget.cpp @@ -329,61 +329,42 @@ struct SortInstByName { /// getInstructionsByEnumValue - Return all of the instructions defined by the /// target, ordered by their enum value. void CodeGenTarget::ComputeInstrsByEnum() const { + // The ordering here must match the ordering in TargetOpcodes.h. + const char *const FixedInstrs[] = { + "PHI", + "INLINEASM", + "DBG_LABEL", + "EH_LABEL", + "GC_LABEL", + "KILL", + "EXTRACT_SUBREG", + "INSERT_SUBREG", + "IMPLICIT_DEF", + "SUBREG_TO_REG", + "COPY_TO_REGCLASS", + "DBG_VALUE", + "REG_SEQUENCE", + "COPY", + 0 + }; const DenseMap<const Record*, CodeGenInstruction*> &Insts = getInstructions(); - const CodeGenInstruction *PHI = GetInstByName("PHI", Insts); - const CodeGenInstruction *INLINEASM = GetInstByName("INLINEASM", Insts); - const CodeGenInstruction *DBG_LABEL = GetInstByName("DBG_LABEL", Insts); - const CodeGenInstruction *EH_LABEL = GetInstByName("EH_LABEL", Insts); - const CodeGenInstruction *GC_LABEL = GetInstByName("GC_LABEL", Insts); - const CodeGenInstruction *KILL = GetInstByName("KILL", Insts); - const CodeGenInstruction *EXTRACT_SUBREG = - GetInstByName("EXTRACT_SUBREG", Insts); - const CodeGenInstruction *INSERT_SUBREG = - GetInstByName("INSERT_SUBREG", Insts); - const CodeGenInstruction *IMPLICIT_DEF = GetInstByName("IMPLICIT_DEF", Insts); - const CodeGenInstruction *SUBREG_TO_REG = - GetInstByName("SUBREG_TO_REG", Insts); - const CodeGenInstruction *COPY_TO_REGCLASS = - GetInstByName("COPY_TO_REGCLASS", Insts); - const CodeGenInstruction *DBG_VALUE = GetInstByName("DBG_VALUE", Insts); - const CodeGenInstruction *REG_SEQUENCE = GetInstByName("REG_SEQUENCE", Insts); - - // Print out the rest of the instructions now. - InstrsByEnum.push_back(PHI); - InstrsByEnum.push_back(INLINEASM); - InstrsByEnum.push_back(DBG_LABEL); - InstrsByEnum.push_back(EH_LABEL); - InstrsByEnum.push_back(GC_LABEL); - InstrsByEnum.push_back(KILL); - InstrsByEnum.push_back(EXTRACT_SUBREG); - InstrsByEnum.push_back(INSERT_SUBREG); - InstrsByEnum.push_back(IMPLICIT_DEF); - InstrsByEnum.push_back(SUBREG_TO_REG); - InstrsByEnum.push_back(COPY_TO_REGCLASS); - InstrsByEnum.push_back(DBG_VALUE); - InstrsByEnum.push_back(REG_SEQUENCE); - + for (const char *const *p = FixedInstrs; *p; ++p) { + const CodeGenInstruction *Instr = GetInstByName(*p, Insts); + assert(Instr && "Missing target independent instruction"); + assert(Instr->Namespace == "TargetOpcode" && "Bad namespace"); + InstrsByEnum.push_back(Instr); + } unsigned EndOfPredefines = InstrsByEnum.size(); - + for (DenseMap<const Record*, CodeGenInstruction*>::const_iterator I = Insts.begin(), E = Insts.end(); I != E; ++I) { const CodeGenInstruction *CGI = I->second; - if (CGI != PHI && - CGI != INLINEASM && - CGI != DBG_LABEL && - CGI != EH_LABEL && - CGI != GC_LABEL && - CGI != KILL && - CGI != EXTRACT_SUBREG && - CGI != INSERT_SUBREG && - CGI != IMPLICIT_DEF && - CGI != SUBREG_TO_REG && - CGI != COPY_TO_REGCLASS && - CGI != DBG_VALUE && - CGI != REG_SEQUENCE) + if (CGI->Namespace != "TargetOpcode") InstrsByEnum.push_back(CGI); } - + + assert(InstrsByEnum.size() == Insts.size() && "Missing predefined instr"); + // All of the instructions are now in random order based on the map iteration. // Sort them by name. std::sort(InstrsByEnum.begin()+EndOfPredefines, InstrsByEnum.end(), diff --git a/contrib/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp b/contrib/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp index 4473f0d..3750bd8 100644 --- a/contrib/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp +++ b/contrib/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp @@ -635,6 +635,7 @@ void MatcherTableEmitter::EmitPredicateFunctions(formatted_raw_ostream &OS) { if (!ComplexPatterns.empty()) { OS << "bool CheckComplexPattern(SDNode *Root, SDValue N,\n"; OS << " unsigned PatternNo, SmallVectorImpl<SDValue> &Result) {\n"; + OS << " unsigned NextRes = Result.size();\n"; OS << " switch (PatternNo) {\n"; OS << " default: assert(0 && \"Invalid pattern # in table?\");\n"; for (unsigned i = 0, e = ComplexPatterns.size(); i != e; ++i) { @@ -645,12 +646,12 @@ void MatcherTableEmitter::EmitPredicateFunctions(formatted_raw_ostream &OS) { ++NumOps; // Get the chained node too. OS << " case " << i << ":\n"; - OS << " Result.resize(Result.size()+" << NumOps << ");\n"; + OS << " Result.resize(NextRes+" << NumOps << ");\n"; OS << " return " << P.getSelectFunc(); OS << "(Root, N"; for (unsigned i = 0; i != NumOps; ++i) - OS << ", Result[Result.size()-" << (NumOps-i) << ']'; + OS << ", Result[NextRes+" << i << ']'; OS << ");\n"; } OS << " }\n"; diff --git a/contrib/llvm/utils/TableGen/EDEmitter.cpp b/contrib/llvm/utils/TableGen/EDEmitter.cpp index 0d5ee40..c5ee828 100644 --- a/contrib/llvm/utils/TableGen/EDEmitter.cpp +++ b/contrib/llvm/utils/TableGen/EDEmitter.cpp @@ -306,6 +306,7 @@ static int X86TypeFromOpName(LiteralConstantEmitter *type, REG("RFP64"); REG("RFP80"); REG("VR128"); + REG("VR256"); REG("RST"); REG("SEGMENT_REG"); REG("DEBUG_REG"); @@ -339,6 +340,7 @@ static int X86TypeFromOpName(LiteralConstantEmitter *type, MEM("opaque80mem"); MEM("i128mem"); MEM("f128mem"); + MEM("f256mem"); MEM("opaque512mem"); // all R, I, R, I @@ -347,6 +349,7 @@ static int X86TypeFromOpName(LiteralConstantEmitter *type, LEA("lea64mem"); // all I + PCR("i16imm_pcrel"); PCR("i32imm_pcrel"); PCR("i64i32imm_pcrel"); PCR("brtarget8"); @@ -500,6 +503,8 @@ static void X86ExtractSemantics( // TODO add support for fixed operands } else if (name.find("F") != name.npos) { // ignore (this pushes onto the FP stack) + } else if (name.find("A") != name.npos) { + // ignore (pushes all GP registoers onto the stack) } else if (name[name.length() - 1] == 'm') { PUSH("src"); } else if (name.find("i") != name.npos) { @@ -518,6 +523,8 @@ static void X86ExtractSemantics( // TODO add support for fixed operands } else if (name.find("F") != name.npos) { // ignore (this pops from the FP stack) + } else if (name.find("A") != name.npos) { + // ignore (pushes all GP registoers onto the stack) } else if (name[name.length() - 1] == 'm') { POP("dst"); } else { @@ -570,6 +577,7 @@ static void X86ExtractSemantics( static int ARMFlagFromOpName(LiteralConstantEmitter *type, const std::string &name) { REG("GPR"); + REG("tcGPR"); REG("cc_out"); REG("s_cc_out"); REG("tGPR"); @@ -592,10 +600,7 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type, IMM("msr_mask"); IMM("neg_zero"); IMM("imm0_31"); - IMM("h8imm"); - IMM("h16imm"); - IMM("h32imm"); - IMM("h64imm"); + IMM("nModImm"); IMM("imm0_4095"); IMM("jt2block_operand"); IMM("t_imm_s4"); diff --git a/contrib/llvm/utils/TableGen/FastISelEmitter.cpp b/contrib/llvm/utils/TableGen/FastISelEmitter.cpp index 9ec9e08..08fc139 100644 --- a/contrib/llvm/utils/TableGen/FastISelEmitter.cpp +++ b/contrib/llvm/utils/TableGen/FastISelEmitter.cpp @@ -54,15 +54,15 @@ struct OperandsSignature { bool initialize(TreePatternNode *InstPatNode, const CodeGenTarget &Target, MVT::SimpleValueType VT) { - if (!InstPatNode->isLeaf() && - InstPatNode->getOperator()->getName() == "imm") { - Operands.push_back("i"); - return true; - } - if (!InstPatNode->isLeaf() && - InstPatNode->getOperator()->getName() == "fpimm") { - Operands.push_back("f"); - return true; + if (!InstPatNode->isLeaf()) { + if (InstPatNode->getOperator()->getName() == "imm") { + Operands.push_back("i"); + return true; + } + if (InstPatNode->getOperator()->getName() == "fpimm") { + Operands.push_back("f"); + return true; + } } const CodeGenRegisterClass *DstRC = 0; @@ -432,11 +432,9 @@ void FastISelMap::PrintFunctionDefinitions(raw_ostream &OS) { for (unsigned i = 0; i < Memo.PhysRegs->size(); ++i) { if ((*Memo.PhysRegs)[i] != "") - OS << " TII.copyRegToReg(*MBB, MBB->end(), " - << (*Memo.PhysRegs)[i] << ", Op" << i << ", " - << "TM.getRegisterInfo()->getPhysicalRegisterRegClass(" - << (*Memo.PhysRegs)[i] << "), " - << "MRI.getRegClass(Op" << i << "), DL);\n"; + OS << " BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, " + << "TII.get(TargetOpcode::COPY), " + << (*Memo.PhysRegs)[i] << ").addReg(Op" << i << ");\n"; } OS << " return FastEmitInst_"; @@ -524,14 +522,12 @@ void FastISelMap::PrintFunctionDefinitions(raw_ostream &OS) { HasPred = true; } - for (unsigned i = 0; i < Memo.PhysRegs->size(); ++i) { - if ((*Memo.PhysRegs)[i] != "") - OS << " TII.copyRegToReg(*MBB, MBB->end(), " - << (*Memo.PhysRegs)[i] << ", Op" << i << ", " - << "TM.getRegisterInfo()->getPhysicalRegisterRegClass(" - << (*Memo.PhysRegs)[i] << "), " - << "MRI.getRegClass(Op" << i << "), DL);\n"; - } + for (unsigned i = 0; i < Memo.PhysRegs->size(); ++i) { + if ((*Memo.PhysRegs)[i] != "") + OS << " BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, " + << "TII.get(TargetOpcode::COPY), " + << (*Memo.PhysRegs)[i] << ").addReg(Op" << i << ");\n"; + } OS << " return FastEmitInst_"; diff --git a/contrib/llvm/utils/TableGen/InstrInfoEmitter.cpp b/contrib/llvm/utils/TableGen/InstrInfoEmitter.cpp index 006a2a1..f28af15 100644 --- a/contrib/llvm/utils/TableGen/InstrInfoEmitter.cpp +++ b/contrib/llvm/utils/TableGen/InstrInfoEmitter.cpp @@ -92,7 +92,8 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) { else if (OpR->isSubClassOf("PointerLikeRegClass")) Res += utostr(OpR->getValueAsInt("RegClassKind")) + ", "; else - Res += "0, "; + // -1 means the operand does not have a fixed register class. + Res += "-1, "; // Fill in applicable flags. Res += "0"; @@ -301,7 +302,7 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, } OS << ", 0x"; OS.write_hex(Value); - OS << ", "; + OS << "ULL, "; // Emit the implicit uses and defs lists... std::vector<Record*> UseList = Inst.TheDef->getValueAsListOfDefs("Uses"); diff --git a/contrib/llvm/utils/TableGen/NeonEmitter.cpp b/contrib/llvm/utils/TableGen/NeonEmitter.cpp new file mode 100644 index 0000000..3516d31 --- /dev/null +++ b/contrib/llvm/utils/TableGen/NeonEmitter.cpp @@ -0,0 +1,1202 @@ +//===- 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. +// +//===----------------------------------------------------------------------===// + +#include "NeonEmitter.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.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)); + break; + } + 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'; + default: throw "unhandled type in widen!"; + } + return '\0'; +} + +/// 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 widen!"; + } + return '\0'; +} + +/// 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; + case 'x': + poly = false; + if (type == 'f') + type = 'i'; + break; + case 'f': + if (type == 'h') + quad = true; + type = 'f'; + usgn = false; + break; + case 'w': + type = Widen(type); + quad = true; + break; + case 'n': + type = Widen(type); + 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. If generic is true, emit the generic vector type rather than +/// the public NEON type. QUc -> uint8x8_t / __neon_uint8x8_t. +static std::string TypeString(const char mod, StringRef typestr, + bool generic = false) { + 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 (generic) + s += "__neon_"; + + 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!"; + break; + } + + 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"; + if (mod == 'i') + return "i"; + + // 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); + + if (pntr) { + usgn = false; + poly = false; + type = 'v'; + } + 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'); + + if (type == 'l') + 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 == '3' || mod == '4') + return "vv*"; + 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 ? "V16c" : "V8c"; + } + + // Non-return array types are passed as individual vectors. + if (mod == '2') + return quad ? "V16cV16c" : "V8cV8c"; + if (mod == '3') + return quad ? "V16cV16cV16c" : "V8cV8cV8c"; + if (mod == '4') + return quad ? "V16cV16cV16cV16c" : "V8cV8cV8cV8c"; + + 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 ? "V16c" : "V8c"; +} + +/// StructTag - generate the name of the struct tag for a type. +/// These names are mandated by ARM's ABI. +static std::string StructTag(StringRef typestr) { + bool quad = false; + bool poly = false; + bool usgn = false; + + // base type to get the type string for. + char type = ClassifyType(typestr, quad, poly, usgn); + + SmallString<128> s; + s += "__simd"; + s += quad ? "128_" : "64_"; + if (usgn) + s.push_back('u'); + + switch (type) { + case 'c': + s += poly ? "poly8" : "int8"; + break; + case 's': + s += poly ? "poly16" : "int16"; + break; + case 'i': + s += "int32"; + break; + case 'l': + s += "int64"; + break; + case 'h': + s += "float16"; + break; + case 'f': + s += "float32"; + break; + default: + throw "unhandled type!"; + break; + } + + // Append _t, finishing the struct tag name. + s += "_t"; + + return s.str(); +} + +/// 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!"; + break; + } + 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; +} + +// Generate the string "(argtype a, argtype b, ...)" +static std::string GenArgs(const std::string &proto, StringRef typestr) { + bool define = proto.find('i') != std::string::npos; + char arg = 'a'; + + std::string s; + s += "("; + + for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { + if (!define) { + s += TypeString(proto[i], typestr); + s.push_back(' '); + } + s.push_back(arg); + if ((i + 1) < e) + s += ", "; + } + + s += ")"; + return s; +} + +static std::string Duplicate(unsigned nElts, StringRef typestr, + const std::string &a) { + std::string s; + + s = "(__neon_" + TypeString('d', typestr) + "){ "; + for (unsigned i = 0; i != nElts; ++i) { + s += a; + if ((i + 1) < nElts) + s += ", "; + } + s += " }"; + + return s; +} + +// Generate the definition for this intrinsic, e.g. "a + b" for OpAdd. +// If structTypes is true, the NEON types are structs of vector types rather +// than vector types, and the call becomes "a.val + b.val" +static std::string GenOpString(OpKind op, const std::string &proto, + StringRef typestr, bool structTypes = true) { + bool dummy, quad = 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; + } + + std::string ts = TypeString(proto[0], typestr); + std::string s = ts + " r; r"; + + if (structTypes) + s += ".val"; + + s += " = "; + + std::string a, b, c; + if (proto.size() > 1) + a = (structTypes && proto[1] != 'l' && proto[1] != 's') ? "a.val" : "a"; + b = structTypes ? "b.val" : "b"; + c = structTypes ? "c.val" : "c"; + + switch(op) { + case OpAdd: + s += a + " + " + b; + break; + case OpSub: + s += a + " - " + b; + break; + case OpMulN: + b = Duplicate(nElts << (int)quad, typestr, "b"); + case OpMul: + s += a + " * " + b; + break; + case OpMlaN: + c = Duplicate(nElts << (int)quad, typestr, "c"); + case OpMla: + s += a + " + ( " + b + " * " + c + " )"; + break; + case OpMlsN: + c = Duplicate(nElts << (int)quad, typestr, "c"); + case OpMls: + s += a + " - ( " + b + " * " + c + " )"; + break; + case OpEq: + s += "(__neon_" + ts + ")(" + a + " == " + b + ")"; + break; + case OpGe: + s += "(__neon_" + ts + ")(" + a + " >= " + b + ")"; + break; + case OpLe: + s += "(__neon_" + ts + ")(" + a + " <= " + b + ")"; + break; + case OpGt: + s += "(__neon_" + ts + ")(" + a + " > " + b + ")"; + break; + case OpLt: + s += "(__neon_" + 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 += "(__neon_" + ts + ")" + a; + break; + case OpConcat: + s += "__builtin_shufflevector((__neon_int64x1_t)" + a; + s += ", (__neon_int64x1_t)" + b + ", 0, 1)"; + break; + case OpHi: + s += "(__neon_int64x1_t)(((__neon_int64x2_t)" + a + ")[1])"; + break; + case OpLo: + s += "(__neon_int64x1_t)(((__neon_int64x2_t)" + a + ")[0])"; + break; + case OpDup: + s += Duplicate(nElts << (int)quad, typestr, a); + break; + case OpSelect: + // ((0 & 1) | (~0 & 2)) + ts = TypeString(proto[1], typestr); + s += "( " + a + " & (__neon_" + ts + ")" + b + ") | "; + s += "(~" + a + " & (__neon_" + ts + ")" + c + ")"; + break; + case OpRev16: + s += "__builtin_shufflevector(" + a + ", " + a; + for (unsigned i = 2; i <= nElts << (int)quad; i += 2) + for (unsigned j = 0; j != 2; ++j) + s += ", " + utostr(i - j - 1); + s += ")"; + break; + case OpRev32: + nElts >>= 1; + s += "__builtin_shufflevector(" + a + ", " + a; + for (unsigned i = nElts; i <= nElts << (1 + (int)quad); i += nElts) + for (unsigned j = 0; j != nElts; ++j) + s += ", " + utostr(i - j - 1); + s += ")"; + break; + case OpRev64: + s += "__builtin_shufflevector(" + a + ", " + a; + for (unsigned i = nElts; i <= nElts << (int)quad; i += nElts) + for (unsigned j = 0; j != nElts; ++j) + s += ", " + utostr(i - j - 1); + s += ")"; + break; + default: + throw "unknown OpKind!"; + break; + } + s += "; return r;"; + return s; +} + +static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) { + unsigned mod = proto[0]; + unsigned ret = 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); + + if (usgn) + ret |= 0x08; + if (quad) + ret |= 0x10; + + switch (type) { + case 'c': + ret |= poly ? 5 : 0; + break; + case 's': + ret |= poly ? 6 : 1; + break; + case 'i': + ret |= 2; + break; + case 'l': + ret |= 3; + break; + case 'h': + ret |= 7; + break; + case 'f': + ret |= 4; + break; + default: + throw "unhandled type!"; + break; + } + return ret; +} + +// Generate the definition for this intrinsic, e.g. __builtin_neon_cls(a) +// If structTypes is true, the NEON types are structs of vector types rather +// than vector types, and the call becomes __builtin_neon_cls(a.val) +static std::string GenBuiltin(const std::string &name, const std::string &proto, + StringRef typestr, ClassKind ck, + bool structTypes = true) { + bool dummy, quad = 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; + } + if (quad) nElts <<= 1; + + char arg = 'a'; + 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] == '3' || proto[0] == '4'); + + // 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. + bool define = proto.find('i') != std::string::npos; + + // 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; + + if (proto[0] != 'v') { + std::string ts = TypeString(proto[0], typestr); + + if (define) { + if (sret) + s += "({ " + ts + " r; "; + else if (proto[0] != 's') + s += "(" + ts + "){(__neon_" + ts + ")"; + } else if (sret) { + s += ts + " r; "; + } else { + s += ts + " r; r"; + if (structTypes && proto[0] != 's' && proto[0] != 'i' && proto[0] != 'l') + s += ".val"; + + s += " = "; + } + } + + bool splat = proto.find('a') != std::string::npos; + + s += "__builtin_neon_"; + if (splat) { + 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, "; + + for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { + std::string args = std::string(&arg, 1); + if (define) + args = "(" + args + ")"; + + // Handle multiple-vector values specially, emitting each subvector as an + // argument to the __builtin. + if (structTypes && (proto[i] == '2' || proto[i] == '3' || proto[i] == '4')){ + for (unsigned vi = 0, ve = proto[i] - '0'; vi != ve; ++vi) { + s += args + ".val[" + utostr(vi) + "].val"; + if ((vi + 1) < ve) + s += ", "; + } + if ((i + 1) < e) + s += ", "; + + continue; + } + + if (splat && (i + 1) == e) + s += Duplicate(nElts, typestr, args); + else + s += args; + + if (structTypes && proto[i] != 's' && proto[i] != 'i' && proto[i] != 'l' && + proto[i] != 'p' && proto[i] != 'c' && proto[i] != 'a') { + s += ".val"; + } + 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)); + + if (define) + s += ")"; + else + s += ");"; + + if (proto[0] != 'v') { + if (define) { + if (sret) + s += "; r; })"; + else if (proto[0] != 's') + s += "}"; + } 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; +} + +/// 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) { + EmitSourceFileHeader("ARM NEON Header", OS); + + // FIXME: emit license into file? + + 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 uint8_t poly8_t;\n"; + OS << "typedef uint16_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 v = 1; v != 5; ++v) { + for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) { + bool dummy, quad = false; + (void) ClassifyType(TDTypeVec[i], quad, dummy, dummy); + OS << "typedef __attribute__(( __vector_size__("; + + OS << utostr(8*v*(quad ? 2 : 1)) << ") )) "; + if (!quad) + OS << " "; + + OS << TypeString('s', TDTypeVec[i]); + OS << " __neon_"; + + char t = (v == 1) ? 'd' : '0' + v; + OS << TypeString(t, TDTypeVec[i]) << ";\n"; + } + } + OS << "\n"; + + // Emit struct typedefs. + for (unsigned vi = 1; vi != 5; ++vi) { + for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) { + std::string ts = TypeString('d', TDTypeVec[i], vi == 1); + std::string vs = TypeString((vi > 1) ? '0' + vi : 'd', TDTypeVec[i]); + std::string tag = (vi > 1) ? vs : StructTag(TDTypeVec[i]); + OS << "typedef struct " << tag << " {\n"; + OS << " " << ts << " val"; + if (vi > 1) + OS << "[" << utostr(vi) << "]"; + OS << ";\n} " << vs << ";\n\n"; + } + } + + OS << "#define __ai static __attribute__((__always_inline__))\n\n"; + + std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst"); + + // Unique the return+pattern types, and assign them. + for (unsigned i = 0, e = RV.size(); i != e; ++i) { + Record *R = RV[i]; + std::string name = LowercaseString(R->getName()); + std::string Proto = R->getValueAsString("Prototype"); + std::string Types = R->getValueAsString("Types"); + + SmallVector<StringRef, 16> TypeVec; + ParseTypes(R, Types, TypeVec); + + OpKind k = OpMap[R->getValueAsDef("Operand")->getName()]; + + bool define = Proto.find('i') != std::string::npos; + + for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { + assert(!Proto.empty() && ""); + + // static always inline + return type + if (define) + OS << "#define"; + else + OS << "__ai " << TypeString(Proto[0], TypeVec[ti]); + + // Function name with type suffix + OS << " " << MangleName(name, TypeVec[ti], ClassS); + + // Function arguments + OS << GenArgs(Proto, TypeVec[ti]); + + // Definition. + if (define) + OS << " "; + else + OS << " { "; + + if (k != OpNone) { + OS << GenOpString(k, Proto, TypeVec[ti]); + } else { + if (R->getSuperClasses().size() < 2) + throw TGError(R->getLoc(), "Builtin has no class kind"); + + ClassKind ck = ClassMap[R->getSuperClasses()[1]]; + + if (ck == ClassNone) + throw TGError(R->getLoc(), "Builtin has no class kind"); + OS << GenBuiltin(name, Proto, TypeVec[ti], ck); + } + if (!define) + OS << " }"; + OS << "\n"; + } + OS << "\n"; + } + OS << "#undef __ai\n\n"; + OS << "#endif /* __ARM_NEON_H */\n"; +} + +static unsigned RangeFromType(StringRef typestr) { + // base type to get the type string for. + bool quad = false, dummy = false; + char type = ClassifyType(typestr, quad, 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!"; + break; + } +} + +/// 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 = LowercaseString(R->getName()); + 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 = LowercaseString(R->getName()); + + // 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]); + } + } + if (mask) + OS << "case ARM::BI__builtin_neon_" + << MangleName(name, TypeVec[si], ClassB) + << ": mask = " << "0x" << utohexstr(mask) << "; break;\n"; + if (qmask) + OS << "case ARM::BI__builtin_neon_" + << MangleName(name, TypeVec[qi], ClassB) + << ": mask = " << "0x" << utohexstr(qmask) << "; 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 = LowercaseString(R->getName()); + 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. + if (Proto.find('i') == 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; + + // Builtins which are overloaded by type will need to have their upper + // bound computed at Sema time based on the type constant. + if (Proto.find('s') == std::string::npos) { + 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 { + rangestr = "u = " + utostr(RangeFromType(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] == '3' || 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"; +} diff --git a/contrib/llvm/utils/TableGen/NeonEmitter.h b/contrib/llvm/utils/TableGen/NeonEmitter.h new file mode 100644 index 0000000..6c6760d --- /dev/null +++ b/contrib/llvm/utils/TableGen/NeonEmitter.h @@ -0,0 +1,122 @@ +//===- 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 "Record.h" +#include "TableGenBackend.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringMap.h" + +enum OpKind { + OpNone, + OpAdd, + OpSub, + OpMul, + OpMla, + OpMls, + OpMulN, + OpMlaN, + OpMlsN, + OpEq, + OpGe, + OpLe, + OpGt, + OpLt, + OpNeg, + OpNot, + OpAnd, + OpOr, + OpXor, + OpAndNot, + OpOrNot, + OpCast, + OpConcat, + OpDup, + OpHi, + OpLo, + OpSelect, + OpRev16, + OpRev32, + OpRev64 +}; + +enum ClassKind { + ClassNone, + ClassI, + ClassS, + ClassW, + ClassB +}; + +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_SUB"] = OpSub; + OpMap["OP_MUL"] = OpMul; + OpMap["OP_MLA"] = OpMla; + OpMap["OP_MLS"] = OpMls; + OpMap["OP_MUL_N"] = OpMulN; + OpMap["OP_MLA_N"] = OpMlaN; + OpMap["OP_MLS_N"] = OpMlsN; + 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_SEL"] = OpSelect; + OpMap["OP_REV16"] = OpRev16; + OpMap["OP_REV32"] = OpRev32; + OpMap["OP_REV64"] = OpRev64; + + 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); + }; + +} // End llvm namespace + +#endif diff --git a/contrib/llvm/utils/TableGen/Record.cpp b/contrib/llvm/utils/TableGen/Record.cpp index 4f9f604..d2cf379 100644 --- a/contrib/llvm/utils/TableGen/Record.cpp +++ b/contrib/llvm/utils/TableGen/Record.cpp @@ -270,7 +270,15 @@ Init *RecordRecTy::convertValue(TypedInit *TI) { } bool RecordRecTy::baseClassOf(const RecordRecTy *RHS) const { - return Rec == RHS->getRecord() || RHS->getRecord()->isSubClassOf(Rec); + if (Rec == RHS->getRecord() || RHS->getRecord()->isSubClassOf(Rec)) + return true; + + const std::vector<Record*> &SC = Rec->getSuperClasses(); + for (unsigned i = 0, e = SC.size(); i != e; ++i) + if (RHS->getRecord()->isSubClassOf(SC[i])) + return true; + + return false; } @@ -721,9 +729,20 @@ Init *BinOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) { break; } case EQ: { - // Make sure we've resolved + // try to fold eq comparison for 'bit' and 'int', otherwise fallback + // to string objects. + IntInit* L = + dynamic_cast<IntInit*>(LHS->convertInitializerTo(new IntRecTy())); + IntInit* R = + dynamic_cast<IntInit*>(RHS->convertInitializerTo(new IntRecTy())); + + if (L && R) + return new IntInit(L->getValue() == R->getValue()); + StringInit *LHSs = dynamic_cast<StringInit*>(LHS); StringInit *RHSs = dynamic_cast<StringInit*>(RHS); + + // Make sure we've resolved if (LHSs && RHSs) return new IntInit(LHSs->getValue() == RHSs->getValue()); @@ -971,6 +990,8 @@ Init *TernOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) { case IF: { IntInit *LHSi = dynamic_cast<IntInit*>(LHS); + if (Init *I = LHS->convertInitializerTo(new IntRecTy())) + LHSi = dynamic_cast<IntInit*>(I); if (LHSi) { if (LHSi->getValue()) { return MHS; @@ -990,6 +1011,8 @@ Init *TernOpInit::resolveReferences(Record &R, const RecordVal *RV) { if (Opc == IF && lhs != LHS) { IntInit *Value = dynamic_cast<IntInit*>(lhs); + if (Init *I = lhs->convertInitializerTo(new IntRecTy())) + Value = dynamic_cast<IntInit*>(I); if (Value != 0) { // Short-circuit if (Value->getValue()) { @@ -1239,7 +1262,7 @@ Init *DagInit::resolveReferences(Record &R, const RecordVal *RV) { Init *Op = Val->resolveReferences(R, RV); if (Args != NewArgs || Op != Val) - return new DagInit(Op, "", NewArgs, ArgNames); + return new DagInit(Op, ValName, NewArgs, ArgNames); return this; } diff --git a/contrib/llvm/utils/TableGen/RegisterInfoEmitter.cpp b/contrib/llvm/utils/TableGen/RegisterInfoEmitter.cpp index c99bbd9..a3ca0bc 100644 --- a/contrib/llvm/utils/TableGen/RegisterInfoEmitter.cpp +++ b/contrib/llvm/utils/TableGen/RegisterInfoEmitter.cpp @@ -82,6 +82,7 @@ void RegisterInfoEmitter::runHeader(raw_ostream &OS) { << " { return false; }\n" << " unsigned getSubReg(unsigned RegNo, unsigned Index) const;\n" << " unsigned getSubRegIndex(unsigned RegNo, unsigned SubRegNo) const;\n" + << " unsigned composeSubRegIndices(unsigned, unsigned) const;\n" << "};\n\n"; const std::vector<CodeGenRegisterClass> &RegisterClasses = @@ -95,7 +96,7 @@ void RegisterInfoEmitter::runHeader(raw_ostream &OS) { for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i) { if (i) OS << ",\n"; OS << " " << RegisterClasses[i].getName() << "RegClassID"; - OS << " = " << (i+1); + OS << " = " << i; } OS << "\n };\n\n"; @@ -171,14 +172,28 @@ static void addSubSuperReg(Record *R, Record *S, addSubSuperReg(R, *I, SubRegs, SuperRegs, Aliases); } -// Map SubRegIndex -> Register -typedef std::map<Record*, Record*, LessRecord> SubRegMap; -// Map Register -> SubRegMap -typedef std::map<Record*, SubRegMap> AllSubRegMap; +struct RegisterMaps { + // Map SubRegIndex -> Register + typedef std::map<Record*, Record*, LessRecord> SubRegMap; + // Map Register -> SubRegMap + typedef std::map<Record*, SubRegMap> SubRegMaps; + + SubRegMaps SubReg; + SubRegMap &inferSubRegIndices(Record *Reg); + + // Composite SubRegIndex instances. + // Map (SubRegIndex,SubRegIndex) -> SubRegIndex + typedef DenseMap<std::pair<Record*,Record*>,Record*> CompositeMap; + CompositeMap Composite; + + // Compute SubRegIndex compositions after inferSubRegIndices has run on all + // registers. + void computeComposites(); +}; // Calculate all subregindices for Reg. Loopy subregs cause infinite recursion. -static SubRegMap &inferSubRegIndices(Record *Reg, AllSubRegMap &ASRM) { - SubRegMap &SRM = ASRM[Reg]; +RegisterMaps::SubRegMap &RegisterMaps::inferSubRegIndices(Record *Reg) { + SubRegMap &SRM = SubReg[Reg]; if (!SRM.empty()) return SRM; std::vector<Record*> SubRegs = Reg->getValueAsListOfDefs("SubRegs"); @@ -191,7 +206,7 @@ static SubRegMap &inferSubRegIndices(Record *Reg, AllSubRegMap &ASRM) { if (!SRM.insert(std::make_pair(Indices[i], SubRegs[i])).second) throw "SubRegIndex " + Indices[i]->getName() + " appears twice in Register " + Reg->getName(); - inferSubRegIndices(SubRegs[i], ASRM); + inferSubRegIndices(SubRegs[i]); } // Keep track of inherited subregs and how they can be reached. @@ -202,7 +217,7 @@ static SubRegMap &inferSubRegIndices(Record *Reg, AllSubRegMap &ASRM) { // Clone inherited subregs. Here the order is important - earlier subregs take // precedence. for (unsigned i = 0, e = SubRegs.size(); i != e; ++i) { - SubRegMap &M = ASRM[SubRegs[i]]; + SubRegMap &M = SubReg[SubRegs[i]]; for (SubRegMap::iterator si = M.begin(), se = M.end(); si != se; ++si) if (!SRM.insert(*si).second) Orphans[si->second] = std::make_pair(Indices[i], si->first); @@ -226,8 +241,8 @@ static SubRegMap &inferSubRegIndices(Record *Reg, AllSubRegMap &ASRM) { DefInit *IdxInit = dynamic_cast<DefInit*>(*di); if (!IdxInit || !IdxInit->getDef()->isSubClassOf("SubRegIndex")) throw "Invalid SubClassIndex in " + Pat->getAsString(); - SubRegMap::const_iterator ni = ASRM[R2].find(IdxInit->getDef()); - if (ni == ASRM[R2].end()) + SubRegMap::const_iterator ni = SubReg[R2].find(IdxInit->getDef()); + if (ni == SubReg[R2].end()) throw "Composite " + Pat->getAsString() + " refers to bad index in " + R2->getName(); R2 = ni->second; @@ -255,6 +270,62 @@ static SubRegMap &inferSubRegIndices(Record *Reg, AllSubRegMap &ASRM) { return SRM; } +void RegisterMaps::computeComposites() { + for (SubRegMaps::const_iterator sri = SubReg.begin(), sre = SubReg.end(); + sri != sre; ++sri) { + Record *Reg1 = sri->first; + const SubRegMap &SRM1 = sri->second; + for (SubRegMap::const_iterator i1 = SRM1.begin(), e1 = SRM1.end(); + i1 != e1; ++i1) { + Record *Idx1 = i1->first; + Record *Reg2 = i1->second; + // Ignore identity compositions. + if (Reg1 == Reg2) + continue; + // If Reg2 has no subregs, Idx1 doesn't compose. + if (!SubReg.count(Reg2)) + continue; + const SubRegMap &SRM2 = SubReg[Reg2]; + // Try composing Idx1 with another SubRegIndex. + for (SubRegMap::const_iterator i2 = SRM2.begin(), e2 = SRM2.end(); + i2 != e2; ++i2) { + std::pair<Record*,Record*> IdxPair(Idx1, i2->first); + Record *Reg3 = i2->second; + // OK Reg1:IdxPair == Reg3. Find the index with Reg:Idx == Reg3. + for (SubRegMap::const_iterator i1d = SRM1.begin(), e1d = SRM1.end(); + i1d != e1d; ++i1d) { + // Ignore identity compositions. + if (Reg2 == Reg3) + continue; + if (i1d->second == Reg3) { + std::pair<CompositeMap::iterator,bool> Ins = + Composite.insert(std::make_pair(IdxPair, i1d->first)); + // Conflicting composition? + if (!Ins.second && Ins.first->second != i1d->first) { + errs() << "Error: SubRegIndex " << getQualifiedName(Idx1) + << " and " << getQualifiedName(IdxPair.second) + << " compose ambiguously as " + << getQualifiedName(Ins.first->second) << " or " + << getQualifiedName(i1d->first) << "\n"; + abort(); + } + } + } + } + } + } + + // We don't care about the difference between (Idx1, Idx2) -> Idx2 and invalid + // compositions, so remove any mappings of that form. + for (CompositeMap::iterator i = Composite.begin(), e = Composite.end(); + i != e;) { + CompositeMap::iterator j = i; + ++i; + if (j->first.second == j->second) + Composite.erase(j); + } +} + class RegisterSorter { private: std::map<Record*, std::set<Record*>, LessRecord> &RegisterSubRegs; @@ -836,7 +907,7 @@ void RegisterInfoEmitter::run(raw_ostream &OS) { std::string ClassName = Target.getName() + "GenRegisterInfo"; // Calculate the mapping of subregister+index pairs to physical registers. - AllSubRegMap AllSRM; + RegisterMaps RegMaps; // Emit the subregister + index mapping function based on the information // calculated above. @@ -845,14 +916,14 @@ void RegisterInfoEmitter::run(raw_ostream &OS) { << " switch (RegNo) {\n" << " default:\n return 0;\n"; for (unsigned i = 0, e = Regs.size(); i != e; ++i) { - SubRegMap &SRM = inferSubRegIndices(Regs[i].TheDef, AllSRM); + RegisterMaps::SubRegMap &SRM = RegMaps.inferSubRegIndices(Regs[i].TheDef); if (SRM.empty()) continue; OS << " case " << getQualifiedName(Regs[i].TheDef) << ":\n"; OS << " switch (Index) {\n"; OS << " default: return 0;\n"; - for (SubRegMap::const_iterator ii = SRM.begin(), ie = SRM.end(); ii != ie; - ++ii) + for (RegisterMaps::SubRegMap::const_iterator ii = SRM.begin(), + ie = SRM.end(); ii != ie; ++ii) OS << " case " << getQualifiedName(ii->first) << ": return " << getQualifiedName(ii->second) << ";\n"; OS << " };\n" << " break;\n"; @@ -866,12 +937,12 @@ void RegisterInfoEmitter::run(raw_ostream &OS) { << " switch (RegNo) {\n" << " default:\n return 0;\n"; for (unsigned i = 0, e = Regs.size(); i != e; ++i) { - SubRegMap &SRM = AllSRM[Regs[i].TheDef]; + RegisterMaps::SubRegMap &SRM = RegMaps.SubReg[Regs[i].TheDef]; if (SRM.empty()) continue; OS << " case " << getQualifiedName(Regs[i].TheDef) << ":\n"; - for (SubRegMap::const_iterator ii = SRM.begin(), ie = SRM.end(); ii != ie; - ++ii) + for (RegisterMaps::SubRegMap::const_iterator ii = SRM.begin(), + ie = SRM.end(); ii != ie; ++ii) OS << " if (SubRegNo == " << getQualifiedName(ii->second) << ") return " << getQualifiedName(ii->first) << ";\n"; OS << " return 0;\n"; @@ -879,7 +950,32 @@ void RegisterInfoEmitter::run(raw_ostream &OS) { OS << " };\n"; OS << " return 0;\n"; OS << "}\n\n"; - + + // Emit composeSubRegIndices + RegMaps.computeComposites(); + OS << "unsigned " << ClassName + << "::composeSubRegIndices(unsigned IdxA, unsigned IdxB) const {\n" + << " switch (IdxA) {\n" + << " default:\n return IdxB;\n"; + for (unsigned i = 0, e = SubRegIndices.size(); i != e; ++i) { + bool Open = false; + for (unsigned j = 0; j != e; ++j) { + if (Record *Comp = RegMaps.Composite.lookup( + std::make_pair(SubRegIndices[i], SubRegIndices[j]))) { + if (!Open) { + OS << " case " << getQualifiedName(SubRegIndices[i]) + << ": switch(IdxB) {\n default: return IdxB;\n"; + Open = true; + } + OS << " case " << getQualifiedName(SubRegIndices[j]) + << ": return " << getQualifiedName(Comp) << ";\n"; + } + } + if (Open) + OS << " }\n"; + } + OS << " }\n}\n\n"; + // Emit the constructor of the class... OS << ClassName << "::" << ClassName << "(int CallFrameSetupOpcode, int CallFrameDestroyOpcode)\n" diff --git a/contrib/llvm/utils/TableGen/TGParser.cpp b/contrib/llvm/utils/TableGen/TGParser.cpp index 8c158e0..f81aabe 100644 --- a/contrib/llvm/utils/TableGen/TGParser.cpp +++ b/contrib/llvm/utils/TableGen/TGParser.cpp @@ -1635,13 +1635,12 @@ bool TGParser::ParseObjectBody(Record *CurRec) { return ParseBody(CurRec); } - /// ParseDef - Parse and return a top level or multiclass def, return the record /// corresponding to it. This returns null on error. /// /// DefInst ::= DEF ObjectName ObjectBody /// -llvm::Record *TGParser::ParseDef(MultiClass *CurMultiClass) { +bool TGParser::ParseDef(MultiClass *CurMultiClass) { SMLoc DefLoc = Lex.getLoc(); assert(Lex.getCode() == tgtok::Def && "Unknown tok"); Lex.Lex(); // Eat the 'def' token. @@ -1655,7 +1654,7 @@ llvm::Record *TGParser::ParseDef(MultiClass *CurMultiClass) { // Ensure redefinition doesn't happen. if (Records.getDef(CurRec->getName())) { Error(DefLoc, "def '" + CurRec->getName() + "' already defined"); - return 0; + return true; } Records.addDef(CurRec); } else { @@ -1664,20 +1663,33 @@ llvm::Record *TGParser::ParseDef(MultiClass *CurMultiClass) { if (CurMultiClass->DefPrototypes[i]->getName() == CurRec->getName()) { Error(DefLoc, "def '" + CurRec->getName() + "' already defined in this multiclass!"); - return 0; + return true; } CurMultiClass->DefPrototypes.push_back(CurRec); } if (ParseObjectBody(CurRec)) - return 0; + return true; if (CurMultiClass == 0) // Def's in multiclasses aren't really defs. CurRec->resolveReferences(); // If ObjectBody has template arguments, it's an error. assert(CurRec->getTemplateArgs().empty() && "How'd this get template args?"); - return CurRec; + + if (CurMultiClass) { + // Copy the template arguments for the multiclass into the def. + const std::vector<std::string> &TArgs = + CurMultiClass->Rec.getTemplateArgs(); + + for (unsigned i = 0, e = TArgs.size(); i != e; ++i) { + const RecordVal *RV = CurMultiClass->Rec.getValue(TArgs[i]); + assert(RV && "Template arg doesn't exist?"); + CurRec->addValue(*RV); + } + } + + return false; } @@ -1758,12 +1770,12 @@ std::vector<LetRecord> TGParser::ParseLetList() { } /// ParseTopLevelLet - Parse a 'let' at top level. This can be a couple of -/// different related productions. +/// different related productions. This works inside multiclasses too. /// /// Object ::= LET LetList IN '{' ObjectList '}' /// Object ::= LET LetList IN Object /// -bool TGParser::ParseTopLevelLet() { +bool TGParser::ParseTopLevelLet(MultiClass *CurMultiClass) { assert(Lex.getCode() == tgtok::Let && "Unexpected token"); Lex.Lex(); @@ -1779,7 +1791,7 @@ bool TGParser::ParseTopLevelLet() { // If this is a scalar let, just handle it now if (Lex.getCode() != tgtok::l_brace) { // LET LetList IN Object - if (ParseObject()) + if (ParseObject(CurMultiClass)) return true; } else { // Object ::= LETCommand '{' ObjectList '}' SMLoc BraceLoc = Lex.getLoc(); @@ -1787,7 +1799,7 @@ bool TGParser::ParseTopLevelLet() { Lex.Lex(); // eat the '{'. // Parse the object list. - if (ParseObjectList()) + if (ParseObjectList(CurMultiClass)) return true; if (Lex.getCode() != tgtok::r_brace) { @@ -1802,29 +1814,6 @@ bool TGParser::ParseTopLevelLet() { return false; } -/// ParseMultiClassDef - Parse a def in a multiclass context. -/// -/// MultiClassDef ::= DefInst -/// -bool TGParser::ParseMultiClassDef(MultiClass *CurMC) { - if (Lex.getCode() != tgtok::Def) - return TokError("expected 'def' in multiclass body"); - - Record *D = ParseDef(CurMC); - if (D == 0) return true; - - // Copy the template arguments for the multiclass into the def. - const std::vector<std::string> &TArgs = CurMC->Rec.getTemplateArgs(); - - for (unsigned i = 0, e = TArgs.size(); i != e; ++i) { - const RecordVal *RV = CurMC->Rec.getValue(TArgs[i]); - assert(RV && "Template arg doesn't exist?"); - D->addValue(*RV); - } - - return false; -} - /// ParseMultiClass - Parse a multiclass definition. /// /// MultiClassInst ::= MULTICLASS ID TemplateArgList? @@ -1885,10 +1874,18 @@ bool TGParser::ParseMultiClass() { if (Lex.Lex() == tgtok::r_brace) // eat the '{'. return TokError("multiclass must contain at least one def"); - while (Lex.getCode() != tgtok::r_brace) - if (ParseMultiClassDef(CurMultiClass)) - return true; - + while (Lex.getCode() != tgtok::r_brace) { + switch (Lex.getCode()) { + default: + return TokError("expected 'let', 'def' or 'defm' in multiclass body"); + case tgtok::Let: + case tgtok::Def: + case tgtok::Defm: + if (ParseObject(CurMultiClass)) + return true; + break; + } + } Lex.Lex(); // eat the '}'. } @@ -1900,7 +1897,7 @@ bool TGParser::ParseMultiClass() { /// /// DefMInst ::= DEFM ID ':' DefmSubClassRef ';' /// -bool TGParser::ParseDefm() { +bool TGParser::ParseDefm(MultiClass *CurMultiClass) { assert(Lex.getCode() == tgtok::Defm && "Unexpected token!"); if (Lex.Lex() != tgtok::Id) // eat the defm. return TokError("expected identifier after defm"); @@ -1910,6 +1907,12 @@ bool TGParser::ParseDefm() { if (Lex.Lex() != tgtok::colon) return TokError("expected ':' after defm identifier"); + // Keep track of the new generated record definitions. + std::vector<Record*> NewRecDefs; + + // This record also inherits from a regular class (non-multiclass)? + bool InheritFromClass = false; + // eat the colon. Lex.Lex(); @@ -1991,17 +1994,87 @@ bool TGParser::ParseDefm() { return Error(DefmPrefixLoc, "def '" + CurRec->getName() + "' already defined, instantiating defm with subdef '" + DefProto->getName() + "'"); - Records.addDef(CurRec); - CurRec->resolveReferences(); + + // Don't create a top level definition for defm inside multiclasses, + // instead, only update the prototypes and bind the template args + // with the new created definition. + if (CurMultiClass) { + for (unsigned i = 0, e = CurMultiClass->DefPrototypes.size(); + i != e; ++i) { + if (CurMultiClass->DefPrototypes[i]->getName() == CurRec->getName()) { + Error(DefmPrefixLoc, "defm '" + CurRec->getName() + + "' already defined in this multiclass!"); + return 0; + } + } + CurMultiClass->DefPrototypes.push_back(CurRec); + + // Copy the template arguments for the multiclass into the new def. + const std::vector<std::string> &TA = + CurMultiClass->Rec.getTemplateArgs(); + + for (unsigned i = 0, e = TA.size(); i != e; ++i) { + const RecordVal *RV = CurMultiClass->Rec.getValue(TA[i]); + assert(RV && "Template arg doesn't exist?"); + CurRec->addValue(*RV); + } + } else { + Records.addDef(CurRec); + } + + NewRecDefs.push_back(CurRec); } if (Lex.getCode() != tgtok::comma) break; Lex.Lex(); // eat ','. SubClassLoc = Lex.getLoc(); + + // A defm can inherit from regular classes (non-multiclass) as + // long as they come in the end of the inheritance list. + InheritFromClass = (Records.getClass(Lex.getCurStrVal()) != 0); + + if (InheritFromClass) + break; + Ref = ParseSubClassReference(0, true); } + if (InheritFromClass) { + // Process all the classes to inherit as if they were part of a + // regular 'def' and inherit all record values. + SubClassReference SubClass = ParseSubClassReference(0, false); + while (1) { + // Check for error. + if (SubClass.Rec == 0) return true; + + // Get the expanded definition prototypes and teach them about + // the record values the current class to inherit has + for (unsigned i = 0, e = NewRecDefs.size(); i != e; ++i) { + Record *CurRec = NewRecDefs[i]; + + // Add it. + if (AddSubClass(CurRec, SubClass)) + return true; + + // Process any variables on the let stack. + for (unsigned i = 0, e = LetStack.size(); i != e; ++i) + for (unsigned j = 0, e = LetStack[i].size(); j != e; ++j) + if (SetValue(CurRec, LetStack[i][j].Loc, LetStack[i][j].Name, + LetStack[i][j].Bits, LetStack[i][j].Value)) + return true; + } + + if (Lex.getCode() != tgtok::comma) break; + Lex.Lex(); // eat ','. + SubClass = ParseSubClassReference(0, false); + } + } + + if (!CurMultiClass) + for (unsigned i = 0, e = NewRecDefs.size(); i != e; ++i) + NewRecDefs[i]->resolveReferences(); + if (Lex.getCode() != tgtok::semi) return TokError("expected ';' at end of defm"); Lex.Lex(); @@ -2016,12 +2089,12 @@ bool TGParser::ParseDefm() { /// Object ::= DefMInst /// Object ::= LETCommand '{' ObjectList '}' /// Object ::= LETCommand Object -bool TGParser::ParseObject() { +bool TGParser::ParseObject(MultiClass *MC) { switch (Lex.getCode()) { default: assert(0 && "This is not an object"); - case tgtok::Let: return ParseTopLevelLet(); - case tgtok::Def: return ParseDef(0) == 0; - case tgtok::Defm: return ParseDefm(); + case tgtok::Let: return ParseTopLevelLet(MC); + case tgtok::Def: return ParseDef(MC); + case tgtok::Defm: return ParseDefm(MC); case tgtok::Class: return ParseClass(); case tgtok::MultiClass: return ParseMultiClass(); } @@ -2029,9 +2102,9 @@ bool TGParser::ParseObject() { /// ParseObjectList /// ObjectList :== Object* -bool TGParser::ParseObjectList() { +bool TGParser::ParseObjectList(MultiClass *MC) { while (isObjectStart(Lex.getCode())) { - if (ParseObject()) + if (ParseObject(MC)) return true; } return false; diff --git a/contrib/llvm/utils/TableGen/TGParser.h b/contrib/llvm/utils/TableGen/TGParser.h index 9f4b634..0aee931 100644 --- a/contrib/llvm/utils/TableGen/TGParser.h +++ b/contrib/llvm/utils/TableGen/TGParser.h @@ -69,16 +69,15 @@ private: // Semantic analysis methods. SubMultiClassReference &SubMultiClass); private: // Parser methods. - bool ParseObjectList(); - bool ParseObject(); + bool ParseObjectList(MultiClass *MC = 0); + bool ParseObject(MultiClass *MC); bool ParseClass(); bool ParseMultiClass(); - bool ParseMultiClassDef(MultiClass *CurMC); - bool ParseDefm(); - bool ParseTopLevelLet(); + bool ParseDefm(MultiClass *CurMultiClass); + bool ParseDef(MultiClass *CurMultiClass); + bool ParseTopLevelLet(MultiClass *CurMultiClass); std::vector<LetRecord> ParseLetList(); - Record *ParseDef(MultiClass *CurMultiClass); bool ParseObjectBody(Record *CurRec); bool ParseBody(Record *CurRec); bool ParseBodyItem(Record *CurRec); diff --git a/contrib/llvm/utils/TableGen/TableGen.cpp b/contrib/llvm/utils/TableGen/TableGen.cpp index 17435f6..7a4f74f 100644 --- a/contrib/llvm/utils/TableGen/TableGen.cpp +++ b/contrib/llvm/utils/TableGen/TableGen.cpp @@ -19,6 +19,7 @@ #include "AsmWriterEmitter.h" #include "CallingConvEmitter.h" #include "ClangASTNodesEmitter.h" +#include "ClangAttrEmitter.h" #include "ClangDiagnosticsEmitter.h" #include "CodeEmitterGen.h" #include "DAGISelEmitter.h" @@ -29,6 +30,7 @@ #include "InstrInfoEmitter.h" #include "IntrinsicEmitter.h" #include "LLVMCConfigurationEmitter.h" +#include "NeonEmitter.h" #include "OptParserEmitter.h" #include "Record.h" #include "RegisterInfoEmitter.h" @@ -52,8 +54,11 @@ enum ActionType { GenARMDecoder, GenDisassembler, GenCallingConv, + GenClangAttrClasses, + GenClangAttrList, GenClangDiagsDefs, GenClangDiagGroups, + GenClangDeclNodes, GenClangStmtNodes, GenDAGISel, GenFastISel, @@ -63,6 +68,8 @@ enum ActionType { GenTgtIntrinsic, GenLLVMCConf, GenEDHeader, GenEDInfo, + GenArmNeon, + GenArmNeonSema, PrintEnums }; @@ -107,10 +114,16 @@ namespace { "Generate intrinsic information"), clEnumValN(GenTgtIntrinsic, "gen-tgt-intrinsic", "Generate target intrinsic information"), + clEnumValN(GenClangAttrClasses, "gen-clang-attr-classes", + "Generate clang attribute clases"), + clEnumValN(GenClangAttrList, "gen-clang-attr-list", + "Generate a clang attribute list"), clEnumValN(GenClangDiagsDefs, "gen-clang-diags-defs", "Generate Clang diagnostics definitions"), clEnumValN(GenClangDiagGroups, "gen-clang-diag-groups", "Generate Clang diagnostic groups"), + clEnumValN(GenClangDeclNodes, "gen-clang-decl-nodes", + "Generate Clang AST statement nodes"), clEnumValN(GenClangStmtNodes, "gen-clang-stmt-nodes", "Generate Clang AST statement nodes"), clEnumValN(GenLLVMCConf, "gen-llvmc", @@ -119,6 +132,10 @@ namespace { "Generate enhanced disassembly info header"), clEnumValN(GenEDInfo, "gen-enhanced-disassembly-info", "Generate enhanced disassembly info"), + 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(PrintEnums, "print-enums", "Print enum values for a class"), clEnumValEnd)); @@ -191,105 +208,117 @@ int main(int argc, char **argv) { if (ParseFile(InputFilename, IncludeDirs, SrcMgr)) return 1; - raw_ostream *Out = &outs(); - if (OutputFilename != "-") { - std::string Error; - Out = new raw_fd_ostream(OutputFilename.c_str(), Error); - - if (!Error.empty()) { - errs() << argv[0] << ": error opening " << OutputFilename - << ":" << Error << "\n"; - return 1; - } - - // Make sure the file gets removed if *gasp* tablegen crashes... - sys::RemoveFileOnSignal(sys::Path(OutputFilename)); + std::string Error; + raw_fd_ostream Out(OutputFilename.c_str(), Error); + if (!Error.empty()) { + errs() << argv[0] << ": error opening " << OutputFilename + << ":" << Error << "\n"; + return 1; } + // Make sure the file gets removed if *gasp* tablegen crashes... + sys::RemoveFileOnSignal(sys::Path(OutputFilename)); + try { switch (Action) { case PrintRecords: - *Out << Records; // No argument, dump all contents + Out << Records; // No argument, dump all contents break; case GenEmitter: - CodeEmitterGen(Records).run(*Out); + CodeEmitterGen(Records).run(Out); break; case GenRegisterEnums: - RegisterInfoEmitter(Records).runEnums(*Out); + RegisterInfoEmitter(Records).runEnums(Out); break; case GenRegister: - RegisterInfoEmitter(Records).run(*Out); + RegisterInfoEmitter(Records).run(Out); break; case GenRegisterHeader: - RegisterInfoEmitter(Records).runHeader(*Out); + RegisterInfoEmitter(Records).runHeader(Out); break; case GenInstrEnums: - InstrEnumEmitter(Records).run(*Out); + InstrEnumEmitter(Records).run(Out); break; case GenInstrs: - InstrInfoEmitter(Records).run(*Out); + InstrInfoEmitter(Records).run(Out); break; case GenCallingConv: - CallingConvEmitter(Records).run(*Out); + CallingConvEmitter(Records).run(Out); break; case GenAsmWriter: - AsmWriterEmitter(Records).run(*Out); + AsmWriterEmitter(Records).run(Out); break; case GenARMDecoder: - ARMDecoderEmitter(Records).run(*Out); + ARMDecoderEmitter(Records).run(Out); break; case GenAsmMatcher: - AsmMatcherEmitter(Records).run(*Out); + AsmMatcherEmitter(Records).run(Out); + break; + case GenClangAttrClasses: + ClangAttrClassEmitter(Records).run(Out); + break; + case GenClangAttrList: + ClangAttrListEmitter(Records).run(Out); break; case GenClangDiagsDefs: - ClangDiagsDefsEmitter(Records, ClangComponent).run(*Out); + ClangDiagsDefsEmitter(Records, ClangComponent).run(Out); break; case GenClangDiagGroups: - ClangDiagGroupsEmitter(Records).run(*Out); + ClangDiagGroupsEmitter(Records).run(Out); + break; + case GenClangDeclNodes: + ClangASTNodesEmitter(Records, "Decl", "Decl").run(Out); + ClangDeclContextEmitter(Records).run(Out); break; case GenClangStmtNodes: - ClangStmtNodesEmitter(Records).run(*Out); + ClangASTNodesEmitter(Records, "Stmt", "").run(Out); break; case GenDisassembler: - DisassemblerEmitter(Records).run(*Out); + DisassemblerEmitter(Records).run(Out); break; case GenOptParserDefs: - OptParserEmitter(Records, true).run(*Out); + OptParserEmitter(Records, true).run(Out); break; case GenOptParserImpl: - OptParserEmitter(Records, false).run(*Out); + OptParserEmitter(Records, false).run(Out); break; case GenDAGISel: - DAGISelEmitter(Records).run(*Out); + DAGISelEmitter(Records).run(Out); break; case GenFastISel: - FastISelEmitter(Records).run(*Out); + FastISelEmitter(Records).run(Out); break; case GenSubtarget: - SubtargetEmitter(Records).run(*Out); + SubtargetEmitter(Records).run(Out); break; case GenIntrinsic: - IntrinsicEmitter(Records).run(*Out); + IntrinsicEmitter(Records).run(Out); break; case GenTgtIntrinsic: - IntrinsicEmitter(Records, true).run(*Out); + IntrinsicEmitter(Records, true).run(Out); break; case GenLLVMCConf: - LLVMCConfigurationEmitter(Records).run(*Out); + LLVMCConfigurationEmitter(Records).run(Out); break; case GenEDHeader: - EDEmitter(Records).runHeader(*Out); + EDEmitter(Records).runHeader(Out); break; case GenEDInfo: - EDEmitter(Records).run(*Out); + EDEmitter(Records).run(Out); + break; + case GenArmNeon: + NeonEmitter(Records).run(Out); + break; + case GenArmNeonSema: + NeonEmitter(Records).runHeader(Out); break; case PrintEnums: { std::vector<Record*> Recs = Records.getAllDerivedDefinitions(Class); for (unsigned i = 0, e = Recs.size(); i != e; ++i) - *Out << Recs[i]->getName() << ", "; - *Out << "\n"; + Out << Recs[i]->getName() << ", "; + Out << "\n"; break; } default: @@ -297,8 +326,6 @@ int main(int argc, char **argv) { return 1; } - if (Out != &outs()) - delete Out; // Close the file return 0; } catch (const TGError &Error) { @@ -313,9 +340,7 @@ int main(int argc, char **argv) { errs() << argv[0] << ": Unknown unexpected exception occurred.\n"; } - if (Out != &outs()) { - delete Out; // Close the file + if (OutputFilename != "-") std::remove(OutputFilename.c_str()); // Remove the file, it's broken - } return 1; } diff --git a/contrib/llvm/utils/TableGen/X86RecognizableInstr.cpp b/contrib/llvm/utils/TableGen/X86RecognizableInstr.cpp index b7085ae..4dba85b 100644 --- a/contrib/llvm/utils/TableGen/X86RecognizableInstr.cpp +++ b/contrib/llvm/utils/TableGen/X86RecognizableInstr.cpp @@ -33,7 +33,7 @@ using namespace llvm; MAP(C9, 38) \ MAP(E8, 39) \ MAP(F0, 40) \ - MAP(F8, 41) \ + MAP(F8, 41) \ MAP(F9, 42) // A clone of X86 since we can't depend on something that is generated. @@ -212,6 +212,7 @@ RecognizableInstr::RecognizableInstr(DisassemblerTables &tables, HasOpSizePrefix = Rec->getValueAsBit("hasOpSizePrefix"); HasREX_WPrefix = Rec->getValueAsBit("hasREX_WPrefix"); + HasVEX_4VPrefix = Rec->getValueAsBit("hasVEX_4VPrefix"); HasLockPrefix = Rec->getValueAsBit("hasLockPrefix"); IsCodeGenOnly = Rec->getValueAsBit("isCodeGenOnly"); @@ -532,7 +533,13 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) { "Unexpected number of operands for MRMSrcRegFrm"); HANDLE_OPERAND(roRegister) HANDLE_OPERAND(rmRegister) - HANDLE_OPTIONAL(immediate) + + if (HasVEX_4VPrefix) + // FIXME: In AVX, the register below becomes the one encoded + // in ModRMVEX and the one above the one in the VEX.VVVV field + HANDLE_OPTIONAL(rmRegister) + else + HANDLE_OPTIONAL(immediate) break; case X86Local::MRMSrcMem: // Operand 1 is a register operand in the Reg/Opcode field. @@ -541,6 +548,12 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) { assert(numPhysicalOperands >= 2 && numPhysicalOperands <= 3 && "Unexpected number of operands for MRMSrcMemFrm"); HANDLE_OPERAND(roRegister) + + if (HasVEX_4VPrefix) + // FIXME: In AVX, the register below becomes the one encoded + // in ModRMVEX and the one above the one in the VEX.VVVV field + HANDLE_OPTIONAL(rmRegister) + HANDLE_OPERAND(memory) HANDLE_OPTIONAL(immediate) break; @@ -823,6 +836,7 @@ OperandType RecognizableInstr::typeFromString(const std::string &s, TYPE("RST", TYPE_ST) TYPE("i128mem", TYPE_M128) TYPE("i64i32imm_pcrel", TYPE_REL64) + TYPE("i16imm_pcrel", TYPE_REL16) TYPE("i32imm_pcrel", TYPE_REL32) TYPE("SSECC", TYPE_IMM3) TYPE("brtarget", TYPE_RELv) @@ -942,6 +956,7 @@ OperandEncoding RecognizableInstr::relocationEncodingFromString ENCODING("i64i8imm", ENCODING_IB) ENCODING("i8imm", ENCODING_IB) ENCODING("i64i32imm_pcrel", ENCODING_ID) + ENCODING("i16imm_pcrel", ENCODING_IW) ENCODING("i32imm_pcrel", ENCODING_ID) ENCODING("brtarget", ENCODING_Iv) ENCODING("brtarget8", ENCODING_IB) diff --git a/contrib/llvm/utils/TableGen/X86RecognizableInstr.h b/contrib/llvm/utils/TableGen/X86RecognizableInstr.h index 84374b0..db4d96d 100644 --- a/contrib/llvm/utils/TableGen/X86RecognizableInstr.h +++ b/contrib/llvm/utils/TableGen/X86RecognizableInstr.h @@ -52,6 +52,8 @@ private: bool HasOpSizePrefix; /// The hasREX_WPrefix field from the record bool HasREX_WPrefix; + /// The hasVEX_4VPrefix field from the record + bool HasVEX_4VPrefix; /// The hasLockPrefix field from the record bool HasLockPrefix; /// The isCodeGenOnly filed from the record |