diff options
Diffstat (limited to 'tools/llvmc')
-rw-r--r-- | tools/llvmc/CompilerDriver.cpp | 384 | ||||
-rw-r--r-- | tools/llvmc/CompilerDriver.h | 81 | ||||
-rw-r--r-- | tools/llvmc/ConfigData.cpp | 112 | ||||
-rw-r--r-- | tools/llvmc/ConfigLexer.h | 13 | ||||
-rw-r--r-- | tools/llvmc/ConfigLexer.l | 187 | ||||
-rw-r--r-- | tools/llvmc/Configuration.cpp | 112 | ||||
-rw-r--r-- | tools/llvmc/Makefile | 2 | ||||
-rw-r--r-- | tools/llvmc/ll | 1 | ||||
-rw-r--r-- | tools/llvmc/llvmc.cpp | 214 | ||||
-rw-r--r-- | tools/llvmc/st | 70 |
10 files changed, 726 insertions, 450 deletions
diff --git a/tools/llvmc/CompilerDriver.cpp b/tools/llvmc/CompilerDriver.cpp index f0ae129cea..f124219a0d 100644 --- a/tools/llvmc/CompilerDriver.cpp +++ b/tools/llvmc/CompilerDriver.cpp @@ -14,6 +14,7 @@ #include "CompilerDriver.h" #include "ConfigLexer.h" +#include "Support/SystemUtils.h" #include <iostream> using namespace llvm; @@ -33,27 +34,25 @@ namespace { const char OutputSuffix[] = ".o"; - void WriteAction(CompilerDriver::Action* a ) { - std::cerr << a->program; - std::vector<std::string>::iterator I = a->args.begin(); - while (I != a->args.end()) { + void WriteAction(CompilerDriver::Action* action ) { + std::cerr << action->program; + std::vector<std::string>::iterator I = action->args.begin(); + while (I != action->args.end()) { std::cerr << " " + *I; ++I; } std::cerr << "\n"; } - void DumpAction(CompilerDriver::Action* a) { - std::cerr << "command = " << a->program; - std::vector<std::string>::iterator I = a->args.begin(); - while (I != a->args.end()) { + void DumpAction(CompilerDriver::Action* action) { + std::cerr << "command = " << action->program; + std::vector<std::string>::iterator I = action->args.begin(); + while (I != action->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"; + std::cerr << "flags = " << action->flags << "\n"; } void DumpConfigData(CompilerDriver::ConfigData* cd, const std::string& type ){ @@ -79,11 +78,57 @@ namespace { /// This specifies the passes to run for OPT_FAST_COMPILE (-O1) /// which should reduce the volume of code and make compilation /// faster. This is also safe on any llvm module. - static const char* DefaultOptimizations[] = { - "-simplifycfg", "-mem2reg", "-mergereturn", "-instcombine", + static const char* DefaultFastCompileOptimizations[] = { + "-simplifycfg", "-mem2reg", "-instcombine" }; } +// Stuff in this namespace properly belongs in lib/System and needs +// to be portable but we're avoiding that for now. +namespace sys { + std::string MakeTemporaryDirectory() { + char temp_name[64]; + strcpy(temp_name,"/tmp/llvm_XXXXXX"); + if (0 == mkdtemp(temp_name)) + throw std::string("Can't create temporary directory"); + return temp_name; + } + + std::string FindExecutableInPath(const std::string& program) { + // First, just see if the program is already executable + if (isExecutableFile(program)) return program; + + // Get the path. If its empty, we can't do anything + const char *PathStr = getenv("PATH"); + if (PathStr == 0) return ""; + + // Now we have a colon separated list of directories to search; try them. + unsigned PathLen = strlen(PathStr); + while (PathLen) { + // Find the first colon... + const char *Colon = std::find(PathStr, PathStr+PathLen, ':'); + + // Check to see if this first directory contains the executable... + std::string FilePath = std::string(PathStr, Colon) + '/' + program; + if (isExecutableFile(FilePath)) + return FilePath; // Found the executable! + + // Nope it wasn't in this directory, check the next range! + PathLen -= Colon-PathStr; + PathStr = Colon; + + // Advance past duplicate coons + while (*PathStr == ':') { + PathStr++; + PathLen--; + } + } + + // If we fell out, we ran out of directories in PATH to search, return failure + return ""; + } +} + CompilerDriver::CompilerDriver(ConfigDataProvider& confDatProv ) : cdp(&confDatProv) , finalPhase(LINKING) @@ -94,46 +139,43 @@ CompilerDriver::CompilerDriver(ConfigDataProvider& confDatProv ) , timeActions(false) , emitRawCode(false) , emitNativeCode(false) + , keepTemps(false) , machine() , LibraryPaths() - , PreprocessorOptions() - , TranslatorOptions() - , OptimizerOptions() - , AssemblerOptions() - , LinkerOptions() + , AdditionalArgs() + , TempDir() { // FIXME: These libraries are platform specific LibraryPaths.push_back("/lib"); LibraryPaths.push_back("/usr/lib"); + AdditionalArgs.reserve(NUM_PHASES); + StringVector emptyVec; + for (unsigned i = 0; i < NUM_PHASES; ++i) + AdditionalArgs.push_back(emptyVec); } CompilerDriver::~CompilerDriver() { cdp = 0; LibraryPaths.clear(); - PreprocessorOptions.clear(); - TranslatorOptions.clear(); - OptimizerOptions.clear(); - AssemblerOptions.clear(); - LinkerOptions.clear(); + AdditionalArgs.clear(); } -void CompilerDriver::error( const std::string& errmsg ) { - std::cerr << "Error: " << errmsg << ".\n"; - exit(1); +CompilerDriver::ConfigData::ConfigData() + : langName() + , PreProcessor() + , Translator() + , Optimizer() + , Assembler() + , Linker() +{ + StringVector emptyVec; + for (unsigned i = 0; i < NUM_PHASES; ++i) + opts.push_back(emptyVec); } -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; +void CompilerDriver::error( const std::string& errmsg ) { + std::cerr << "llvmc: Error: " << errmsg << ".\n"; + exit(1); } CompilerDriver::Action* CompilerDriver::GetAction(ConfigData* cd, @@ -141,7 +183,9 @@ CompilerDriver::Action* CompilerDriver::GetAction(ConfigData* cd, const std::string& output, Phases phase) { - Action* pat = 0; + Action* pat = 0; ///< The pattern/template for the action + Action* action = new Action; ///< The actual action to execute + // Get the action pattern switch (phase) { case PREPROCESSING: pat = &cd->PreProcessor; break; @@ -155,74 +199,93 @@ CompilerDriver::Action* CompilerDriver::GetAction(ConfigData* cd, } assert(pat != 0 && "Invalid command pattern"); - // Create the resulting action - Action* a = new Action(*pat); + // Copy over some pattern things that don't need to change + action->program = pat->program; + action->flags = pat->flags; + + // Do the substitutions from the pattern to the actual + StringVector::iterator PI = pat->args.begin(); + StringVector::iterator PE = pat->args.end(); + while (PI != PE) { + if ((*PI)[0] == '@') { + if (*PI == "@in@") { + action->args.push_back(input); + } else if (*PI == "@out@") { + action->args.push_back(output); + } else if (*PI == "@time@") { + if (timePasses) + action->args.push_back("-time-passes"); + } else if (*PI == "@stats@") { + if (showStats) + action->args.push_back("-stats"); + } else if (*PI == "@target@") { + // FIXME: Ignore for now + } else if (*PI == "@opt@") { + if (!emitRawCode) { + if (pat->isSet(GROKS_DASH_O)) { + if (optLevel != OPT_NONE) { + std::string optArg("-O"); + switch (optLevel) { + case OPT_FAST_COMPILE : optArg.append("1"); break; + case OPT_SIMPLE: optArg.append("2"); break; + case OPT_AGGRESSIVE: optArg.append("3"); break; + case OPT_LINK_TIME: optArg.append("4"); break; + case OPT_AGGRESSIVE_LINK_TIME: optArg.append("5"); break; + default : + assert(!"Invalid optimization argument!"); + optArg.append("0"); + break; + } + action->args.push_back(optArg); + } + } else { + if (cd->opts.size() > static_cast<unsigned>(optLevel) && + !cd->opts[optLevel].empty()) + action->args.insert(action->args.end(), cd->opts[optLevel].begin(), + cd->opts[optLevel].end()); + } + } + } else { + error("Invalid substitution name"); + } + } else { + // Its not a substitution, just put it in the action + action->args.push_back(*PI); + } + PI++; + } - // 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; + // Get specific options for each kind of action type + StringVector& args = AdditionalArgs[phase]; - // 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; + // Add specific options for each kind of action type + action->args.insert(action->args.end(), args.begin(), args.end()); + + // Finally, we're done + return action; } -void CompilerDriver::DoAction(Action*a) -{ +bool CompilerDriver::DoAction(Action*action) { + assert(action != 0 && "Invalid Action!"); if (isVerbose) - WriteAction(a); + WriteAction(action); if (!isDryRun) { - std::cerr << "execve(\"" << a->program << "\",[\""; - std::vector<std::string>::iterator I = a->args.begin(); - while (I != a->args.end()) { - std::cerr << *I; - ++I; - if (I != a->args.end()) - std::cerr << "\",\""; - } - std::cerr << "\"],ENV);\n"; + std::string prog(sys::FindExecutableInPath(action->program)); + if (prog.empty()) + error("Can't find program '" + action->program + "'"); + + // Get the program's arguments + const char* argv[action->args.size() + 1]; + argv[0] = prog.c_str(); + unsigned i = 1; + for (; i <= action->args.size(); ++i) + argv[i] = action->args[i-1].c_str(); + argv[i] = 0; + + // Invoke the program + return !ExecWait(argv, environ); } + return true; } int CompilerDriver::execute(const InputList& InpList, @@ -259,15 +322,11 @@ int CompilerDriver::execute(const InputList& InpList, std::vector<Action*> actions; // Create a temporary directory for our temporary files - char temp_name[64]; - strcpy(temp_name,"/tmp/llvm_XXXXXX"); - if (0 == mkdtemp(temp_name)) - error("Can't create temporary directory"); - std::string TempDir(temp_name); - std::string TempPreprocessorOut(TempDir + "/preproc.tmp"); - std::string TempTranslatorOut(TempDir + "/trans.tmp"); - std::string TempOptimizerOut(TempDir + "/opt.tmp"); - std::string TempAssemblerOut(TempDir + "/asm.tmp"); + std::string TempDir(sys::MakeTemporaryDirectory()); + std::string TempPreprocessorOut(TempDir + "/preproc.o"); + std::string TempTranslatorOut(TempDir + "/trans.o"); + std::string TempOptimizerOut(TempDir + "/opt.o"); + std::string TempAssemblerOut(TempDir + "/asm.o"); /// PRE-PROCESSING / TRANSLATION / OPTIMIZATION / ASSEMBLY phases // for each input item @@ -312,76 +371,137 @@ int CompilerDriver::execute(const InputList& InpList, OutFile = Output; } + // Initialize the input file + std::string InFile(I->first); + // PRE-PROCESSING PHASE - Action& a = cd->PreProcessor; + Action& action = cd->PreProcessor; // Get the preprocessing action, if needed, or error if appropriate - if (!a.program.empty()) { - if (a.isSet(REQUIRED_FLAG) || finalPhase == PREPROCESSING) { - actions.push_back(GetAction(cd,I->first, - TempPreprocessorOut,PREPROCESSING)); + if (!action.program.empty()) { + if (action.isSet(REQUIRED_FLAG) || finalPhase == PREPROCESSING) { + if (finalPhase == PREPROCESSING) + actions.push_back(GetAction(cd,InFile,OutFile,PREPROCESSING)); + else { + actions.push_back(GetAction(cd,InFile,TempPreprocessorOut, + PREPROCESSING)); + InFile = TempPreprocessorOut; + } } } else if (finalPhase == PREPROCESSING) { error(cd->langName + " does not support pre-processing"); - } else if (a.isSet(REQUIRED_FLAG)) { + } else if (action.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 - a = cd->Translator; + action = cd->Translator; // Get the translation action, if needed, or error if appropriate - if (!a.program.empty()) { - if (a.isSet(REQUIRED_FLAG) || finalPhase == TRANSLATION) { - actions.push_back(GetAction(cd,I->first,TempTranslatorOut,TRANSLATION)); + if (!action.program.empty()) { + if (action.isSet(REQUIRED_FLAG) || finalPhase == TRANSLATION) { + if (finalPhase == TRANSLATION) + actions.push_back(GetAction(cd,InFile,OutFile,TRANSLATION)); + else { + actions.push_back(GetAction(cd,InFile,TempTranslatorOut,TRANSLATION)); + InFile = TempTranslatorOut; + } + + // ll -> bc Helper + if (action.isSet(OUTPUT_IS_ASM_FLAG)) { + /// The output of the translator is an LLVM Assembly program + /// We need to translate it to bytecode + Action* action = new Action(); + action->program = "llvm-as"; + action->args.push_back(InFile); + action->args.push_back("-o"); + InFile += ".bc"; + action->args.push_back(InFile); + actions.push_back(action); + } } } else if (finalPhase == TRANSLATION) { error(cd->langName + " does not support translation"); - } else if (a.isSet(REQUIRED_FLAG)) { + } else if (action.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 - a = cd->Optimizer; + action = cd->Optimizer; // Get the optimization action, if needed, or error if appropriate - if (!a.program.empty()) { - actions.push_back(GetAction(cd,I->first,TempOptimizerOut,OPTIMIZATION)); + if (!action.program.empty() && !emitRawCode) { + if (action.isSet(REQUIRED_FLAG) || finalPhase == OPTIMIZATION) { + if (finalPhase == OPTIMIZATION) + actions.push_back(GetAction(cd,InFile,OutFile,OPTIMIZATION)); + else { + actions.push_back(GetAction(cd,InFile,TempOptimizerOut,OPTIMIZATION)); + InFile = TempOptimizerOut; + } + // ll -> bc Helper + if (action.isSet(OUTPUT_IS_ASM_FLAG)) { + /// The output of the translator is an LLVM Assembly program + /// We need to translate it to bytecode + Action* action = new Action(); + action->program = "llvm-as"; + action->args.push_back(InFile); + action->args.push_back("-o"); + InFile += ".bc"; + action->args.push_back(InFile); + actions.push_back(action); + } + } } else if (finalPhase == OPTIMIZATION) { error(cd->langName + " does not support optimization"); - } else if (a.isSet(REQUIRED_FLAG)) { + } else if (action.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; } + /// ASSEMBLY PHASE + if (emitNativeCode) { + // We must cause native code to be generated + } else { + } + + // Go to next file to be processed ++I; } /// LINKING PHASE + if (emitNativeCode) { + } else { + } /// RUN THE ACTIONS std::vector<Action*>::iterator aIter = actions.begin(); while (aIter != actions.end()) { - DoAction(*aIter); + if (!DoAction(*aIter)) + error("Action failed"); aIter++; } - // Cleanup files - CleanupTempFile(TempPreprocessorOut.c_str()); - CleanupTempFile(TempTranslatorOut.c_str()); - CleanupTempFile(TempOptimizerOut.c_str()); + if (!keepTemps) { + // Cleanup files + CleanupTempFile(TempPreprocessorOut.c_str()); + CleanupTempFile(TempTranslatorOut.c_str()); + CleanupTempFile(TempOptimizerOut.c_str()); - // Cleanup temporary directory we created - if (0 == access(TempDir.c_str(), F_OK | W_OK)) - rmdir(TempDir.c_str()); + // Cleanup temporary directory we created + if (0 == access(TempDir.c_str(), F_OK | W_OK)) + rmdir(TempDir.c_str()); + } return 0; } diff --git a/tools/llvmc/CompilerDriver.h b/tools/llvmc/CompilerDriver.h index 0914feca4c..4b825e22ea 100644 --- a/tools/llvmc/CompilerDriver.h +++ b/tools/llvmc/CompilerDriver.h @@ -32,13 +32,17 @@ namespace llvm { /// @brief A vector of strings, commonly used typedef std::vector<std::string> StringVector; + /// @brief A table of strings, indexed typically by Phases + typedef std::vector<StringVector> StringTable; + /// @brief The phases of processing that llvmc understands enum Phases { PREPROCESSING, ///< Source language combining, filtering, substitution TRANSLATION, ///< Translate source -> LLVM bytecode/assembly OPTIMIZATION, ///< Optimize translation result - LINKING, ///< Link bytecode and native code ASSEMBLY, ///< Convert program to executable + LINKING, ///< Link bytecode and native code + NUM_PHASES ///< Always last! }; /// @brief The levels of optimization llvmc understands @@ -56,9 +60,10 @@ namespace llvm { 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 + TRANSLATES_FLAG = 0x0008, ///< Does this action translate? + OPTIMIZES_FLAG = 0x0010, ///< Does this action optimize? + OUTPUT_IS_ASM_FLAG = 0x0020, ///< Action produces .ll files? + FLAGS_MASK = 0x003F, ///< Union of all flags }; /// This type is the input list to the CompilerDriver. It provides @@ -73,25 +78,24 @@ namespace llvm { /// @brief A structure to hold the action data for a given source /// language. struct Action { - Action() : inputAt(0) , outputAt(0), flags(0) {} + Action() : flags(0) {} std::string 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; } + bool isSet(unsigned fl) { return (flags&fl) != 0; } }; struct ConfigData { - std::string langName; ///< The name of the source language - std::vector<StringVector> 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 + ConfigData(); + std::string langName; ///< The name of the source language + StringTable 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 @@ -148,6 +152,12 @@ namespace llvm { /// execution time of each action taken. void setTimeActions( bool TF ) { timeActions = TF; } + /// @brief Cause the CompilerDriver to print timings for each pass. + void setTimePasses( bool TF ) { timePasses = TF; } + + /// @brief Cause the CompilerDriver to show statistics gathered + void setShowStats( bool TF ) { showStats = TF; } + /// @brief Indicate that native code is to be generated instead /// of LLVM bytecode. void setEmitNativeCode( bool TF ) { emitNativeCode = TF; } @@ -155,34 +165,17 @@ namespace llvm { /// @brief Indicate that raw, unoptimized code is to be generated. void setEmitRawCode(bool TF ) { emitRawCode = TF; } + void setKeepTemporaries(bool TF) { keepTemps = TF; } + /// @brief Set the output machine name. void setOutputMachine( const std::string& machineName ) { machine = machineName; } /// @brief Set Preprocessor specific options - void setPreprocessorOptions(const std::vector<std::string>& opts) { - PreprocessorOptions = opts; - } - - /// @brief Set Translator specific options - void setTranslatorOptions(const std::vector<std::string>& opts) { - TranslatorOptions = opts; - } - - /// @brief Set Optimizer specific options - void setOptimizerOptions(const std::vector<std::string>& opts) { - OptimizerOptions = opts; - } - - /// @brief Set Assembler specific options - void setAssemblerOptions(const std::vector<std::string>& opts) { - AssemblerOptions = opts; - } - - /// @brief Set Linker specific options - void setLinkerOptions(const std::vector<std::string>& opts) { - LinkerOptions = opts; + void setPhaseArgs(Phases phase, const std::vector<std::string>& opts) { + assert(phase <= LINKING && phase >= PREPROCESSING); + AdditionalArgs[phase] = opts; } /// @brief Set Library Paths @@ -202,7 +195,7 @@ namespace llvm { private: Action* GetAction(ConfigData* cd, const std::string& input, const std::string& output, Phases phase ); - void DoAction(Action* a); + bool DoAction(Action* a); /// @} /// @name Data @@ -215,15 +208,15 @@ namespace llvm { bool isVerbose; ///< Print actions? bool isDebug; ///< Print lotsa debug info? bool timeActions; ///< Time the actions executed ? + bool timePasses; ///< Time each pass and print timing ? + bool showStats; ///< Show gathered statistics ? bool emitRawCode; ///< Emit Raw (unoptimized) code? bool emitNativeCode; ///< Emit native code instead of bytecode? + bool keepTemps; ///< Keep temporary files? std::string machine; ///< Target machine name - std::vector<std::string> LibraryPaths; - std::vector<std::string> PreprocessorOptions; - std::vector<std::string> TranslatorOptions; - std::vector<std::string> OptimizerOptions; - std::vector<std::string> AssemblerOptions; - std::vector<std::string> LinkerOptions; + StringVector LibraryPaths; ///< -L options + StringTable AdditionalArgs; ///< The -Txyz options + std::string TempDir; ///< Name of the temporary directory. /// @} diff --git a/tools/llvmc/ConfigData.cpp b/tools/llvmc/ConfigData.cpp index cfea9eb435..a92550a9d3 100644 --- a/tools/llvmc/ConfigData.cpp +++ b/tools/llvmc/ConfigData.cpp @@ -15,21 +15,21 @@ #include "ConfigData.h" #include "ConfigLexer.h" #include "CompilerDriver.h" +#include "Support/CommandLine.h" #include "Support/StringExtras.h" #include <iostream> #include <fstream> using namespace llvm; -extern int ::Configlineno; - namespace llvm { - ConfigLexerInfo ConfigLexerData; + ConfigLexerInfo ConfigLexerState; InputProvider* ConfigLexerInput = 0; InputProvider::~InputProvider() {} void InputProvider::error(const std::string& msg) { - std::cerr << name << ":" << Configlineno << ": Error: " << msg << "\n"; + std::cerr << name << ":" << ConfigLexerState.lineNum << ": Error: " << + msg << "\n"; errCount++; } @@ -65,17 +65,34 @@ namespace { std::ifstream F; }; + cl::opt<bool> DumpTokens("dump-tokens", cl::Optional, cl::Hidden, cl::init(false), + cl::desc("Dump lexical tokens (debug use only).")); + struct Parser { + Parser() { + token = EOFTOK; + provider = 0; + confDat = 0; + ConfigLexerState.lineNum = 1; + ConfigLexerState.in_value = false; + ConfigLexerState.StringVal.clear(); + ConfigLexerState.IntegerVal = 0; + }; + ConfigLexerTokens token; InputProvider* provider; CompilerDriver::ConfigData* confDat; - CompilerDriver::Action* action; - int next() { return token = Configlex(); } + int next() { + token = Configlex(); + if (DumpTokens) + std::cerr << token << "\n"; + return token; + } bool next_is_real() { - token = Configlex(); + next(); return (token != EOLTOK) && (token != ERRORTOK) && (token != 0); } @@ -96,7 +113,7 @@ namespace { switch (token ) { case STRING : case OPTION : - result += ConfigLexerData.StringVal + " "; + result += ConfigLexerState.StringVal + " "; break; default: error("Invalid name"); @@ -130,15 +147,32 @@ namespace { return result; } + bool parseSubstitution(CompilerDriver::StringVector& optList) { + switch (token) { + case IN_SUBST: optList.push_back("@in@"); break; + case OUT_SUBST: optList.push_back("@out@"); break; + case TIME_SUBST: optList.push_back("@time@"); break; + case STATS_SUBST: optList.push_back("@stats@"); break; + case OPT_SUBST: optList.push_back("@opt@"); break; + case TARGET_SUBST: optList.push_back("@target@"); break; + default: + return false; + } + return true; + } + 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; + if (next() == EQUALS) { + while (next_is_real()) { + if (token == STRING || token == OPTION) + optList.push_back(ConfigLexerState.StringVal); + else if (!parseSubstitution(optList)) { + error("Expecting a program argument or substitution", false); + break; + } } - } + } else + error("Expecting '='"); } void parseLang() { @@ -174,25 +208,17 @@ namespace { // no value (valid) action.program.clear(); action.args.clear(); - action.inputAt = 0; - action.outputAt = 0; } else { if (token == STRING || token == OPTION) { - action.program = ConfigLexerData.StringVal; + action.program = ConfigLexerState.StringVal; } else { error("Expecting a program name"); } while (next_is_real()) { if (token == STRING || token == OPTION) { - action.args.push_back(ConfigLexerData.StringVal); - } else if (token == IN_SUBST) { - action.inputAt = action.args.size(); - action.args.push_back("@in@"); - } else if (token == OUT_SUBST) { - action.outputAt = action.args.size(); - action.args.push_back("@out@"); - } else { - error("Expecting a program argument", false); + action.args.push_back(ConfigLexerState.StringVal); + } else if (!parseSubstitution(action.args)) { + error("Expecting a program argument or substitution", false); break; } } @@ -246,12 +272,13 @@ namespace { else confDat->Translator.clear(CompilerDriver::GROKS_DASH_O_FLAG); break; - case GROKS_O10N: + case OUTPUT_IS_ASM: if (parseBoolean()) - confDat->Translator.set(CompilerDriver::GROKS_O10N_FLAG); + confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG); else - confDat->Translator.clear(CompilerDriver::GROKS_O10N_FLAG); + confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG); break; + default: error("Expecting 'command', 'required', 'preprocesses', " "'groks_dash_O' or 'optimizes'"); @@ -264,17 +291,29 @@ namespace { case COMMAND: parseCommand(confDat->Optimizer); break; + case PREPROCESSES: + if (parseBoolean()) + confDat->Optimizer.set(CompilerDriver::PREPROCESSES_FLAG); + else + confDat->Optimizer.clear(CompilerDriver::PREPROCESSES_FLAG); + break; + case TRANSLATES: + if (parseBoolean()) + confDat->Optimizer.set(CompilerDriver::TRANSLATES_FLAG); + else + confDat->Optimizer.clear(CompilerDriver::TRANSLATES_FLAG); + 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: + case OUTPUT_IS_ASM: if (parseBoolean()) - confDat->Optimizer.set(CompilerDriver::GROKS_O10N_FLAG); + confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG); else - confDat->Optimizer.clear(CompilerDriver::GROKS_O10N_FLAG); + confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG); break; default: error("Expecting 'command' or 'groks_dash_O'"); @@ -304,12 +343,6 @@ namespace { 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; @@ -349,7 +382,6 @@ namespace { 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 fd25589e61..78fc30b8b4 100644 --- a/tools/llvmc/ConfigLexer.h +++ b/ |