diff options
author | Mikhail Glushenkov <foldr@codedgers.com> | 2008-12-07 16:41:11 +0000 |
---|---|---|
committer | Mikhail Glushenkov <foldr@codedgers.com> | 2008-12-07 16:41:11 +0000 |
commit | f915253dfcfbe772ee04872544a4f012c6f851be (patch) | |
tree | 37804c93f492340cbffe03d4f709e34d9e1d99e2 | |
parent | 6290f5cac23399201f8785e5ca8b305e42a1342c (diff) |
Use (actions) instead of option properties, support external options.
Also includes a major refactoring. See documentation for more
information.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@60656 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/llvm/CompilerDriver/Action.h | 16 | ||||
-rw-r--r-- | include/llvm/CompilerDriver/Common.td | 30 | ||||
-rw-r--r-- | include/llvm/CompilerDriver/Tool.h | 20 | ||||
-rw-r--r-- | include/llvm/CompilerDriver/Tools.td | 85 | ||||
-rw-r--r-- | tools/llvmc/driver/CompilationGraph.cpp | 82 | ||||
-rw-r--r-- | tools/llvmc/driver/Tool.cpp | 74 | ||||
-rw-r--r-- | utils/TableGen/LLVMCConfigurationEmitter.cpp | 1860 |
7 files changed, 1070 insertions, 1097 deletions
diff --git a/include/llvm/CompilerDriver/Action.h b/include/llvm/CompilerDriver/Action.h index c3b31d4e55..9cac0aa45b 100644 --- a/include/llvm/CompilerDriver/Action.h +++ b/include/llvm/CompilerDriver/Action.h @@ -27,14 +27,22 @@ namespace llvmc { std::string Command_; /// Args_ - Command arguments. Stdout redirection ("> file") is allowed. std::vector<std::string> Args_; + /// StopCompilation_ - Should we stop compilation after executing + /// this action? + bool StopCompilation_; + /// OutFile_ - The output file name. + std::string OutFile_; + public: - Action() {} - Action (const std::string& C, const StrVector& A) - : Command_(C), Args_(A) + Action (const std::string& C, const StrVector& A, + bool S, const std::string& O) + : Command_(C), Args_(A), StopCompilation_(S), OutFile_(O) {} /// Execute - Executes the represented action. - int Execute() const; + int Execute () const; + bool StopCompilation () const { return StopCompilation_; } + const std::string& OutFile() { return OutFile_; } }; } diff --git a/include/llvm/CompilerDriver/Common.td b/include/llvm/CompilerDriver/Common.td index 109a7e5eda..c510956004 100644 --- a/include/llvm/CompilerDriver/Common.td +++ b/include/llvm/CompilerDriver/Common.td @@ -15,7 +15,7 @@ class Tool<list<dag> l> { list<dag> properties = l; } -// Possible Tool properties +// Possible Tool properties. def in_language; def out_language; @@ -23,8 +23,9 @@ def output_suffix; def cmd_line; def join; def sink; +def actions; -// Possible option types +// Possible option types. def alias_option; def switch_option; @@ -33,17 +34,16 @@ def parameter_list_option; def prefix_option; def prefix_list_option; -// Possible option properties +def extern_switch; +def extern_parameter; +def extern_list; + +// Possible option properties. -def append_cmd; -def forward; -def forward_as; def help; def hidden; def really_hidden; def required; -def stop_compilation; -def unpack_values; // Empty DAG marker. def empty; @@ -51,6 +51,10 @@ def empty; // The 'case' construct. def case; +// Boolean operators. +def and; +def or; + // Primitive tests. def switch_on; def parameter_equals; @@ -59,9 +63,13 @@ def input_languages_contain; def not_empty; def default; -// Boolean operators. -def and; -def or; +// Possible actions. + +def append_cmd; +def forward; +def forward_as; +def stop_compilation; +def unpack_values; // Increase/decrease the edge weight. def inc_weight; diff --git a/include/llvm/CompilerDriver/Tool.h b/include/llvm/CompilerDriver/Tool.h index c422a43992..8e8f6e73c2 100644 --- a/include/llvm/CompilerDriver/Tool.h +++ b/include/llvm/CompilerDriver/Tool.h @@ -36,22 +36,29 @@ namespace llvmc { virtual ~Tool() {} virtual Action GenerateAction (const PathVector& inFiles, - const llvm::sys::Path& outFile, + bool HasChildren, + const llvm::sys::Path& TempDir, const InputLanguagesSet& InLangs, const LanguageMap& LangMap) const = 0; virtual Action GenerateAction (const llvm::sys::Path& inFile, - const llvm::sys::Path& outFile, + bool HasChildren, + const llvm::sys::Path& TempDir, const InputLanguagesSet& InLangs, const LanguageMap& LangMap) const = 0; virtual const char* Name() const = 0; virtual const char** InputLanguages() const = 0; virtual const char* OutputLanguage() const = 0; - virtual const char* OutputSuffix() const = 0; - virtual bool IsLast() const = 0; virtual bool IsJoin() const = 0; + + protected: + /// OutFileName - Generate the output file name. + llvm::sys::Path OutFilename(const llvm::sys::Path& In, + const llvm::sys::Path& TempDir, + bool StopCompilation, + const char* OutputSuffix) const; }; /// JoinTool - A Tool that has an associated input file list. @@ -61,10 +68,11 @@ namespace llvmc { void ClearJoinList() { JoinList_.clear(); } bool JoinListEmpty() const { return JoinList_.empty(); } - Action GenerateAction(const llvm::sys::Path& outFile, + Action GenerateAction(bool HasChildren, + const llvm::sys::Path& TempDir, const InputLanguagesSet& InLangs, const LanguageMap& LangMap) const { - return GenerateAction(JoinList_, outFile, InLangs, LangMap); + return GenerateAction(JoinList_, HasChildren, TempDir, InLangs, LangMap); } // We shouldn't shadow base class's version of GenerateAction. using Tool::GenerateAction; diff --git a/include/llvm/CompilerDriver/Tools.td b/include/llvm/CompilerDriver/Tools.td index e701b47649..d8248acae2 100644 --- a/include/llvm/CompilerDriver/Tools.td +++ b/include/llvm/CompilerDriver/Tools.td @@ -11,6 +11,35 @@ // //===----------------------------------------------------------------------===// +def OptList : OptionList<[ + (switch_option "emit-llvm", + (help "Emit LLVM bitcode files instead of native object files")), + (switch_option "E", + (help "Stop after the preprocessing stage, do not run the compiler")), + (switch_option "fsyntax-only", + (help "Stop after checking the input for syntax errors")), + (switch_option "opt", + (help "Enable opt")), + (switch_option "S", + (help "Stop after compilation, do not assemble")), + (switch_option "c", + (help "Compile and assemble, but do not link")), + (parameter_option "linker", + (help "Choose linker (possible values: gcc, g++)")), + (parameter_list_option "include", + (help "Include the named file prior to preprocessing")), + (prefix_list_option "I", + (help "Add a directory to include path")), + (prefix_list_option "Wa,", + (help "Pass options to assembler")), + (prefix_list_option "L", + (help "Add a directory to link path")), + (prefix_list_option "l", + (help "Search a library when linking")), + (prefix_list_option "Wl,", + (help "Pass options to linker")) +]>; + class llvm_gcc_based <string cmd_prefix, string in_lang> : Tool< [(in_language in_lang), (out_language "llvm-bitcode"), @@ -25,16 +54,13 @@ class llvm_gcc_based <string cmd_prefix, string in_lang> : Tool< !strconcat(cmd_prefix, " -fsyntax-only $INFILE"), (default), !strconcat(cmd_prefix, " -c $INFILE -o $OUTFILE -emit-llvm"))), - (switch_option "emit-llvm", (stop_compilation), - (help "Emit LLVM intermediate files instead of native object files")), - (switch_option "E", (stop_compilation), - (help "Stop after the preprocessing stage, do not run the compiler")), - (switch_option "fsyntax-only", (stop_compilation), - (help "Stop after checking the input for syntax errors")), - (parameter_list_option "include", (forward), - (help "Include the named file prior to preprocessing")), - (prefix_list_option "I", (forward), - (help "Add a directory to include path")), + (actions + (case + (switch_on "emit-llvm"), (stop_compilation), + (switch_on "E"), (stop_compilation), + (switch_on "fsyntax-only"), (stop_compilation), + (not_empty "include"), (forward "include"), + (not_empty "I"), (forward "include"))), (sink) ]>; @@ -46,7 +72,6 @@ def llvm_gcc_mxx : llvm_gcc_based<"llvm-gcc -x objective-c++", "objective-c++">; def opt : Tool< [(in_language "llvm-bitcode"), (out_language "llvm-bitcode"), - (switch_option "opt", (help "Enable opt")), (output_suffix "bc"), (cmd_line "opt -f $INFILE -o $OUTFILE") ]>; @@ -62,8 +87,8 @@ def llc : Tool< [(in_language "llvm-bitcode"), (out_language "assembler"), (output_suffix "s"), - (switch_option "S", (stop_compilation), - (help "Stop after compilation, do not assemble")), + (actions (case + (switch_on "S"), (stop_compilation))), (cmd_line "llc -f $INFILE -o $OUTFILE") ]>; @@ -72,36 +97,28 @@ def llvm_gcc_assembler : Tool< (out_language "object-code"), (output_suffix "o"), (cmd_line "llvm-gcc -c -x assembler $INFILE -o $OUTFILE"), - (switch_option "c", (stop_compilation), - (help "Compile and assemble, but do not link")), - (prefix_list_option "Wa,", (unpack_values), (help "Pass options to assembler")) + (actions (case + (switch_on "c"), (stop_compilation), + (not_empty "Wa,"), (unpack_values "Wa,"))) ]>; -// Default linker -def llvm_gcc_linker : Tool< +// Base class for linkers +class llvm_gcc_based_linker <string cmd_prefix> : Tool< [(in_language "object-code"), (out_language "executable"), (output_suffix "out"), - (cmd_line "llvm-gcc $INFILE -o $OUTFILE"), + (cmd_line !strconcat(cmd_prefix, " $INFILE -o $OUTFILE")), (join), - (prefix_list_option "L", (forward), (help "Add a directory to link path")), - (prefix_list_option "l", (forward), (help "Search a library when linking")), - (prefix_list_option "Wl,", (unpack_values), (help "Pass options to linker")) + (actions (case + (not_empty "L"), (forward "L"), + (not_empty "l"), (forward "l"), + (not_empty "Wl,"), (unpack_values "Wl,"))) ]>; +// Default linker +def llvm_gcc_linker : llvm_gcc_based_linker<"llvm-gcc">; // Alternative linker for C++ -def llvm_gcc_cpp_linker : Tool< -[(in_language "object-code"), - (out_language "executable"), - (output_suffix "out"), - (cmd_line "llvm-g++ $INFILE -o $OUTFILE"), - (join), - (parameter_option "linker", - (help "Choose linker (possible values: gcc, g++)")), - (prefix_list_option "L", (forward)), - (prefix_list_option "l", (forward)), - (prefix_list_option "Wl,", (unpack_values)) -]>; +def llvm_gcc_cpp_linker : llvm_gcc_based_linker<"llvm-g++">; // Language map diff --git a/tools/llvmc/driver/CompilationGraph.cpp b/tools/llvmc/driver/CompilationGraph.cpp index a4fda4834f..6d7faa3dec 100644 --- a/tools/llvmc/driver/CompilationGraph.cpp +++ b/tools/llvmc/driver/CompilationGraph.cpp @@ -29,7 +29,6 @@ using namespace llvm; using namespace llvmc; extern cl::list<std::string> InputFilenames; -extern cl::opt<std::string> OutputFilename; extern cl::list<std::string> Languages; namespace llvmc { @@ -143,30 +142,6 @@ void CompilationGraph::insertEdge(const std::string& A, Edge* Edg) { B.IncrInEdges(); } -namespace { - sys::Path MakeTempFile(const sys::Path& TempDir, const std::string& BaseName, - const std::string& Suffix) { - sys::Path Out; - - // Make sure we don't end up with path names like '/file.o' if the - // TempDir is empty. - if (TempDir.empty()) { - Out.set(BaseName); - } - else { - Out = TempDir; - Out.appendComponent(BaseName); - } - Out.appendSuffix(Suffix); - // NOTE: makeUnique always *creates* a unique temporary file, - // which is good, since there will be no races. However, some - // tools do not like it when the output file already exists, so - // they have to be placated with -f or something like that. - Out.makeUnique(true, NULL); - return Out; - } -} - // Pass input file through the chain until we bump into a Join node or // a node that says that it is the last. void CompilationGraph::PassThroughGraph (const sys::Path& InFile, @@ -174,12 +149,10 @@ void CompilationGraph::PassThroughGraph (const sys::Path& InFile, const InputLanguagesSet& InLangs, const sys::Path& TempDir, const LanguageMap& LangMap) const { - bool Last = false; sys::Path In = InFile; const Node* CurNode = StartNode; - while(!Last) { - sys::Path Out; + while(true) { Tool* CurTool = CurNode->ToolPtr.getPtr(); if (CurTool->IsJoin()) { @@ -188,32 +161,19 @@ void CompilationGraph::PassThroughGraph (const sys::Path& InFile, break; } - // Since toolchains do not have to end with a Join node, we should - // check if this Node is the last. - if (!CurNode->HasChildren() || CurTool->IsLast()) { - if (!OutputFilename.empty()) { - Out.set(OutputFilename); - } - else { - Out.set(In.getBasename()); - Out.appendSuffix(CurTool->OutputSuffix()); - } - Last = true; - } - else { - Out = MakeTempFile(TempDir, In.getBasename(), CurTool->OutputSuffix()); - } + Action CurAction = CurTool->GenerateAction(In, CurNode->HasChildren(), + TempDir, InLangs, LangMap); - if (int ret = CurTool->GenerateAction(In, Out, InLangs, LangMap).Execute()) + if (int ret = CurAction.Execute()) throw error_code(ret); - if (Last) + if (CurAction.StopCompilation()) return; CurNode = &getNode(ChooseEdge(CurNode->OutEdges, InLangs, CurNode->Name())->ToolName()); - In = Out; Out.clear(); + In = CurAction.OutFile(); } } @@ -351,36 +311,24 @@ int CompilationGraph::Build (const sys::Path& TempDir, sys::Path Out; const Node* CurNode = *B; JoinTool* JT = &dynamic_cast<JoinTool&>(*CurNode->ToolPtr.getPtr()); - bool IsLast = false; // Are there any files in the join list? if (JT->JoinListEmpty()) continue; - // Is this the last tool in the toolchain? - // NOTE: we can process several toolchains in parallel. - if (!CurNode->HasChildren() || JT->IsLast()) { - if (OutputFilename.empty()) { - Out.set("a"); - Out.appendSuffix(JT->OutputSuffix()); - } - else - Out.set(OutputFilename); - IsLast = true; - } - else { - Out = MakeTempFile(TempDir, "tmp", JT->OutputSuffix()); - } + Action CurAction = JT->GenerateAction(CurNode->HasChildren(), + TempDir, InLangs, LangMap); - if (int ret = JT->GenerateAction(Out, InLangs, LangMap).Execute()) + if (int ret = CurAction.Execute()) throw error_code(ret); - if (!IsLast) { - const Node* NextNode = - &getNode(ChooseEdge(CurNode->OutEdges, InLangs, - CurNode->Name())->ToolName()); + if (CurAction.StopCompilation()) + return 0; + + const Node* NextNode = + &getNode(ChooseEdge(CurNode->OutEdges, InLangs, + CurNode->Name())->ToolName()); PassThroughGraph(Out, NextNode, InLangs, TempDir, LangMap); - } } return 0; diff --git a/tools/llvmc/driver/Tool.cpp b/tools/llvmc/driver/Tool.cpp new file mode 100644 index 0000000000..886b26b5d7 --- /dev/null +++ b/tools/llvmc/driver/Tool.cpp @@ -0,0 +1,74 @@ +//===--- Tool.cpp - The LLVM Compiler Driver --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open +// Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Tool base class - implementation details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CompilerDriver/Tool.h" + +#include "llvm/System/Path.h" +#include "llvm/Support/CommandLine.h" + +using namespace llvm; +using namespace llvmc; + +extern cl::opt<std::string> OutputFilename; + +namespace { + sys::Path MakeTempFile(const sys::Path& TempDir, const std::string& BaseName, + const std::string& Suffix) { + sys::Path Out; + + // Make sure we don't end up with path names like '/file.o' if the + // TempDir is empty. + if (TempDir.empty()) { + Out.set(BaseName); + } + else { + Out = TempDir; + Out.appendComponent(BaseName); + } + Out.appendSuffix(Suffix); + // NOTE: makeUnique always *creates* a unique temporary file, + // which is good, since there will be no races. However, some + // tools do not like it when the output file already exists, so + // they have to be placated with -f or something like that. + Out.makeUnique(true, NULL); + return Out; + } +} + +sys::Path Tool::OutFilename(const sys::Path& In, + const sys::Path& TempDir, + bool StopCompilation, + const char* OutputSuffix) const { + sys::Path Out; + + if (StopCompilation) { + if (!OutputFilename.empty()) { + Out.set(OutputFilename); + } + else if (IsJoin()) { + Out.set("a"); + Out.appendSuffix(OutputSuffix); + } + else { + Out.set(In.getBasename()); + Out.appendSuffix(OutputSuffix); + } + } + else { + if (IsJoin()) + Out = MakeTempFile(TempDir, "tmp", OutputSuffix); + else + Out = MakeTempFile(TempDir, In.getBasename(), OutputSuffix); + } + return Out; +} diff --git a/utils/TableGen/LLVMCConfigurationEmitter.cpp b/utils/TableGen/LLVMCConfigurationEmitter.cpp index 97ea3d6834..175de45925 100644 --- a/utils/TableGen/LLVMCConfigurationEmitter.cpp +++ b/utils/TableGen/LLVMCConfigurationEmitter.cpp @@ -45,7 +45,6 @@ typedef std::vector<std::string> StrVector; const char * Indent1 = " "; const char * Indent2 = " "; const char * Indent3 = " "; -const char * Indent4 = " "; // Default help string. const char * DefaultHelpString = "NO HELP MESSAGE PROVIDED"; @@ -56,6 +55,13 @@ const char * SinkOptionName = "AutoGeneratedSinkOption"; //===----------------------------------------------------------------------===// /// Helper functions +/// Id - An 'identity' function object. +struct Id { + template<typename T> + void operator()(const T&) const { + } +}; + int InitPtrToInt(const Init* ptr) { const IntInit& val = dynamic_cast<const IntInit&>(*ptr); return val.getValue(); @@ -89,426 +95,330 @@ bool isDagEmpty (const DagInit* d) { return d->getOperator()->getAsString() == "empty"; } +// EscapeVariableName - Escape commas and other symbols not allowed +// in the C++ variable names. Makes it possible to use options named +// like "Wa," (useful for prefix options). +std::string EscapeVariableName(const std::string& Var) { + std::string ret; + for (unsigned i = 0; i != Var.size(); ++i) { + char cur_char = Var[i]; + if (cur_char == ',') { + ret += "_comma_"; + } + else if (cur_char == '+') { + ret += "_plus_"; + } + else if (cur_char == '-') { + ret += "_dash_"; + } + else { + ret.push_back(cur_char); + } + } + return ret; +} + //===----------------------------------------------------------------------===// /// Back-end specific code -// A command-line option can have one of the following types: -// -// Alias - an alias for another option. -// -// Switch - a simple switch without arguments, e.g. -O2 -// -// Parameter - an option that takes one(and only one) argument, e.g. -o file, -// --output=file -// -// ParameterList - same as Parameter, but more than one occurence -// of the option is allowed, e.g. -lm -lpthread -// -// Prefix - argument is everything after the prefix, -// e.g. -Wa,-foo,-bar, -DNAME=VALUE -// -// PrefixList - same as Prefix, but more than one option occurence is -// allowed. +/// OptionType - One of six different option types. See the +/// documentation for detailed description of differences. +/// Extern* options are those that are defined in some other plugin. namespace OptionType { - enum OptionType { Alias, Switch, - Parameter, ParameterList, Prefix, PrefixList}; + enum OptionType { Alias, Switch, Parameter, ParameterList, + Prefix, PrefixList, + ExternSwitch, ExternParameter, ExternList }; + +bool IsList (OptionType t) { + return (t == ParameterList || t == PrefixList || t == ExternList); } -bool IsListOptionType (OptionType::OptionType t) { - return (t == OptionType::ParameterList || t == OptionType::PrefixList); +bool IsSwitch (OptionType t) { + return (t == Switch || t == ExternSwitch); } -// Code duplication here is necessary because one option can affect -// several tools and those tools may have different actions associated -// with this option. GlobalOptionDescriptions are used to generate -// the option registration code, while ToolOptionDescriptions are used -// to generate tool-specific code. +bool IsParameter (OptionType t) { + return (t == Parameter || t == Prefix || t == ExternParameter); +} -/// OptionDescription - Base class for option descriptions. +} + +OptionType::OptionType stringToOptionType(const std::string& T) { + if (T == "alias_option") + return OptionType::Alias; + else if (T == "switch_option") + return OptionType::Switch; + else if (T == "parameter_option") + return OptionType::Parameter; + else if (T == "parameter_list_option") + return OptionType::ParameterList; + else if (T == "prefix_option") + return OptionType::Prefix; + else if (T == "prefix_list_option") + return OptionType::PrefixList; + else if (T == "extern_switch") + return OptionType::ExternSwitch; + else if (T == "extern_parameter") + return OptionType::ExternParameter; + else if (T == "extern_list") + return OptionType::ExternList; + else + throw "Unknown option type: " + T + '!'; +} + +namespace OptionDescriptionFlags { + enum OptionDescriptionFlags { Required = 0x1, Hidden = 0x2, + ReallyHidden = 0x4 }; +} + +/// OptionDescription - Represents data contained in a single +/// OptionList entry. struct OptionDescription { OptionType::OptionType Type; std::string Name; + unsigned Flags; + std::string Help; OptionDescription(OptionType::OptionType t = OptionType::Switch, - const std::string& n = "") - : Type(t), Name(n) + const std::string& n = "", + const std::string& h = DefaultHelpString) + : Type(t), Name(n), Flags(0x0), Help(h) {} - const char* GenTypeDeclaration() const { - switch (Type) { - case OptionType::Alias: - return "cl::alias"; - case OptionType::PrefixList: - case OptionType::ParameterList: - return "cl::list<std::string>"; - case OptionType::Switch: - return "cl::opt<bool>"; - case OptionType::Parameter: - case OptionType::Prefix: - default: - return "cl::opt<std::string>"; - } - } + /// GenTypeDeclaration - Returns the C++ variable type of this + /// option. + const char* GenTypeDeclaration() const; - // Escape commas and other symbols not allowed in the C++ variable - // names. Makes it possible to use options with names like "Wa," - // (useful for prefix options). - std::string EscapeVariableName(const std::string& Var) const { - std::string ret; - for (unsigned i = 0; i != Var.size(); ++i) { - char cur_char = Var[i]; - if (cur_char == ',') { - ret += "_comma_"; - } - else if (cur_char == '+') { - ret += "_plus_"; - } - else if (cur_char == '-') { - ret += "_dash_"; - } - else { - ret.push_back(cur_char); - } - } - return ret; - } + /// GenVariableName - Returns the variable name used in the + /// generated C++ code. + std::string GenVariableName() const; - std::string GenVariableName() const { - const std::string& EscapedName = EscapeVariableName(Name); - switch (Type) { - case OptionType::Alias: - return "AutoGeneratedAlias" + EscapedName; - case OptionType::Switch: - return "AutoGeneratedSwitch" + EscapedName; - case OptionType::Prefix: - return "AutoGeneratedPrefix" + EscapedName; - case OptionType::PrefixList: - return "AutoGeneratedPrefixList" + EscapedName; - case OptionType::Parameter: - return "AutoGeneratedParameter" + EscapedName; - case OptionType::ParameterList: - default: - return "AutoGeneratedParameterList" + EscapedName; - } - } + /// Merge - Merge two option descriptions. + void Merge (const OptionDescription& other); + + // Misc convenient getters/setters. + + bool isAlias() const; + bool isExtern() const; + bool isRequired() const; + void setRequired(); + + bool isHidden() const; + void setHidden(); + + bool isReallyHidden() const; + void setReallyHidden(); }; -// Global option description. +void OptionDescription::Merge (const OptionDescription& other) +{ + if (other.Type != Type) + throw "Conflicting definitions for the option " + Name + "!"; -namespace GlobalOptionDescriptionFlags { - enum GlobalOptionDescriptionFlags { Required = 0x1, Hidden = 0x2, - ReallyHidden = 0x4 }; + if (Help == other.Help || Help == DefaultHelpString) + Help = other.Help; + else if (other.Help != DefaultHelpString) { + llvm::cerr << "Warning: several different help strings" + " defined for option " + Name + "\n"; + } + + Flags |= other.Flags; } -struct GlobalOptionDescription : public OptionDescription { - std::string Help; - unsigned Flags; +bool OptionDescription::isAlias() const { + return Type == OptionType::Alias; +} - // We need to provide a default constructor because - // StringMap can only store DefaultConstructible objects. - GlobalOptionDescription() : OptionDescription(), Flags(0) - {} +bool OptionDescription::isExtern() const { + return (Type == OptionType::ExternList || Type == OptionType::ExternParameter + || Type == OptionType::ExternSwitch); +} - GlobalOptionDescription (OptionType::OptionType t, const std::string& n, - const std::string& h = DefaultHelpString) - : OptionDescription(t, n), Help(h), Flags(0) - {} +bool OptionDescription::isRequired() const { + return Flags & OptionDescriptionFlags::Required; +} +void OptionDescription::setRequired() { + Flags |= OptionDescriptionFlags::Required; +} - bool isRequired() const { - return Flags & GlobalOptionDescriptionFlags::Required; - } - void setRequired() { - Flags |= GlobalOptionDescriptionFlags::Required; - } +bool OptionDescription::isHidden() const { + return Flags & OptionDescriptionFlags::Hidden; +} +void OptionDescription::setHidden() { + Flags |= OptionDescriptionFlags::Hidden; +} - bool isHidden() const { - return Flags & GlobalOptionDescriptionFlags::Hidden; - } - void setHidden() { - Flags |= GlobalOptionDescriptionFlags::Hidden; - } +bool OptionDescription::isReallyHidden() const { + return Flags & OptionDescriptionFlags::ReallyHidden; +} +void OptionDescription::setReallyHidden() { + Flags |= OptionDescriptionFlags::ReallyHidden; +} - bool isReallyHidden() const { - return Flags & GlobalOptionDescriptionFlags::ReallyHidden; - } - void setReallyHidden() { - Flags |= GlobalOptionDescriptionFlags::ReallyHidden; +const char* OptionDescription::GenTypeDeclaration() const { + switch (Type) { + case OptionType::Alias: + return "cl::alias"; + case OptionType::ExternList: + case OptionType::PrefixList: + case OptionType::ParameterList: + return "cl::list<std::string>"; + case OptionType::Switch: + case OptionType::ExternSwitch: + return "cl::opt<bool>"; + case OptionType::ExternParameter: + case OptionType::Parameter: + case OptionType::Prefix: + default: + return "cl::opt<std::string>"; } +} - /// Merge - Merge two option descriptions. - void Merge (const GlobalOptionDescription& other) - { - if (other.Type != Type) - throw "Conflicting definitions for the option " + Name + "!"; - - if (Help == other.Help || Help == DefaultHelpString) - Help = other.Help; - else if (other.Help != DefaultHelpString) { - llvm::cerr << "Warning: several different help strings" - " defined for option " + Name + "\n"; - } - - Flags |= other.Flags; +std::string OptionDescription::GenVariableName() const { + const std::string& EscapedName = EscapeVariableName(Name); + switch (Type) { + case OptionType::Alias: + return "AutoGeneratedAlias_" + EscapedName; + case OptionType::PrefixList: + case OptionType::ParameterList: + case OptionType::ExternList: + return "AutoGeneratedList_" + EscapedName; + case OptionType::ExternSwitch: + case OptionType::Switch: + return "AutoGeneratedSwitch_" + EscapedName; + case OptionType::ExternParameter: + case OptionType::Prefix: + case OptionType::Parameter: + default: + return "AutoGeneratedParameter_" + EscapedName; } -}; +} -/// GlobalOptionDescriptions - A GlobalOptionDescription array -/// together with some flags affecting generation of option -/// declarations. -struct GlobalOptionDescriptions { - typedef StringMap<GlobalOptionDescription> container_type; - typedef container_type::const_iterator const_iterator; +/// OptionDescriptions - An OptionDescription array plus some helper +/// functions. +class OptionDescriptions { + typedef StringMap<OptionDescription> container_type; - /// Descriptions - A list of GlobalOptionDescriptions. + /// Descriptions - A list of OptionDescriptions. container_type Descriptions; - /// HasSink - Should the emitter generate a "cl::sink" option? - bool HasSink; +public: /// FindOption - exception-throwing wrapper for find(). - const GlobalOptionDescription& FindOption(const std::string& OptName) const { - const_iterator I = Descriptions.find(OptName); - if (I != Descriptions.end()) - return I->second; - else - throw OptName + ": no such option!"; - } + const OptionDescription& FindOption(const std::string& OptName) const; - /// insertDescription - Insert new GlobalOptionDescription into - /// GlobalOptionDescriptions list - void insertDescription (const GlobalOptionDescription& o) - { - container_type::iterator I = Descriptions.find(o.Name); - if (I != Descriptions.end()) { - GlobalOptionDescription& D = I->second; - D.Merge(o); - } - else { - Descriptions[o.Name] = o; - } - } + /// insertDescription - Insert new OptionDescription into + /// OptionDescriptions list + void InsertDescription (const OptionDescription& o); // Support for STL-style iteration + typedef container_type::const_iterator const_iterator; const_iterator begin() const { return Descriptions.begin(); } const_iterator end() const { return Descriptions.end(); } }; - -// Tool-local option description. - -// Properties without arguments are implemented as flags. -namespace ToolOptionDescriptionFlags { - enum ToolOptionDescriptionFlags { StopCompilation = 0x1, - Forward = 0x2, UnpackValues = 0x4}; -} -namespace OptionPropertyType { - enum OptionPropertyType { AppendCmd, ForwardAs, OutputSuffix }; +const OptionDescription& +OptionDescriptions::FindOption(const std::string& OptName) const +{ + const_iterator I = Descriptions.find(OptName); + if (I != Descriptions.end()) + return I->second; + else + throw OptName + ": no such option!"; } -typedef std::pair<OptionPropertyType::OptionPropertyType, std::string> -OptionProperty; -typedef SmallVector<OptionProperty, 4> OptionPropertyList; - -struct ToolOptionDescription : public OptionDescription { - unsigned Flags; - OptionPropertyList Props; - - // StringMap can only store DefaultConstructible objects - ToolOptionDescription() : OptionDescription(), Flags(0) {} - - ToolOptionDescription (OptionType::OptionType t, const std::string& n) - : OptionDescription(t, n) - {} - - // Various boolean properties - bool isStopCompilation() const { - return Flags & ToolOptionDescriptionFlags::StopCompilation; - } - void setStopCompilation() { - Flags |= ToolOptionDescriptionFlags::StopCompilation; - } - - bool isForward() const { - return Flags & ToolOptionDescriptionFlags::Forward; +void OptionDescriptions::InsertDescription (const OptionDescription& o) +{ + container_type::iterator I = Descriptions.find(o.Name); + if (I != Descriptions.end()) { + OptionDescription& D = I->second; + D.Merge(o); } - void setForward() { - Flags |= ToolOptionDescriptionFlags::Forward; + else { |