From bf437720381ded52024e52560bc84e95dde266f7 Mon Sep 17 00:00:00 2001 From: Reid Spencer Date: Sun, 15 Aug 2004 08:19:46 +0000 Subject: [PATCH] More Functionality: - cleaned up lexical scanner - added support for "lang.optN" configuration items - added temporary file support (ala lib/System) - corrected logic for deciding which phases to run - consolidated the Action and ActionPattern classes git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@15765 91177308-0d34-0410-b5e6-96231b3b80d8 --- tools/llvmc/CompilerDriver.cpp | 196 +++++++++++++++++++++++----- tools/llvmc/CompilerDriver.h | 98 ++++++++++---- tools/llvmc/ConfigData.cpp | 232 +++++++++++++++++++++++---------- tools/llvmc/ConfigLexer.h | 11 +- tools/llvmc/ConfigLexer.l | 39 ++++-- tools/llvmc/Configuration.cpp | 232 +++++++++++++++++++++++---------- tools/llvmc/Makefile | 2 +- tools/llvmc/llvmc.cpp | 29 +++-- 8 files changed, 620 insertions(+), 219 deletions(-) diff --git a/tools/llvmc/CompilerDriver.cpp b/tools/llvmc/CompilerDriver.cpp index ff63b2100ed..038274b72aa 100644 --- a/tools/llvmc/CompilerDriver.cpp +++ b/tools/llvmc/CompilerDriver.cpp @@ -13,6 +13,7 @@ //===------------------------------------------------------------------------=== #include "CompilerDriver.h" +#include "ConfigLexer.h" #include using namespace llvm; @@ -32,7 +33,7 @@ namespace { const char OutputSuffix[] = ".o"; - void WriteAction(CompilerDriver::Action* a) { + void WriteAction(CompilerDriver::Action* a ) { std::cerr << a->program; std::vector::iterator I = a->args.begin(); while (I != a->args.end()) { @@ -42,24 +43,32 @@ namespace { std::cerr << "\n"; } + void DumpAction(CompilerDriver::Action* a) { + std::cerr << "command = " << a->program; + std::vector::iterator I = a->args.begin(); + while (I != a->args.end()) { + std::cerr << " " + *I; + ++I; + } + std::cerr << "\n"; + std::cerr << "flags = " << a->flags << "\n"; + std::cerr << "inputAt = " << a->inputAt << "\n"; + std::cerr << "outputAt = " << a->outputAt << "\n"; + } + void DumpConfigData(CompilerDriver::ConfigData* cd, const std::string& type ){ std::cerr << "Configuration Data For '" << cd->langName << "' (" << type << ")\n"; - std::cerr << "translator.preprocesses=" << cd->TranslatorPreprocesses - << "\n"; - std::cerr << "translator.groks_dash_O=" << cd->TranslatorGroksDashO << "\n"; - std::cerr << "translator.optimizes=" << cd->TranslatorOptimizes << "\n"; - std::cerr << "preprocessor.needed=" << cd->PreprocessorNeeded << "\n"; std::cerr << "PreProcessor: "; - WriteAction(&cd->PreProcessor); + DumpAction(&cd->PreProcessor); std::cerr << "Translator: "; - WriteAction(&cd->Translator); + DumpAction(&cd->Translator); std::cerr << "Optimizer: "; - WriteAction(&cd->Optimizer); + DumpAction(&cd->Optimizer); std::cerr << "Assembler: "; - WriteAction(&cd->Assembler); + DumpAction(&cd->Assembler); std::cerr << "Linker: "; - WriteAction(&cd->Linker); + DumpAction(&cd->Linker); } } @@ -75,16 +84,26 @@ CompilerDriver::CompilerDriver(ConfigDataProvider& confDatProv ) , emitRawCode(false) , emitNativeCode(false) , machine() - , libPaths() + , LibraryPaths() + , PreprocessorOptions() + , TranslatorOptions() + , OptimizerOptions() + , AssemblerOptions() + , LinkerOptions() { // FIXME: These libraries are platform specific - libPaths.push_back("/lib"); - libPaths.push_back("/usr/lib"); + LibraryPaths.push_back("/lib"); + LibraryPaths.push_back("/usr/lib"); } CompilerDriver::~CompilerDriver() { cdp = 0; - libPaths.clear(); + LibraryPaths.clear(); + PreprocessorOptions.clear(); + TranslatorOptions.clear(); + OptimizerOptions.clear(); + AssemblerOptions.clear(); + LinkerOptions.clear(); } void CompilerDriver::error( const std::string& errmsg ) { @@ -92,12 +111,27 @@ void CompilerDriver::error( const std::string& errmsg ) { exit(1); } +inline std::string makeDashO(CompilerDriver::OptimizationLevels lev) { + if (lev == CompilerDriver::OPT_NONE) return ""; + std::string result("-O"); + switch (lev) { + case CompilerDriver::OPT_FAST_COMPILE : result.append("1"); break; + case CompilerDriver::OPT_SIMPLE: result.append("2"); break; + case CompilerDriver::OPT_AGGRESSIVE: result.append("3"); break; + case CompilerDriver::OPT_LINK_TIME: result.append("4"); break; + case CompilerDriver::OPT_AGGRESSIVE_LINK_TIME: result.append("5"); break; + default: assert(!"Invalid optimization level!"); + } + return result; +} + CompilerDriver::Action* CompilerDriver::GetAction(ConfigData* cd, const std::string& input, const std::string& output, Phases phase) { Action* pat = 0; + // Get the action pattern switch (phase) { case PREPROCESSING: pat = &cd->PreProcessor; break; case TRANSLATION: pat = &cd->Translator; break; @@ -109,11 +143,57 @@ CompilerDriver::Action* CompilerDriver::GetAction(ConfigData* cd, break; } assert(pat != 0 && "Invalid command pattern"); + + // Create the resulting action Action* a = new Action(*pat); + + // Replace the substitution arguments if (pat->inputAt < a->args.size()) a->args[pat->inputAt] = input; if (pat->outputAt < a->args.size()) a->args[pat->outputAt] = output; + + // Insert specific options for each kind of action type + switch (phase) { + case PREPROCESSING: + a->args.insert(a->args.begin(), PreprocessorOptions.begin(), + PreprocessorOptions.end()); + break; + case TRANSLATION: + a->args.insert(a->args.begin(), TranslatorOptions.begin(), + TranslatorOptions.end()); + if (a->isSet(GROKS_DASH_O_FLAG)) + a->args.insert(a->args.begin(), makeDashO(optLevel)); + else if (a->isSet(GROKS_O10N_FLAG)) + a->args.insert(a->args.begin(), cd->opts[optLevel].begin(), + cd->opts[optLevel].end()); + break; + case OPTIMIZATION: + a->args.insert(a->args.begin(), OptimizerOptions.begin(), + OptimizerOptions.end()); + if (a->isSet(GROKS_DASH_O_FLAG)) + a->args.insert(a->args.begin(), makeDashO(optLevel)); + else if (a->isSet(GROKS_O10N_FLAG)) + a->args.insert(a->args.begin(), cd->opts[optLevel].begin(), + cd->opts[optLevel].end()); + break; + case ASSEMBLY: + a->args.insert(a->args.begin(), AssemblerOptions.begin(), + AssemblerOptions.end()); + break; + case LINKING: + a->args.insert(a->args.begin(), LinkerOptions.begin(), + LinkerOptions.end()); + if (a->isSet(GROKS_DASH_O_FLAG)) + a->args.insert(a->args.begin(), makeDashO(optLevel)); + else if (a->isSet(GROKS_O10N_FLAG)) + a->args.insert(a->args.begin(), cd->opts[optLevel].begin(), + cd->opts[optLevel].end()); + break; + default: + assert(!"Invalid driver phase!"); + break; + } return a; } @@ -122,18 +202,20 @@ void CompilerDriver::DoAction(Action*a) if (isVerbose) WriteAction(a); if (!isDryRun) { - std::cerr << "execve(\"" << a->program << "\",[\n"; + std::cerr << "execve(\"" << a->program << "\",[\""; std::vector::iterator I = a->args.begin(); while (I != a->args.end()) { - std::cerr << " \"" << *I << "\",\n"; + std::cerr << *I; ++I; + if (I != a->args.end()) + std::cerr << "\",\""; } - std::cerr << "],ENV);\n"; + std::cerr << "\"],ENV);\n"; } } int CompilerDriver::execute(const InputList& InpList, - const std::string& Output ) { + const sys::Path& Output ) { // Echo the configuration of options if we're running verbose if (isDebug) { @@ -162,8 +244,17 @@ int CompilerDriver::execute(const InputList& InpList, if (finalPhase == LINKING && Output.empty()) error("An output file name must be specified for linker output"); + // This vector holds all the resulting actions of the following loop. std::vector actions; + // Create a temporary directory for our temporary files + sys::Path TempDir(sys::Path::CONSTRUCT_TEMP_DIR); + sys::Path TempPreprocessorOut; + sys::Path TempTranslatorOut; + sys::Path TempOptimizerOut; + sys::Path TempAssemblerOut; + sys::Path TempLinkerOut; + /// PRE-PROCESSING / TRANSLATION / OPTIMIZATION / ASSEMBLY phases // for each input item std::vector LinkageItems; @@ -207,28 +298,59 @@ int CompilerDriver::execute(const InputList& InpList, OutFile = Output; } - /// PRE-PROCESSING PHASE - if (finalPhase == PREPROCESSING) { - if (cd->PreProcessor.program.empty()) - error(cd->langName + " does not support pre-processing"); - else - actions.push_back(GetAction(cd,I->first,OutFile,PREPROCESSING)); - } else if (cd->PreprocessorNeeded && !cd->TranslatorPreprocesses) { - if (!cd->PreProcessor.program.empty()) { - actions.push_back(GetAction(cd,I->first,OutFile,PREPROCESSING)); - } - } + // PRE-PROCESSING PHASE + Action& a = cd->PreProcessor; + // Get the preprocessing action, if needed, or error if appropriate + if (!a.program.empty()) { + if (a.isSet(REQUIRED_FLAG) || finalPhase == PREPROCESSING) { + TempPreprocessorOut = TempDir; + TempPreprocessorOut.append_file("preproc.out"); + actions.push_back(GetAction(cd,I->first, + TempPreprocessorOut,PREPROCESSING)); + } + } else if (finalPhase == PREPROCESSING) { + error(cd->langName + " does not support pre-processing"); + } else if (a.isSet(REQUIRED_FLAG)) { + error(std::string("Don't know how to pre-process ") + + cd->langName + " files"); + } // Short-circuit remaining actions if all they want is pre-processing if (finalPhase == PREPROCESSING) { ++I; continue; }; /// TRANSLATION PHASE - actions.push_back(GetAction(cd,I->first,OutFile,TRANSLATION)); + a = cd->Translator; + + // Get the translation action, if needed, or error if appropriate + if (!a.program.empty()) { + if (a.isSet(REQUIRED_FLAG) || finalPhase == TRANSLATION) { + TempTranslatorOut = TempDir; + TempTranslatorOut.append_file("trans.out"); + actions.push_back(GetAction(cd,I->first,TempTranslatorOut,TRANSLATION)); + } + } else if (finalPhase == TRANSLATION) { + error(cd->langName + " does not support translation"); + } else if (a.isSet(REQUIRED_FLAG)) { + error(std::string("Don't know how to translate ") + + cd->langName + " files"); + } // Short-circuit remaining actions if all they want is translation if (finalPhase == TRANSLATION) { ++I; continue; } /// OPTIMIZATION PHASE - actions.push_back(GetAction(cd,I->first,OutFile,OPTIMIZATION)); + a = cd->Optimizer; + + // Get the optimization action, if needed, or error if appropriate + if (!a.program.empty()) { + TempOptimizerOut = TempDir; + TempOptimizerOut.append_file("trans.out"); + actions.push_back(GetAction(cd,I->first,TempOptimizerOut,OPTIMIZATION)); + } else if (finalPhase == OPTIMIZATION) { + error(cd->langName + " does not support optimization"); + } else if (a.isSet(REQUIRED_FLAG)) { + error(std::string("Don't know how to optimize ") + + cd->langName + " files"); + } // Short-circuit remaining actions if all they want is optimization if (finalPhase == OPTIMIZATION) { ++I; continue; } @@ -244,6 +366,16 @@ int CompilerDriver::execute(const InputList& InpList, aIter++; } + // Cleanup files + if (TempPreprocessorOut.exists()) + TempPreprocessorOut.remove_file(); + if (TempTranslatorOut.exists()) + TempTranslatorOut.remove_file(); + if (TempOptimizerOut.exists()) + TempOptimizerOut.remove_file(); + if (TempDir.exists()) + TempDir.remove_directory(); + return 0; } diff --git a/tools/llvmc/CompilerDriver.h b/tools/llvmc/CompilerDriver.h index f49a780ba5e..da2a8f1a317 100644 --- a/tools/llvmc/CompilerDriver.h +++ b/tools/llvmc/CompilerDriver.h @@ -14,6 +14,7 @@ #ifndef LLVM_TOOLS_LLVMC_COMPILERDRIVER_H #define LLVM_TOOLS_LLVMC_COMPILERDRIVER_H +#include "llvm/System/Path.h" #include #include @@ -29,6 +30,10 @@ namespace llvm { /// @name Types /// @{ public: + /// @brief A vector of strings, commonly used + typedef std::vector StringVector; + + /// @brief The phases of processing that llvmc understands enum Phases { PREPROCESSING, ///< Source language combining, filtering, substitution TRANSLATION, ///< Translate source -> LLVM bytecode/assembly @@ -37,20 +42,31 @@ namespace llvm { ASSEMBLY, ///< Convert program to executable }; + /// @brief The levels of optimization llvmc understands enum OptimizationLevels { - OPT_NONE, ///< Zippo optimizations, nada, nil, none. OPT_FAST_COMPILE, ///< Optimize to make >compile< go faster OPT_SIMPLE, ///< Standard/simple optimizations OPT_AGGRESSIVE, ///< Aggressive optimizations OPT_LINK_TIME, ///< Aggressive + LinkTime optimizations - OPT_AGGRESSIVE_LINK_TIME ///< Make it go way fast! + OPT_AGGRESSIVE_LINK_TIME, ///< Make it go way fast! + OPT_NONE ///< No optimizations. Keep this at the end! + }; + + /// @brief Action specific flags + enum ConfigurationFlags { + REQUIRED_FLAG = 0x0001, ///< Should the action always be run? + GROKS_DASH_O_FLAG = 0x0002, ///< Understands the -On options? + PREPROCESSES_FLAG = 0x0004, ///< Does this action preprocess? + OPTIMIZES_FLAG = 0x0008, ///< Does this action optimize? + GROKS_O10N_FLAG = 0x0010, ///< Understands optimization options? + FLAGS_MASK = 0x001F, ///< Union of all flags }; /// This type is the input list to the CompilerDriver. It provides /// a vector of filename/filetype pairs. The filetype is used to look up /// the configuration of the actions to be taken by the driver. /// @brief The Input Data to the execute method - typedef std::vector > InputList; + typedef std::vector > InputList; /// This type is read from configuration files or otherwise provided to /// the CompilerDriver through a "ConfigDataProvider". It serves as both @@ -58,28 +74,25 @@ namespace llvm { /// @brief A structure to hold the action data for a given source /// language. struct Action { - Action() : inputAt(0) , outputAt(0) {} - std::string program; ///< The program to execve - std::vector args; ///< Arguments to the program - size_t inputAt; ///< Argument index to insert input file - size_t outputAt; ///< Argument index to insert output file + Action() : inputAt(0) , outputAt(0), flags(0) {} + sys::Path program; ///< The program to execve + StringVector args; ///< Arguments to the program + size_t inputAt; ///< Argument index to insert input file + size_t outputAt; ///< Argument index to insert output file + unsigned flags; ///< Action specific flags + void set(unsigned fl ) { flags |= fl; } + void clear(unsigned fl) { flags &= (FLAGS_MASK ^ fl); } + bool isSet(unsigned fl) { return flags&fl != 0; } }; struct ConfigData { - ConfigData() : TranslatorPreprocesses(false), - TranslatorOptimizes(false), - TranslatorGroksDashO(false), - PreprocessorNeeded(false) {} - std::string langName; ///< The name of the source language - bool TranslatorPreprocesses;///< Translator program will pre-process - bool TranslatorOptimizes; ///< Translator program will optimize too - bool TranslatorGroksDashO; ///< Translator understands -O arguments - bool PreprocessorNeeded; ///< Preprocessor is needed for translation - Action PreProcessor; ///< PreProcessor command line - Action Translator; ///< Translator command line - Action Optimizer; ///< Optimizer command line - Action Assembler; ///< Assembler command line - Action Linker; ///< Linker command line + std::string langName; ///< The name of the source language + std::vector opts; ///< The o10n options for each level + Action PreProcessor; ///< PreProcessor command line + Action Translator; ///< Translator command line + Action Optimizer; ///< Optimizer command line + Action Assembler; ///< Assembler command line + Action Linker; ///< Linker command line }; /// This pure virtual interface class defines the interface between the @@ -109,7 +122,7 @@ namespace llvm { virtual void error(const std::string& errmsg); /// @brief Execute the actions requested for the given input list. - virtual int execute(const InputList& list, const std::string& output); + virtual int execute(const InputList& list, const sys::Path& output); /// @} /// @name Mutators @@ -148,10 +161,40 @@ namespace llvm { machine = machineName; } + /// @brief Set Preprocessor specific options + void setPreprocessorOptions(const std::vector& opts) { + PreprocessorOptions = opts; + } + + /// @brief Set Translator specific options + void setTranslatorOptions(const std::vector& opts) { + TranslatorOptions = opts; + } + + /// @brief Set Optimizer specific options + void setOptimizerOptions(const std::vector& opts) { + OptimizerOptions = opts; + } + + /// @brief Set Assembler specific options + void setAssemblerOptions(const std::vector& opts) { + AssemblerOptions = opts; + } + + /// @brief Set Linker specific options + void setLinkerOptions(const std::vector& opts) { + LinkerOptions = opts; + } + + /// @brief Set Library Paths + void setLibraryPaths(const std::vector& paths) { + LibraryPaths = paths; + } + /// @brief Set the list of library paths to be searched for /// libraries. void addLibraryPath( const std::string& libPath ) { - libPaths.push_back(libPath); + LibraryPaths.push_back(libPath); } /// @} @@ -176,7 +219,12 @@ namespace llvm { bool emitRawCode; ///< Emit Raw (unoptimized) code? bool emitNativeCode; ///< Emit native code instead of bytecode? std::string machine; ///< Target machine name - std::vector libPaths; ///< list of dirs to find libraries + std::vector LibraryPaths; + std::vector PreprocessorOptions; + std::vector TranslatorOptions; + std::vector OptimizerOptions; + std::vector AssemblerOptions; + std::vector LinkerOptions; /// @} diff --git a/tools/llvmc/ConfigData.cpp b/tools/llvmc/ConfigData.cpp index d2e788bf12b..cfea9eb4356 100644 --- a/tools/llvmc/ConfigData.cpp +++ b/tools/llvmc/ConfigData.cpp @@ -21,16 +21,15 @@ using namespace llvm; -extern int ::Configlex(); +extern int ::Configlineno; namespace llvm { ConfigLexerInfo ConfigLexerData; InputProvider* ConfigLexerInput = 0; - unsigned ConfigLexerLine = 1; InputProvider::~InputProvider() {} void InputProvider::error(const std::string& msg) { - std::cerr << name << ":" << ConfigLexerLine << ": Error: " << msg << "\n"; + std::cerr << name << ":" << Configlineno << ": Error: " << msg << "\n"; errCount++; } @@ -66,9 +65,9 @@ namespace { std::ifstream F; }; - struct ParseContext + struct Parser { - int token; + ConfigLexerTokens token; InputProvider* provider; CompilerDriver::ConfigData* confDat; CompilerDriver::Action* action; @@ -131,38 +130,47 @@ namespace { return result; } - void parseLang() { - if ( next() == NAME ) { - confDat->langName = parseName(); - } else if (token == TRANSLATOR) { - switch (next()) { - case PREPROCESSES: - confDat->TranslatorPreprocesses = parseBoolean(); - break; - case OPTIMIZES: - confDat->TranslatorOptimizes = parseBoolean(); - break; - case GROKS_DASH_O: - confDat->TranslatorGroksDashO = parseBoolean(); - break; - default: - error("Invalid lang.translator identifier"); - break; + void parseOptionList(CompilerDriver::StringVector& optList ) { + while (next_is_real()) { + if (token == STRING || token == OPTION) + optList.push_back(ConfigLexerData.StringVal); + else { + error("Expecting a program option", false); + break; } } - else if (token == PREPROCESSOR) { - if (next() == NEEDED) - confDat->PreprocessorNeeded = parseBoolean(); - } - else { - error("Expecting valid identifier after 'lang.'"); + } + + void parseLang() { + switch (next() ) { + case NAME: + confDat->langName = parseName(); + break; + case OPT1: + parseOptionList(confDat->opts[CompilerDriver::OPT_FAST_COMPILE]); + break; + case OPT2: + parseOptionList(confDat->opts[CompilerDriver::OPT_SIMPLE]); + break; + case OPT3: + parseOptionList(confDat->opts[CompilerDriver::OPT_AGGRESSIVE]); + break; + case OPT4: + parseOptionList(confDat->opts[CompilerDriver::OPT_LINK_TIME]); + break; + case OPT5: + parseOptionList( + confDat->opts[CompilerDriver::OPT_AGGRESSIVE_LINK_TIME]); + break; + default: + error("Expecting 'name' or 'optN' after 'lang.'"); + break; } } void parseCommand(CompilerDriver::Action& action) { if (next() == EQUALS) { - next(); - if (token == EOLTOK) { + if (next() == EOLTOK) { // no value (valid) action.program.clear(); action.args.clear(); @@ -175,79 +183,161 @@ namespace { error("Expecting a program name"); } while (next_is_real()) { - if (token == STRING || token == OPTION) + if (token == STRING || token == OPTION) { action.args.push_back(ConfigLexerData.StringVal); - else if (token == IN_SUBST) { + } else if (token == IN_SUBST) { action.inputAt = action.args.size(); - action.args.push_back("in"); + action.args.push_back("@in@"); } else if (token == OUT_SUBST) { action.outputAt = action.args.size(); - action.args.push_back("out"); - } else + action.args.push_back("@out@"); + } else { error("Expecting a program argument", false); + break; + } } } } } - void parsePreProcessor() { - if (next() != COMMAND) { - error("Expecting 'command'"); - return; + void parsePreprocessor() { + switch (next()) { + case COMMAND: + parseCommand(confDat->PreProcessor); + break; + case REQUIRED: + if (parseBoolean()) + confDat->PreProcessor.set(CompilerDriver::REQUIRED_FLAG); + else + confDat->PreProcessor.clear(CompilerDriver::REQUIRED_FLAG); + break; + default: + error("Expecting 'command' or 'required'"); + break; } - parseCommand(confDat->PreProcessor); } void parseTranslator() { - if (next() != COMMAND) { - error("Expecting 'command'"); - return; + switch (next()) { + case COMMAND: + parseCommand(confDat->Translator); + break; + case REQUIRED: + if (parseBoolean()) + confDat->Translator.set(CompilerDriver::REQUIRED_FLAG); + else + confDat->Translator.clear(CompilerDriver::REQUIRED_FLAG); + break; + case PREPROCESSES: + if (parseBoolean()) + confDat->Translator.set(CompilerDriver::PREPROCESSES_FLAG); + else + confDat->Translator.clear(CompilerDriver::PREPROCESSES_FLAG); + break; + case OPTIMIZES: + if (parseBoolean()) + confDat->Translator.set(CompilerDriver::OPTIMIZES_FLAG); + else + confDat->Translator.clear(CompilerDriver::OPTIMIZES_FLAG); + break; + case GROKS_DASH_O: + if (parseBoolean()) + confDat->Translator.set(CompilerDriver::GROKS_DASH_O_FLAG); + else + confDat->Translator.clear(CompilerDriver::GROKS_DASH_O_FLAG); + break; + case GROKS_O10N: + if (parseBoolean()) + confDat->Translator.set(CompilerDriver::GROKS_O10N_FLAG); + else + confDat->Translator.clear(CompilerDriver::GROKS_O10N_FLAG); + break; + default: + error("Expecting 'command', 'required', 'preprocesses', " + "'groks_dash_O' or 'optimizes'"); + break; } - parseCommand(confDat->Translator); } void parseOptimizer() { - if (next() != COMMAND) { - error("Expecting 'command'"); - return; + switch (next()) { + case COMMAND: + parseCommand(confDat->Optimizer); + break; + case GROKS_DASH_O: + if (parseBoolean()) + confDat->Optimizer.set(CompilerDriver::GROKS_DASH_O_FLAG); + else + confDat->Optimizer.clear(CompilerDriver::GROKS_DASH_O_FLAG); + break; + case GROKS_O10N: + if (parseBoolean()) + confDat->Optimizer.set(CompilerDriver::GROKS_O10N_FLAG); + else + confDat->Optimizer.clear(CompilerDriver::GROKS_O10N_FLAG); + break; + default: + error("Expecting 'command' or 'groks_dash_O'"); + break; } - parseCommand(confDat->Optimizer); } void parseAssembler() { - if (next() != COMMAND) { - error("Expecting 'command'"); - return; + switch(next()) { + case COMMAND: + parseCommand(confDat->Assembler); + break; + default: + error("Expecting 'command'"); + break; } - parseCommand(confDat->Assembler); } void parseLinker() { - if (next() != COMMAND) { - error("Expecting 'command'"); - return; + switch(next()) { + case COMMAND: + parseCommand(confDat->Linker); + break; + case GROKS_DASH_O: + if (parseBoolean()) + confDat->Linker.set(CompilerDriver::GROKS_DASH_O_FLAG); + else + confDat->Linker.clear(CompilerDriver::GROKS_DASH_O_FLAG); + break; + case GROKS_O10N: + if (parseBoolean()) + confDat->Linker.set(CompilerDriver::GROKS_O10N_FLAG); + else + confDat->Linker.clear(CompilerDriver::GROKS_O10N_FLAG); + break; + default: + error("Expecting 'command'"); + break; } - parseCommand(confDat->Linker); } void parseAssignment() { switch (token) { - case LANG: return parseLang(); - case PREPROCESSOR: return parsePreProcessor(); - case TRANSLATOR: return parseTranslator(); - case OPTIMIZER: return parseOptimizer(); - case ASSEMBLER: return parseAssembler(); - case LINKER: return parseLinker(); + case LANG: parseLang(); break; + case PREPROCESSOR: parsePreprocessor(); break; + case TRANSLATOR: parseTranslator(); break; + case OPTIMIZER: parseOptimizer(); break; + case ASSEMBLER: parseAssembler(); break; + case LINKER: parseLinker(); break; case EOLTOK: break; // just ignore case ERRORTOK: default: - error("Invalid top level configuration item identifier"); + error("Invalid top level configuration item"); + break; } } void parseFile() { - while ( next() != 0 ) { - parseAssignment(); + while ( next() != EOFTOK ) { + if (token == ERRORTOK) + error("Invalid token"); + else if (token != EOLTOK) + parseAssignment(); } provider->checkErrors(); } @@ -255,12 +345,12 @@ namespace { void ParseConfigData(InputProvider& provider, CompilerDriver::ConfigData& confDat) { - ParseContext ctxt; - ctxt.token = 0; - ctxt.provider = &provider; - ctxt.confDat = &confDat; - ctxt.action = 0; - ctxt.parseFile(); + Parser p; + p.token = EOFTOK; + p.provider = &provider; + p.confDat = &confDat; + p.action = 0; + p.parseFile(); } } diff --git a/tools/llvmc/ConfigLexer.h b/tools/llvmc/ConfigLexer.h index 5a3e9e9f74f..fd25589e61b 100644 --- a/tools/llvmc/ConfigLexer.h +++ b/tools/llvmc/ConfigLexer.h @@ -25,7 +25,6 @@ struct ConfigLexerInfo }; extern ConfigLexerInfo ConfigLexerData; -extern unsigned ConfigLexerLine; class InputProvider { public: @@ -65,13 +64,21 @@ enum ConfigLexerTokens { ASSEMBLER, ///< The item "assembler" (and case variants) LINKER, ///< The item "linker" (and case variants) NAME, ///< The item "name" (and case variants) - NEEDED, ///< The item "needed" (and case variants) + REQUIRED, ///< The item "required" (and case variants) COMMAND, ///< The item "command" (and case variants) PREPROCESSES, ///< The item "preprocesses" (and case variants) GROKS_DASH_O, ///< The item "groks_dash_O" (and case variants) + GROKS_O10N, ///< The item "groks_optimization" (and case variants) OPTIMIZES, ///< The item "optimizes" (and case variants) + OPT1, ///< The item "opt1" (and case variants) + OPT2, ///< The item "opt2" (and case variants) + OPT3, ///< The item "opt3" (and case variants) + OPT4, ///< The item "opt4" (and case variants) + OPT5, ///< The item "opt5" (and case variants) }; +extern ConfigLexerTokens Configlex(); + } #endif diff --git a/tools/llvmc/ConfigLexer.l b/tools/llvmc/ConfigLexer.l index 58ddd2bdbdf..c0f42a3d903 100644 --- a/tools/llvmc/ConfigLexer.l +++ b/tools/llvmc/ConfigLexer.l @@ -38,6 +38,10 @@ if (result == 0 ) result = YY_NULL; \ } +#define YY_DECL ConfigLexerTokens llvm::Configlex() + +#define yyterminate() { return EOFTOK; } + using namespace llvm; /* Conversion of text ints to binary */ @@ -62,11 +66,17 @@ OPTIMIZER optimizer|Optimizer|OPTIMIZER ASSEMBLER assembler|Assembler|ASSEMBLER LINKER linker|Linker|LINKER NAME name|Name|NAME -NEEDED needed|Needed|NEEDED +REQUIRED required|Required|REQUIRED COMMAND command|Command|COMMAND PREPROCESSES preprocesses|PreProcesses|PREPROCESSES GROKS_DASH_O groks_dash_O|Groks_Dash_O|GROKS_DASH_O +GROKS_O10N groks_optimization|Groks_Optimization|GROKS_OPTIMIZATION OPTIMIZES optimizes|Optimizes|OPTIMIZES +OPT1 opt1|Opt1|OPT1 +OPT2 opt2|Opt2|OPT2 +OPT3 opt3|Opt3|OPT3 +OPT4 opt4|Opt4|OPT4 +OPT5 opt5|Opt5|OPT5 Comment \#[^\n]* NewLine \n White [ \t]* @@ -84,7 +94,8 @@ No no|No|NO %% -{NewLine} { in_value = false; ConfigLexerLine++; return EOLTOK; } +{NewLine} { in_value = false; return EOLTOK; } +{Eq} { in_value = true; return EQUALS; } {Comment} { /* Ignore comments */ } {White} { /* Ignore whitespace */ } @@ -102,19 +113,29 @@ No no|No|NO return OPTION; } else return LINKER; } {NAME} { if (in_value) { ConfigLexerData.StringVal = "name"; return OPTION; } else return NAME; } -{NEEDED} { if (in_value) { ConfigLexerData.StringVal = "needed"; - return OPTION; } else return NEEDED; } +{REQUIRED} { if (in_value) { ConfigLexerData.StringVal = "required"; + return OPTION; } else return REQUIRED; } {COMMAND} { if (in_value) { ConfigLexerData.StringVal = "command"; return OPTION; } else return COMMAND; } {PREPROCESSES} { if (in_value) { ConfigLexerData.StringVal = "preprocesses"; return OPTION; } else return PREPROCESSES; } {GROKS_DASH_O} { if (in_value) { ConfigLexerData.StringVal = "groks_dash_O"; return OPTION; } else return GROKS_DASH_O; } +{GROKS_O10N} { if (in_value) { ConfigLexerData.StringVal = + "groks_optimization"; return OPTION; } + else return GROKS_O10N; } {OPTIMIZES} { if (in_value) { ConfigLexerData.StringVal = "optimizes"; return OPTION; } else return OPTIMIZES; } -{Sep} { if (in_value) { ConfigLexerData.StringVal = yytext; - return OPTION; } } - +{OPT1} { if (in_value) { ConfigLexerData.StringVal = "opt1"; + return OPTION; } else return OPT1; } +{OPT2} { if (in_value) { ConfigLexerData.StringVal = "opt2"; + return OPTION; } else return OPT2; } +{OPT3} { if (in_value) { ConfigLexerData.StringVal = "opt3"; + return OPTION; } else return OPT3; } +{OPT4} { if (in_value) { ConfigLexerData.StringVal = "opt4"; + return OPTION; } else return OPT4; } +{OPT5} { if (in_value) { ConfigLexerData.StringVal = "opt5"; + return OPTION; } else return OPT5; } @in@ { if (in_value) return IN_SUBST; else return ERRORTOK; } @out@ { if (in_value) return OUT_SUBST; else return ERRORTOK; } {True} { if (in_value) return TRUETOK; else return ERRORTOK; } @@ -124,12 +145,14 @@ No no|No|NO {Off} { if (in_value) return FALSETOK; else return ERRORTOK; } {No} { if (in_value) return FALSETOK; else return ERRORTOK; } -{Eq} { in_value = true; return EQUALS; } {Option} { ConfigLexerData.StringVal = yytext; return OPTION; } {Integer} { ConfigLexerData.IntegerVal = IntToVal(yytext); return INTEGER; } {String} { yytext[yyleng-1] = 0; // nuke end quote ConfigLexerData.StringVal = yytext+1; // Nuke start quote return STRING; } +{Sep} { if (in_value) { ConfigLexerData.StringVal = yytext; + return OPTION; } } + %% diff --git a/tools/llvmc/Configuration.cpp b/tools/llvmc/Configuration.cpp index d2e788bf12b..cfea9eb4356 100644 --- a/tools/llvmc/Configuration.cpp +++ b/tools/llvmc/Configuration.cpp @@ -21,16 +21,15 @@ using namespace llvm; -extern int ::Configlex(); +extern int ::Configlineno; namespace llvm { ConfigLexerInfo ConfigLexerData; InputProvider* ConfigLexerInput = 0; - unsigned ConfigLexerLine = 1; InputProvider::~InputProvider() {} void InputProvider::error(const std::string& msg) { - std::cerr << name << ":" << ConfigLexerLine << ": Error: " << msg << "\n"; + std::cerr << name << ":" << Configlineno << ": Error: " << msg << "\n"; errCount++; } @@ -66,9 +65,9 @@ namespace { std::ifstream F; }; - struct ParseContext + struct Parser { - int token; + ConfigLexerTokens token; InputProvider* provider; CompilerDriver::ConfigData* confDat; CompilerDriver::Action* action; @@ -131,38 +130,47 @@ namespace { return result; } - void parseLang() { - if ( next() == NAME ) { - confDat->langName = parseName(); - } else if (token == TRANSLATOR) { - switch (next()) { - case PREPROCESSES: - confDat->TranslatorPreprocesses = parseBoolean(); - break; - case OPTIMIZES: - confDat->TranslatorOptimizes = parseBoolean(); - break; - case GROKS_DASH_O: - confDat->TranslatorGroksDashO = parseBoolean(); - break; - default: - error("Invalid lang.translator identifier"); - break; + void parseOptionList(CompilerDriver::StringVector& optList ) { + while (next_is_real()) { + if (token == STRING || token == OPTION) + optList.push_back(ConfigLexerData.StringVal); + else { + error("Expecting a program option", false); + break; } } - else if (token == PREPROCESSOR) { - if (next() == NEEDED) - confDat->PreprocessorNeeded = parseBoolean(); - } - else { - error("Expecting valid identifier after 'lang.'"); + } + + void parseLang() { + switch (next() ) { + case NAME: + confDat->langName = parseName(); + break; + case OPT1: + parseOptionList(confDat->opts[CompilerDriver::OPT_FAST_COMPILE]); + break; + case OPT2: + parseOptionList(confDat->opts[CompilerDriver::OPT_SIMPLE]); + break; + case OPT3: + parseOptionList(confDat->opts[CompilerDriver::OPT_AGGRESSIVE]); + break; + case OPT4: + parseOptionList(confDat->opts[CompilerDriver::OPT_LINK_TIME]); + break; + case OPT5: + parseOptionList( + confDat->opts[CompilerDriver::OPT_AGGRESSIVE_LINK_TIME]); + break; + default: + error("Expecting 'name' or 'optN' after 'lang.'"); + break; } } void parseCommand(CompilerDriver::Action& action) { if (next() == EQUALS) { - next(); - if (token == EOLTOK) { + if (next() == EOLTOK) { // no value (valid) action.program.clear(); action.args.clear(); @@ -175,79 +183,161 @@ namespace { error("Expecting a program name"); } while (next_is_real()) { - if (token == STRING || token == OPTION) + if (token == STRING || token == OPTION) { action.args.push_back(ConfigLexerData.StringVal); - else if (token == IN_SUBST) { + } else if (token == IN_SUBST) { action.inputAt = action.args.size(); - action.args.push_back("in"); + action.args.push_back("@in@"); } else if (token == OUT_SUBST) { action.outputAt = action.args.size(); - action.args.push_back("out"); - } else + action.args.push_back("@out@"); + } else { error("Expecting a program argument", false); + break; + } } } } } - void parsePreProcessor() { - if (next() != COMMAND) { - error("Expecting 'command'"); - return; + void parsePreprocessor() { + switch (next()) { + case COMMAND: + parseCommand(confDat->PreProcessor); + break; + case REQUIRED: + if (parseBoolean()) + confDat->PreProcessor.set(CompilerDriver::REQUIRED_FLAG); + else + confDat->PreProcessor.clear(CompilerDriver::REQUIRED_FLAG); + break; + default: + error("Expecting 'command' or 'required'"); + break; } - parseCommand(confDat->PreProcessor); } void parseTranslator() { - if (next() != COMMAND) { - error("Expecting 'command'"); - return; + switch (next()) { + case COMMAND: + parseCommand(confDat->Translator); + break; + case REQUIRED: + if (parseBoolean()) + confDat->Translator.set(CompilerDriver::REQUIRED_FLAG); + else + confDat->Translator.clear(CompilerDriver::REQUIRED_FLAG); + break; + case PREPROCESSES: + if (parseBoolean()) + confDat->Translator.set(CompilerDriver::PREPROCESSES_FLAG); + else + confDat->Translator.clear(CompilerDriver::PREPROCESSES_FLAG); + break; + case OPTIMIZES: + if (parseBoolean()) + confDat->Translator.set(CompilerDriver::OPTIMIZES_FLAG); + else + confDat->Translator.clear(CompilerDriver::OPTIMIZES_FLAG); + break; + case GROKS_DASH_O: + if (parseBoolean()) + confDat->Translator.set(CompilerDriver::GROKS_DASH_O_FLAG); + else + confDat->Translator.clear(CompilerDriver::GROKS_DASH_O_FLAG); + break; + case GROKS_O10N: + if (parseBoolean()) + confDat->Translator.set(CompilerDriver::GROKS_O10N_FLAG); + else + confDat->Translator.clear(CompilerDriver::GROKS_O10N_FLAG); + break; + default: + error("Expecting 'command', 'required', 'preprocesses', " + "'groks_dash_O' or 'optimizes'"); + break; } - parseCommand(confDat->Translator); } void parseOptimizer() { - if (next() != COMMAND) { - error("Expecting 'command'"); - return; + switch (next()) { + case COMMAND: + parseCommand(confDat->Optimizer); + break; + case GROKS_DASH_O: + if (parseBoolean()) + confDat->Optimizer.set(CompilerDriver::GROKS_DASH_O_FLAG); + else + confDat->Optimizer.clear(CompilerDriver::GROKS_DASH_O_FLAG); + break; + case GROKS_O10N: + if (parseBoolean()) + confDat->Optimizer.set(CompilerDriver::GROKS_O10N_FLAG); + else + confDat->Optimizer.clear(CompilerDriver::GROKS_O10N_FLAG); + break; + default: + error("Expecting 'command' or 'groks_dash_O'"); + break; } - parseCommand(confDat->Optimizer); } void parseAssembler() { - if (next() != COMMAND) { - error("Expecting 'command'"); - return; + switch(next()) { + case COMMAND: + parseCommand(confDat->Assembler); + break; + default: + error("Expecting 'command'"); + break; } - parseCommand(confDat->Assembler); } void parseLinker() { - if (next() != COMMAND) { - error("Expecting 'command'"); - return; + switch(next()) { + case COMMAND: + parseCommand(confDat->Linker); + break; + case GROKS_DASH_O: + if (parseBoolean()) + confDat->Linker.set(CompilerDriver::GROKS_DASH_O_FLAG); + else + confDat->Linker.clear(CompilerDriver::GROKS_DASH_O_FLAG); + break; + case GROKS_O10N: + if (parseBoolean()) + confDat->Linker.set(CompilerDriver::GROKS_O10N_FLAG); + else + confDat->Linker.clear(CompilerDriver::GROKS_O10N_FLAG); + break; + default: + error("Expecting 'command'"); + break; } - parseCommand(confDat->Linker); } void parseAssignment() { switch (token) { - case LANG: return parseLang(); - case PREPROCESSOR: return parsePreProcessor(); - case TRANSLATOR: return parseTranslator(); - case OPTIMIZER: return parseOptimizer(); - case ASSEMBLER: return parseAssembler(); - case LINKER: return parseLinker(); + case LANG: parseLang(); break; + case PREPROCESSOR: parsePreprocessor(); break; + case TRANSLATOR: parseTranslator(); break; + case OPTIMIZER: parseOptimizer(); break; + case ASSEMBLER: parseAssembler(); break; + case LINKER: parseLinker(); break; case EOLTOK: break; // just ignore case ERRORTOK: default: - error("Invalid top level configuration item identifier"); + error("Invalid top level configuration item"); + break; } } void parseFile() { - while ( next() != 0 ) { - parseAssignment(); + while ( next() != EOFTOK ) { + if (token == ERRORTOK) + error("Invalid token"); + else if (token != EOLTOK) + parseAssignment(); } provider->checkErrors(); } @@ -255,12 +345,12 @@ namespace { void ParseConfigData(InputProvider& provider, CompilerDriver::ConfigData& confDat) { - ParseContext ctxt; - ctxt.token = 0; - ctxt.provider = &provider; - ctxt.confDat = &confDat; - ctxt.action = 0; - ctxt.parseFile(); + Parser p; + p.token = EOFTOK; + p.provider = &provider; + p.confDat = &confDat; + p.action = 0; + p.parseFile(); } } diff --git a/tools/llvmc/Makefile b/tools/llvmc/Makefile index 8708209424d..94cb209e935 100644 --- a/tools/llvmc/Makefile +++ b/tools/llvmc/Makefile @@ -8,6 +8,6 @@ ##===----------------------------------------------------------------------===## LEVEL = ../.. TOOLNAME = llvmc -USEDLIBS = asmparser bcreader bcwriter vmcore support.a +USEDLIBS = asmparser bcreader bcwriter vmcore support.a system.a include $(LEVEL)/Makefile.common diff --git a/tools/llvmc/llvmc.cpp b/tools/llvmc/llvmc.cpp index 9cf43cb3fff..1640803cd4e 100644 --- a/tools/llvmc/llvmc.cpp +++ b/tools/llvmc/llvmc.cpp @@ -69,19 +69,23 @@ static cl::opt OptLevel( //=== TOOL OPTIONS //===------------------------------------------------------------------------=== -static cl::opt PPToolOpts("Tpp", cl::ZeroOrMore, +static cl::list PreprocessorToolOpts("Tpre", cl::ZeroOrMore, cl::desc("Pass specific options to the pre-processor"), cl::value_desc("option")); -static cl::opt AsmToolOpts("Tasm", cl::ZeroOrMore, +static cl::list TranslatorToolOpts("Ttrn", cl::ZeroOrMore, cl::desc("Pass specific options to the assembler"), cl::value_desc("option")); -static cl::opt OptToolOpts("Topt", cl::ZeroOrMore, +static cl::list AssemblerToolOpts("Tasm", cl::ZeroOrMore, + cl::desc("Pass specific options to the assembler"), + cl::value_desc("option")); + +static cl::list OptimizerToolOpts("Topt", cl::ZeroOrMore, cl::desc("Pass specific options to the optimizer"), cl::value_desc("option")); -static cl::opt LinkToolOpts("Tlink", cl::ZeroOrMore, +static cl::list LinkerToolOpts("Tlnk", cl::ZeroOrMore, cl::desc("Pass specific options to the linker"), cl::value_desc("option")); @@ -142,9 +146,12 @@ static cl::opt ConfigDir("config-dir", cl::Optional, cl::desc("Specify a configuration directory to override defaults"), cl::value_desc("directory")); -static cl::opt EmitRawCode("emit-raw-code", cl::Hidden, +static cl::opt EmitRawCode("emit-raw-code", cl::Hidden, cl::Optional, cl::desc("Emit raw, unoptimized code")); +static cl::opt PipeCommands("pipe", cl::Optional, + cl::desc("Invoke sub-commands by linking input/output with pipes")); + //===------------------------------------------------------------------------=== //=== POSITIONAL OPTIONS //===------------------------------------------------------------------------=== @@ -200,6 +207,8 @@ int main(int argc, char **argv) { std::cerr << argv[0] << ": Not implemented yet: -native"; if (EmitRawCode) std::cerr << argv[0] << ": Not implemented yet: -emit-raw-code"; + if (PipeCommands) + std::cerr << argv[0] << ": Not implemented yet: -pipe"; // Default the output file, only if we're going to try to link if (OutputFilename.empty() && OptLevel == CompilerDriver::LINKING) @@ -221,10 +230,12 @@ int main(int argc, char **argv) { CD.setOutputMachine(OutputMachine); CD.setEmitNativeCode(Native); CD.setEmitRawCode(EmitRawCode); - std::vector::iterator pathIt = LibPaths.begin(); - while ( pathIt != LibPaths.end() ) { - CD.addLibraryPath( *pathIt++ ); - } + CD.setLibraryPaths(LibPaths); + CD.setPreprocessorOptions(PreprocessorToolOpts); + CD.setTranslatorOptions(TranslatorToolOpts); + CD.setOptimizerOptions(OptimizerToolOpts); + CD.setAssemblerOptions(AssemblerToolOpts); + CD.setLinkerOptions(LinkerToolOpts); // Prepare the list of files to be compiled by the CompilerDriver. CompilerDriver::InputList InpList;