diff options
author | Michael J. Spencer <bigcheesegs@gmail.com> | 2012-12-05 00:29:32 +0000 |
---|---|---|
committer | Michael J. Spencer <bigcheesegs@gmail.com> | 2012-12-05 00:29:32 +0000 |
commit | 96a564f2beec8c1930f0640844eec433e03bbce8 (patch) | |
tree | db18bf84800e8860865f55dddd773256547604db /utils | |
parent | ee47edfd8e2dd048522ebd47305aeefbe9d8729c (diff) |
Copy clang/Driver/<Option parsing stuff> to llvm.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@169344 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'utils')
-rw-r--r-- | utils/TableGen/CMakeLists.txt | 1 | ||||
-rw-r--r-- | utils/TableGen/OptParserEmitter.cpp | 267 | ||||
-rw-r--r-- | utils/TableGen/TableGen.cpp | 8 | ||||
-rw-r--r-- | utils/TableGen/TableGenBackends.h | 1 |
4 files changed, 276 insertions, 1 deletions
diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt index d0416c9081..0527aa6180 100644 --- a/utils/TableGen/CMakeLists.txt +++ b/utils/TableGen/CMakeLists.txt @@ -24,6 +24,7 @@ add_tablegen(llvm-tblgen LLVM FixedLenDecoderEmitter.cpp InstrInfoEmitter.cpp IntrinsicEmitter.cpp + OptParserEmitter.cpp PseudoLoweringEmitter.cpp RegisterInfoEmitter.cpp SetTheory.cpp diff --git a/utils/TableGen/OptParserEmitter.cpp b/utils/TableGen/OptParserEmitter.cpp new file mode 100644 index 0000000000..5dab9e63a0 --- /dev/null +++ b/utils/TableGen/OptParserEmitter.cpp @@ -0,0 +1,267 @@ +//===- OptParserEmitter.cpp - Table Driven Command Line Parsing -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.h" + +#include <map> + +using namespace llvm; + +static int StrCmpOptionName(const char *A, const char *B) { + char a = *A, b = *B; + while (a == b) { + if (a == '\0') + return 0; + + a = *++A; + b = *++B; + } + + if (a == '\0') // A is a prefix of B. + return 1; + if (b == '\0') // B is a prefix of A. + return -1; + + // Otherwise lexicographic. + return (a < b) ? -1 : 1; +} + +static int CompareOptionRecords(const void *Av, const void *Bv) { + const Record *A = *(const Record*const*) Av; + const Record *B = *(const Record*const*) Bv; + + // Sentinel options precede all others and are only ordered by precedence. + bool ASent = A->getValueAsDef("Kind")->getValueAsBit("Sentinel"); + bool BSent = B->getValueAsDef("Kind")->getValueAsBit("Sentinel"); + if (ASent != BSent) + return ASent ? -1 : 1; + + // Compare options by name, unless they are sentinels. + if (!ASent) + if (int Cmp = StrCmpOptionName(A->getValueAsString("Name").c_str(), + B->getValueAsString("Name").c_str())) + return Cmp; + + if (!ASent) { + std::vector<std::string> APrefixes = A->getValueAsListOfStrings("Prefixes"); + std::vector<std::string> BPrefixes = B->getValueAsListOfStrings("Prefixes"); + + for (std::vector<std::string>::const_iterator APre = APrefixes.begin(), + AEPre = APrefixes.end(), + BPre = BPrefixes.begin(), + BEPre = BPrefixes.end(); + APre != AEPre && + BPre != BEPre; + ++APre, ++BPre) { + if (int Cmp = StrCmpOptionName(APre->c_str(), BPre->c_str())) + return Cmp; + } + } + + // Then by the kind precedence; + int APrec = A->getValueAsDef("Kind")->getValueAsInt("Precedence"); + int BPrec = B->getValueAsDef("Kind")->getValueAsInt("Precedence"); + if (APrec == BPrec && + A->getValueAsListOfStrings("Prefixes") == + B->getValueAsListOfStrings("Prefixes")) { + PrintError(A->getLoc(), Twine("Option is equivilent to")); + PrintError(B->getLoc(), Twine("Other defined here")); + PrintFatalError("Equivalent Options found."); + } + return APrec < BPrec ? -1 : 1; +} + +static const std::string getOptionName(const Record &R) { + // Use the record name unless EnumName is defined. + if (isa<UnsetInit>(R.getValueInit("EnumName"))) + return R.getName(); + + return R.getValueAsString("EnumName"); +} + +static raw_ostream &write_cstring(raw_ostream &OS, llvm::StringRef Str) { + OS << '"'; + OS.write_escaped(Str); + OS << '"'; + return OS; +} + +/// OptParserEmitter - This tablegen backend takes an input .td file +/// describing a list of options and emits a data structure for parsing and +/// working with those options when given an input command line. +namespace llvm { +void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { + // Get the option groups and options. + const std::vector<Record*> &Groups = + Records.getAllDerivedDefinitions("OptionGroup"); + std::vector<Record*> Opts = Records.getAllDerivedDefinitions("Option"); + + emitSourceFileHeader("Option Parsing Definitions", OS); + + array_pod_sort(Opts.begin(), Opts.end(), CompareOptionRecords); + // Generate prefix groups. + typedef SmallVector<SmallString<2>, 2> PrefixKeyT; + typedef std::map<PrefixKeyT, std::string> PrefixesT; + PrefixesT Prefixes; + Prefixes.insert(std::make_pair(PrefixKeyT(), "prefix_0")); + unsigned CurPrefix = 0; + for (unsigned i = 0, e = Opts.size(); i != e; ++i) { + const Record &R = *Opts[i]; + std::vector<std::string> prf = R.getValueAsListOfStrings("Prefixes"); + PrefixKeyT prfkey(prf.begin(), prf.end()); + unsigned NewPrefix = CurPrefix + 1; + if (Prefixes.insert(std::make_pair(prfkey, (Twine("prefix_") + + Twine(NewPrefix)).str())).second) + CurPrefix = NewPrefix; + } + + // Dump prefixes. + + OS << "/////////\n"; + OS << "// Prefixes\n\n"; + OS << "#ifdef PREFIX\n"; + OS << "#define COMMA ,\n"; + for (PrefixesT::const_iterator I = Prefixes.begin(), E = Prefixes.end(); + I != E; ++I) { + OS << "PREFIX("; + + // Prefix name. + OS << I->second; + + // Prefix values. + OS << ", {"; + for (PrefixKeyT::const_iterator PI = I->first.begin(), + PE = I->first.end(); PI != PE; ++PI) { + OS << "\"" << *PI << "\" COMMA "; + } + OS << "0})\n"; + } + OS << "#undef COMMA\n"; + OS << "#endif\n\n"; + + OS << "/////////\n"; + OS << "// Groups\n\n"; + OS << "#ifdef OPTION\n"; + for (unsigned i = 0, e = Groups.size(); i != e; ++i) { + const Record &R = *Groups[i]; + + // Start a single option entry. + OS << "OPTION("; + + // The option prefix; + OS << "0"; + + // The option string. + OS << ", \"" << R.getValueAsString("Name") << '"'; + + // The option identifier name. + OS << ", "<< getOptionName(R); + + // The option kind. + OS << ", Group"; + + // The containing option group (if any). + OS << ", "; + if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) + OS << getOptionName(*DI->getDef()); + else + OS << "INVALID"; + + // The other option arguments (unused for groups). + OS << ", INVALID, 0, 0"; + + // The option help text. + if (!isa<UnsetInit>(R.getValueInit("HelpText"))) { + OS << ",\n"; + OS << " "; + write_cstring(OS, R.getValueAsString("HelpText")); + } else + OS << ", 0"; + + // The option meta-variable name (unused). + OS << ", 0)\n"; + } + OS << "\n"; + + OS << "//////////\n"; + OS << "// Options\n\n"; + for (unsigned i = 0, e = Opts.size(); i != e; ++i) { + const Record &R = *Opts[i]; + + // Start a single option entry. + OS << "OPTION("; + + // The option prefix; + std::vector<std::string> prf = R.getValueAsListOfStrings("Prefixes"); + OS << Prefixes[PrefixKeyT(prf.begin(), prf.end())] << ", "; + + // The option string. + write_cstring(OS, R.getValueAsString("Name")); + + // The option identifier name. + OS << ", "<< getOptionName(R); + + // The option kind. + OS << ", " << R.getValueAsDef("Kind")->getValueAsString("Name"); + + // The containing option group (if any). + OS << ", "; + if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) + OS << getOptionName(*DI->getDef()); + else + OS << "INVALID"; + + // The option alias (if any). + OS << ", "; + if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Alias"))) + OS << getOptionName(*DI->getDef()); + else + OS << "INVALID"; + + // The option flags. + const ListInit *LI = R.getValueAsListInit("Flags"); + if (LI->empty()) { + OS << ", 0"; + } else { + OS << ", "; + for (unsigned i = 0, e = LI->size(); i != e; ++i) { + if (i) + OS << " | "; + OS << cast<DefInit>(LI->getElement(i))->getDef()->getName(); + } + } + + // The option parameter field. + OS << ", " << R.getValueAsInt("NumArgs"); + + // The option help text. + if (!isa<UnsetInit>(R.getValueInit("HelpText"))) { + OS << ",\n"; + OS << " "; + write_cstring(OS, R.getValueAsString("HelpText")); + } else + OS << ", 0"; + + // The option meta-variable name. + OS << ", "; + if (!isa<UnsetInit>(R.getValueInit("MetaVarName"))) + write_cstring(OS, R.getValueAsString("MetaVarName")); + else + OS << "0"; + + OS << ")\n"; + } + OS << "#endif\n"; +} +} // end namespace llvm diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp index 8250b8c0f1..06be55bde7 100644 --- a/utils/TableGen/TableGen.cpp +++ b/utils/TableGen/TableGen.cpp @@ -40,7 +40,8 @@ enum ActionType { GenTgtIntrinsic, GenEDInfo, PrintEnums, - PrintSets + PrintSets, + GenOptParserDefs }; namespace { @@ -82,6 +83,8 @@ namespace { "Print enum values for a class"), clEnumValN(PrintSets, "print-sets", "Print expanded sets for testing DAG exprs"), + clEnumValN(GenOptParserDefs, "gen-opt-parser-defs", + "Generate option definitions"), clEnumValEnd)); cl::opt<std::string> @@ -138,6 +141,9 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) { case GenEDInfo: EmitEnhancedDisassemblerInfo(Records, OS); break; + case GenOptParserDefs: + EmitOptParser(Records, OS); + break; case PrintEnums: { std::vector<Record*> Recs = Records.getAllDerivedDefinitions(Class); diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h index f0d25d8a2c..4c0d8dcb4f 100644 --- a/utils/TableGen/TableGenBackends.h +++ b/utils/TableGen/TableGenBackends.h @@ -75,5 +75,6 @@ void EmitPseudoLowering(RecordKeeper &RK, raw_ostream &OS); void EmitRegisterInfo(RecordKeeper &RK, raw_ostream &OS); void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS); void EmitMapTable(RecordKeeper &RK, raw_ostream &OS); +void EmitOptParser(RecordKeeper &RK, raw_ostream &OS); } // End llvm namespace |