diff --git a/tools/llvmc/CompilerDriver.cpp b/tools/llvmc/CompilerDriver.cpp index f0ae129cea8..f124219a0da 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 using namespace llvm; @@ -33,27 +34,25 @@ namespace { const char OutputSuffix[] = ".o"; - void WriteAction(CompilerDriver::Action* a ) { - std::cerr << a->program; - std::vector::iterator I = a->args.begin(); - while (I != a->args.end()) { + void WriteAction(CompilerDriver::Action* action ) { + std::cerr << action->program; + std::vector::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::iterator I = a->args.begin(); - while (I != a->args.end()) { + void DumpAction(CompilerDriver::Action* action) { + std::cerr << "command = " << action->program; + std::vector::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,54 +139,53 @@ 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(); +} + +CompilerDriver::ConfigData::ConfigData() + : langName() + , PreProcessor() + , Translator() + , Optimizer() + , Assembler() + , Linker() +{ + StringVector emptyVec; + for (unsigned i = 0; i < NUM_PHASES; ++i) + opts.push_back(emptyVec); } void CompilerDriver::error( const std::string& errmsg ) { - std::cerr << "Error: " << errmsg << ".\n"; + std::cerr << "llvmc: Error: " << errmsg << ".\n"; 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; + 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; - // 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; + // 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(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++; } - return a; + + // Get specific options for each kind of action type + StringVector& args = AdditionalArgs[phase]; + + // 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::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 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::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 0914feca4c5..4b825e22eab 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 StringVector; + /// @brief A table of strings, indexed typically by Phases + typedef std::vector 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 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& 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; + void setPhaseArgs(Phases phase, const std::vector& 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 LibraryPaths; - std::vector PreprocessorOptions; - std::vector TranslatorOptions; - std::vector OptimizerOptions; - std::vector AssemblerOptions; - std::vector 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 cfea9eb4356..a92550a9d3b 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 #include 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 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; } - 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; - } + 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 ) { + 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 fd25589e61b..78fc30b8b4a 100644 --- a/tools/llvmc/ConfigLexer.h +++ b/tools/llvmc/ConfigLexer.h @@ -22,9 +22,11 @@ struct ConfigLexerInfo { int64_t IntegerVal; std::string StringVal; + bool in_value; + unsigned lineNum; }; -extern ConfigLexerInfo ConfigLexerData; +extern ConfigLexerInfo ConfigLexerState; class InputProvider { public: @@ -57,6 +59,10 @@ enum ConfigLexerTokens { STRING, ///< A quoted string IN_SUBST, ///< The input substitution item @in@ OUT_SUBST, ///< The output substitution item @out@ + STATS_SUBST, ///< The stats substitution item @stats@ + TIME_SUBST, ///< The substitution item @time@ + OPT_SUBST, ///< The substitution item @opt@ + TARGET_SUBST, ///< The substitition item @target@ LANG, ///< The item "lang" (and case variants) PREPROCESSOR, ///< The item "preprocessor" (and case variants) TRANSLATOR, ///< The item "translator" (and case variants) @@ -67,9 +73,10 @@ enum ConfigLexerTokens { 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) + TRANSLATES, ///< The item "translates" (and case variants) OPTIMIZES, ///< The item "optimizes" (and case variants) + GROKS_DASH_O, ///< The item "groks_dash_O" (and case variants) + OUTPUT_IS_ASM,///< The item "outut_is_asm" (and case variants) OPT1, ///< The item "opt1" (and case variants) OPT2, ///< The item "opt2" (and case variants) OPT3, ///< The item "opt3" (and case variants) diff --git a/tools/llvmc/ConfigLexer.l b/tools/llvmc/ConfigLexer.l index c0f42a3d903..70c0fbfc184 100644 --- a/tools/llvmc/ConfigLexer.l +++ b/tools/llvmc/ConfigLexer.l @@ -14,7 +14,6 @@ %option prefix="Config" -%option yylineno %option nostdinit %option never-interactive %option batch @@ -23,9 +22,9 @@ %option 8bit %option outfile="ConfigLexer.cpp" %option ecs -%option noreject %option noyymore -%array +%option noreject +%pointer %{ @@ -38,53 +37,73 @@ if (result == 0 ) result = YY_NULL; \ } +#define YY_FATAL_ERROR(msg) \ + { \ + assert(ConfigLexerInput != 0 && "Oops"); \ + ConfigLexerInput->error(msg); \ + } + #define YY_DECL ConfigLexerTokens llvm::Configlex() #define yyterminate() { return EOFTOK; } using namespace llvm; -/* Conversion of text ints to binary */ -static int64_t IntToVal(const char *Buffer) { - int64_t Result = 0; - for (; *Buffer; Buffer++) { - int64_t OldRes = Result; - Result *= 10; - Result += *Buffer-'0'; +inline llvm::ConfigLexerTokens +handleContext(const char* tokenText, llvm::ConfigLexerTokens token) { + if (ConfigLexerState.in_value) { + ConfigLexerState.StringVal = tokenText; + return OPTION; } - return Result; + return token; } -bool in_value = false; +inline llvm::ConfigLexerTokens +handleSubstitution(llvm::ConfigLexerTokens token) { + if (ConfigLexerState.in_value) + return token; + YY_FATAL_ERROR("Substitition tokens not allowed in names" ); + return ERRORTOK; +}; + +inline llvm::ConfigLexerTokens handleBoolean(llvm::ConfigLexerTokens token) { + if (ConfigLexerState.in_value) + return token; + YY_FATAL_ERROR("Boolean values not allowed in names"); + return ERRORTOK; +} %} -LANG lang|Lang|LANG -PREPROCESSOR preprocessor|PreProcessor|PREPROCESSOR -TRANSLATOR translator|Translator|TRANSLATOR -OPTIMIZER optimizer|Optimizer|OPTIMIZER ASSEMBLER assembler|Assembler|ASSEMBLER +BadSubst \@[^iots][a-zA-Z]\@ +COMMAND command|Command|COMMAND +Comment \#[^\n]*\n +NewLine \n +Eq \= +EscNewLine \\\n +GROKS_DASH_O groks_dash_O|Groks_Dash_O|GROKS_DASH_O +LANG lang|Lang|LANG LINKER linker|Linker|LINKER NAME name|Name|NAME -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]* -Option [-A-Za-z0-9_:%+/\\|,]* +OPTIMIZER optimizer|Optimizer|OPTIMIZER +OPTIMIZES optimizes|Optimizes|OPTIMIZES +Option [-A-Za-z0-9_:%+/\\|,][-A-Za-z0-9_:%+/\\|,@]* +OUTPUT_IS_ASM output_is_asm|Output_Is_Asm|OUTPUT_IS_ASM +PREPROCESSES preprocesses|PreProcesses|PREPROCESSES +PREPROCESSOR preprocessor|PreProcessor|PREPROCESSOR +REQUIRED required|Required|REQUIRED Sep \. -Eq \= String \"[^\"]*\" -Integer [-+]?[0-9]+ +TRANSLATES translates|Translates|TRANSLATES +TRANSLATOR translator|Translator|TRANSLATOR +White [ \t]* + True true|True|TRUE False false|False|FALSE On on|On|ON @@ -94,64 +113,68 @@ No no|No|NO %% -{NewLine} { in_value = false; return EOLTOK; } -{Eq} { in_value = true; return EQUALS; } -{Comment} { /* Ignore comments */ } {White} { /* Ignore whitespace */ } -{LANG} { if (in_value) { ConfigLexerData.StringVal = "lang"; - return OPTION; } else return LANG; } -{PREPROCESSOR} { if (in_value) { ConfigLexerData.StringVal = "preprocessor"; - return OPTION; } else return PREPROCESSOR; } -{TRANSLATOR} { if (in_value) { ConfigLexerData.StringVal = "translator"; - return OPTION; } else return TRANSLATOR; } -{OPTIMIZER} { if (in_value) { ConfigLexerData.StringVal = "optimizer"; - return OPTION; } else return OPTIMIZER; } -{ASSEMBLER} { if (in_value) { ConfigLexerData.StringVal = "assembler"; - return OPTION; } else return ASSEMBLER; } -{LINKER} { if (in_value) { ConfigLexerData.StringVal = "linker"; - return OPTION; } else return LINKER; } -{NAME} { if (in_value) { ConfigLexerData.StringVal = "name"; - return OPTION; } else return NAME; } -{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; } -{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; } -{On} { if (in_value) return TRUETOK; else return ERRORTOK; } -{Yes} { if (in_value) return TRUETOK; else return ERRORTOK; } -{False} { if (in_value) return FALSETOK; else return ERRORTOK; } -{Off} { if (in_value) return FALSETOK; else return ERRORTOK; } -{No} { if (in_value) return FALSETOK; else return ERRORTOK; } +{Comment} { /* Ignore comments */ + ConfigLexerState.in_value = false; + ConfigLexerState.lineNum++; + return EOLTOK; + } -{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 +{EscNewLine} { ConfigLexerState.lineNum++; + /* Don't return EOLTOK! */ + } + +{NewLine} { ConfigLexerState.in_value = false; + ConfigLexerState.lineNum++; + return EOLTOK; + } + +{Eq} { ConfigLexerState.in_value = true; + return EQUALS; + } + +{LANG} { return handleContext("lang",LANG); } +{PREPROCESSOR} { return handleContext("preprocessor",PREPROCESSOR); } +{TRANSLATOR} { return handleContext("translator",TRANSLATOR); } +{OPTIMIZER} { return handleContext("optimizer",OPTIMIZER); } +{ASSEMBLER} { return handleContext("assembler",ASSEMBLER); } +{LINKER} { return handleContext("linker",LINKER); } +{NAME} { return handleContext("name",NAME); } +{REQUIRED} { return handleContext("required",REQUIRED); } +{COMMAND} { return handleContext("command",COMMAND); } +{PREPROCESSES} { return handleContext("preprocesses",PREPROCESSES); } +{TRANSLATES} { return handleContext("translates",TRANSLATES); } +{OPTIMIZES} { return handleContext("optimizes",OPTIMIZES); } +{GROKS_DASH_O} { return handleContext("groks_dash_O",GROKS_DASH_O); } +{OUTPUT_IS_ASM} { return handleContext("output_ias_asm",OUTPUT_IS_ASM); } +{OPT1} { return handleContext("opt1",OPT1); } +{OPT2} { return handleContext("opt2",OPT2); } +{OPT3} { return handleContext("opt3",OPT3); } +{OPT4} { return handleContext("opt4",OPT4); } +{OPT5} { return handleContext("opt5",OPT5); } + +@in@ { return handleSubstitution(IN_SUBST); } +@out@ { return handleSubstitution(OUT_SUBST); } +@time@ { return handleSubstitution(TIME_SUBST); } +@stats@ { return handleSubstitution(STATS_SUBST); } +@opt@ { return handleSubstitution(OPT_SUBST); } +@target@ { return handleSubstitution(TARGET_SUBST); } +{BadSubst} { YY_FATAL_ERROR("Invalid substitution token"); } +{True} { return handleBoolean(TRUETOK); } +{On} { return handleBoolean(TRUETOK); } +{Yes} { return handleBoolean(TRUETOK); } +{False} { return handleBoolean(FALSETOK); } +{Off} { return handleBoolean(FALSETOK); } +{No} { return handleBoolean(FALSETOK); } + +{Option} { ConfigLexerState.StringVal = yytext; return OPTION; } +{String} { ConfigLexerState.StringVal = yytext+1; // Nuke start quote + ConfigLexerState.StringVal.erase( + --ConfigLexerState.StringVal.end()); return STRING; } -{Sep} { if (in_value) { ConfigLexerData.StringVal = yytext; +{Sep} { if (ConfigLexerState.in_value) { ConfigLexerState.StringVal = yytext; return OPTION; } } diff --git a/tools/llvmc/Configuration.cpp b/tools/llvmc/Configuration.cpp index cfea9eb4356..a92550a9d3b 100644 --- a/tools/llvmc/Configuration.cpp +++ b/tools/llvmc/Configuration.cpp @@ -15,21 +15,21 @@ #include "ConfigData.h" #include "ConfigLexer.h" #include "CompilerDriver.h" +#include "Support/CommandLine.h" #include "Support/StringExtras.h" #include #include 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 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; } - 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; - } + 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 ) { + 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/Makefile b/tools/llvmc/Makefile index 94cb209e935..4db26fd14c9 100644 --- a/tools/llvmc/Makefile +++ b/tools/llvmc/Makefile @@ -8,6 +8,6 @@ ##===----------------------------------------------------------------------===## LEVEL = ../.. TOOLNAME = llvmc -USEDLIBS = asmparser bcreader bcwriter vmcore support.a system.a +USEDLIBS = support.a include $(LEVEL)/Makefile.common diff --git a/tools/llvmc/ll b/tools/llvmc/ll index f32ec5a205d..56736f3bafd 100644 --- a/tools/llvmc/ll +++ b/tools/llvmc/ll @@ -4,7 +4,6 @@ preprocessor.required=false translator.command=llvm-as @in@ -o @out@ translator.groks_dash_O=no - translator.groks_optimization=no translator.optimizes=no translator.preprocesses=true translator.required=TRUE diff --git a/tools/llvmc/llvmc.cpp b/tools/llvmc/llvmc.cpp index 1640803cd4e..6c519cf29d5 100644 --- a/tools/llvmc/llvmc.cpp +++ b/tools/llvmc/llvmc.cpp @@ -26,7 +26,7 @@ namespace { //===------------------------------------------------------------------------=== //=== PHASE OPTIONS //===------------------------------------------------------------------------=== -static cl::opt FinalPhase( +cl::opt FinalPhase( cl::desc("Choose final phase of compilation:"), cl::init(CompilerDriver::LINKING), cl::values( @@ -45,7 +45,7 @@ static cl::opt FinalPhase( //===------------------------------------------------------------------------=== //=== OPTIMIZATION OPTIONS //===------------------------------------------------------------------------=== -static cl::opt OptLevel( +cl::opt OptLevel( cl::desc("Choose level of optimization to apply:"), cl::init(CompilerDriver::OPT_FAST_COMPILE), cl::values( @@ -69,23 +69,23 @@ static cl::opt OptLevel( //=== TOOL OPTIONS //===------------------------------------------------------------------------=== -static cl::list PreprocessorToolOpts("Tpre", cl::ZeroOrMore, +cl::list PreprocessorToolOpts("Tpre", cl::ZeroOrMore, cl::desc("Pass specific options to the pre-processor"), cl::value_desc("option")); -static cl::list TranslatorToolOpts("Ttrn", cl::ZeroOrMore, +cl::list TranslatorToolOpts("Ttrn", cl::ZeroOrMore, cl::desc("Pass specific options to the assembler"), cl::value_desc("option")); -static cl::list AssemblerToolOpts("Tasm", cl::ZeroOrMore, +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::list OptimizerToolOpts("Topt", cl::ZeroOrMore, cl::desc("Pass specific options to the optimizer"), cl::value_desc("option")); -static cl::list LinkerToolOpts("Tlnk", cl::ZeroOrMore, +cl::list LinkerToolOpts("Tlnk", cl::ZeroOrMore, cl::desc("Pass specific options to the linker"), cl::value_desc("option")); @@ -93,10 +93,10 @@ static cl::list LinkerToolOpts("Tlnk", cl::ZeroOrMore, //=== INPUT OPTIONS //===------------------------------------------------------------------------=== -static cl::list LibPaths("L", cl::Prefix, +cl::list LibPaths("L", cl::Prefix, cl::desc("Specify a library search path"), cl::value_desc("directory")); -static cl::list Libraries("l", cl::Prefix, +cl::list Libraries("l", cl::Prefix, cl::desc("Specify libraries to link to"), cl::value_desc("library prefix")); @@ -104,40 +104,46 @@ static cl::list Libraries("l", cl::Prefix, //=== OUTPUT OPTIONS //===------------------------------------------------------------------------=== -static cl::opt OutputFilename("o", +cl::opt OutputFilename("o", cl::desc("Override output filename"), cl::value_desc("filename")); -static cl::opt OutputMachine("m", cl::Prefix, +cl::opt OutputMachine("m", cl::Prefix, cl::desc("Specify a target machine"), cl::value_desc("machine")); -static cl::opt Native("native", cl::init(false), +cl::opt Native("native", cl::init(false), cl::desc("Generative native object and executables instead of bytecode")); //===------------------------------------------------------------------------=== //=== INFORMATION OPTIONS //===------------------------------------------------------------------------=== -static cl::opt DryRun("dry-run", cl::Optional, cl::init(false), +cl::opt DryRun("dry-run", cl::Optional, cl::init(false), cl::desc("Do everything but perform the compilation actions")); -static cl::alias DryRunAlias("y", cl::Optional, +cl::alias DryRunAlias("y", cl::Optional, cl::desc("Alias for -dry-run"), cl::aliasopt(DryRun)); -static cl::opt Verbose("verbose", cl::Optional, cl::init(false), +cl::opt Verbose("verbose", cl::Optional, cl::init(false), cl::desc("Print out each action taken")); -static cl::alias VerboseAlias("v", cl::Optional, +cl::alias VerboseAlias("v", cl::Optional, cl::desc("Alias for -verbose"), cl::aliasopt(Verbose)); -static cl::opt Debug("debug", cl::Optional, cl::init(false), +cl::opt Debug("debug", cl::Optional, cl::init(false), cl::Hidden, cl::desc("Print out debugging information")); -static cl::alias DebugAlias("d", cl::Optional, +cl::alias DebugAlias("d", cl::Optional, cl::desc("Alias for -debug"), cl::aliasopt(Debug)); -static cl::opt TimeActions("time-actions", cl::Optional, cl::init(false), +cl::opt TimeActions("time-actions", cl::Optional, cl::init(false), cl::desc("Print execution time for each action taken")); +cl::opt TimePasses("time-passes", cl::Optional, cl::init(false), + cl::desc("Print execution time for each optimization pass")); + +cl::opt ShowStats("stats", cl::Optional, cl::init(false), + cl::desc("Print statistics accumulated during optimization")); + //===------------------------------------------------------------------------=== //=== ADVANCED OPTIONS //===------------------------------------------------------------------------=== @@ -152,6 +158,9 @@ static cl::opt EmitRawCode("emit-raw-code", cl::Hidden, cl::Optional, static cl::opt PipeCommands("pipe", cl::Optional, cl::desc("Invoke sub-commands by linking input/output with pipes")); +static cl::opt KeepTemporaries("keep-temps", cl::Optional, + cl::desc("Don't delete the temporary files created during compilation")); + //===------------------------------------------------------------------------=== //=== POSITIONAL OPTIONS //===------------------------------------------------------------------------=== @@ -192,86 +201,97 @@ const std::string GetFileType(const std::string& fname, unsigned pos ) { /// @brief The main program for llvmc int main(int argc, char **argv) { - // Make sure we print stack trace if we get bad signals - PrintStackTraceOnErrorSignal(); + try { + // Make sure we print stack trace if we get bad signals + PrintStackTraceOnErrorSignal(); - // Parse the command line options - cl::ParseCommandLineOptions(argc, argv, - " LLVM Compilation Driver (llvmc)\n\n" - " This program provides easy invocation of the LLVM tool set\n" - " and source language compiler tools.\n" - ); + // Parse the command line options + cl::ParseCommandLineOptions(argc, argv, + " LLVM Compilation Driver (llvmc)\n\n" + " This program provides easy invocation of the LLVM tool set\n" + " and source language compiler tools.\n" + ); - // Deal with unimplemented options. - if (Native) - 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"; + // Deal with unimplemented options. + 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) - OutputFilename = "a.out"; + // Default the output file, only if we're going to try to link + if (OutputFilename.empty() && OptLevel == CompilerDriver::LINKING) + OutputFilename = "a.out"; - // Construct the ConfigDataProvider object - LLVMC_ConfigDataProvider Provider; - Provider.setConfigDir(ConfigDir); + // Construct the ConfigDataProvider object + LLVMC_ConfigDataProvider Provider; + Provider.setConfigDir(ConfigDir); - // Construct the CompilerDriver object - CompilerDriver CD(Provider); + // Construct the CompilerDriver object + CompilerDriver CD(Provider); - // Configure the driver based on options - CD.setVerbose(Verbose); - CD.setDebug(Debug); - CD.setDryRun(DryRun); - CD.setFinalPhase(FinalPhase); - CD.setOptimization(OptLevel); - CD.setOutputMachine(OutputMachine); - CD.setEmitNativeCode(Native); - CD.setEmitRawCode(EmitRawCode); - CD.setLibraryPaths(LibPaths); - CD.setPreprocessorOptions(PreprocessorToolOpts); - CD.setTranslatorOptions(TranslatorToolOpts); - CD.setOptimizerOptions(OptimizerToolOpts); - CD.setAssemblerOptions(AssemblerToolOpts); - CD.setLinkerOptions(LinkerToolOpts); + // Configure the driver based on options + CD.setVerbose(Verbose); + CD.setDebug(Debug); + CD.setDryRun(DryRun); + CD.setFinalPhase(FinalPhase); + CD.setOptimization(OptLevel); + CD.setOutputMachine(OutputMachine); + CD.setEmitNativeCode(Native); + CD.setEmitRawCode(EmitRawCode); + CD.setTimeActions(TimeActions); + CD.setTimePasses(TimePasses); + CD.setShowStats(ShowStats); + CD.setKeepTemporaries(KeepTemporaries); + CD.setLibraryPaths(LibPaths); + if (!PreprocessorToolOpts.empty()) + CD.setPhaseArgs(CompilerDriver::PREPROCESSING, PreprocessorToolOpts); + if (!TranslatorToolOpts.empty()) + CD.setPhaseArgs(CompilerDriver::TRANSLATION, TranslatorToolOpts); + if (!OptimizerToolOpts.empty()) + CD.setPhaseArgs(CompilerDriver::OPTIMIZATION, OptimizerToolOpts); + if (!AssemblerToolOpts.empty()) + CD.setPhaseArgs(CompilerDriver::ASSEMBLY,AssemblerToolOpts); + if (!LinkerToolOpts.empty()) + CD.setPhaseArgs(CompilerDriver::LINKING, LinkerToolOpts); - // Prepare the list of files to be compiled by the CompilerDriver. - CompilerDriver::InputList InpList; - std::vector::iterator fileIt = Files.begin(); - std::vector::iterator libIt = Libraries.begin(); - unsigned libPos = 0, filePos = 0; - while ( 1 ) { - if ( libIt != Libraries.end() ) - libPos = Libraries.getPosition( libIt - Libraries.begin() ); - else - libPos = 0; - if ( fileIt != Files.end() ) - filePos = Files.getPosition( fileIt - Files.begin() ); - else - filePos = 0; + // Prepare the list of files to be compiled by the CompilerDriver. + CompilerDriver::InputList InpList; + std::vector::iterator fileIt = Files.begin(); + std::vector::iterator libIt = Libraries.begin(); + unsigned libPos = 0, filePos = 0; + while ( 1 ) { + if ( libIt != Libraries.end() ) + libPos = Libraries.getPosition( libIt - Libraries.begin() ); + else + libPos = 0; + if ( fileIt != Files.end() ) + filePos = Files.getPosition( fileIt - Files.begin() ); + else + filePos = 0; - if ( filePos != 0 && (libPos == 0 || filePos < libPos) ) { - // Add a source file - InpList.push_back( std::make_pair(*fileIt, GetFileType(*fileIt,filePos))); - ++fileIt; + if ( filePos != 0 && (libPos == 0 || filePos < libPos) ) { + // Add a source file + InpList.push_back( std::make_pair(*fileIt, GetFileType(*fileIt,filePos))); + ++fileIt; + } + else if ( libPos != 0 && (filePos == 0 || libPos < filePos) ) { + // Add a library + InpList.push_back( std::make_pair(*libIt++,"")); + } + else + break; // we're done with the list } - else if ( libPos != 0 && (filePos == 0 || libPos < filePos) ) { - // Add a library - InpList.push_back( std::make_pair(*libIt++,"")); + + // Tell the driver to do its thing + int result = CD.execute(InpList,OutputFilename); + if (result != 0) { + std::cerr << argv[0] << ": Error executing actions. Terminated.\n"; + return result; } - else - break; // we're done with the list - } - // Tell the driver to do its thing - int result = CD.execute(InpList,OutputFilename); - if (result != 0) { - std::cerr << argv[0] << ": Error executing actions. Terminated.\n"; - return result; + // All is good, return success + return 0; + } catch (std::string& msg) { + std::cerr << msg << "\n"; + } catch (...) { + std::cerr << "Unexpected unknown exception occurred.\n"; } - - // All is good, return success - return 0; } diff --git a/tools/llvmc/st b/tools/llvmc/st index f9afb1b5194..93d5c5b286c 100644 --- a/tools/llvmc/st +++ b/tools/llvmc/st @@ -1,22 +1,72 @@ -# Stacker CompilerDriver Configuration File +# Stacker Configuration File For llvmc +########################################################## +# Language definitions +########################################################## lang.name=Stacker + lang.opt1=-simplifycfg -instcombine -mem2reg + lang.opt2=-simplifycfg -instcombine -mem2reg -scalarrepl -sccp + lang.opt3=-simplifycfg -instcombine -mem2reg -scalarrepl -sccp \ + -branch-combine -adce -globaldce -inline -licm -pre + lang.opt4=-simplifycfg -instcombine -mem2reg -scalarrepl -sccp \ + -ipconstprop -branch-combine -adce -globaldce -inline -licm -pre + lang.opt5=-simplifycfg -instcombine -mem2reg -scalarrepl -sccp \ + -ipconstprop -branch-combine -adce -globaldce -inline -licm -pre \ + -block-placement + +########################################################## # Pre-processor definitions +########################################################## + + # Stacker doesn't have a preprocessor but the following + # allows the -E option to be supported preprocessor.command=cp @in@ @out@ - preprocessor.required=False + preprocessor.required=false +########################################################## # Translator definitions - translator.command=stkrc -S 2048 @in@ -o @out@ - translator.preprocesses=false - translator.optimizes=TRUE - translator.groks_dash_O=No - translator.required=no +########################################################## + # To compile stacker source, we just run the stacker + # compiler with a default stack size of 2048 entries. + translator.command=stkrc -s 2048 @in@ -o @out@ @time@ @stats@ + + # stkrc doesn't preprocess but we set this to true so + # that we don't run the cp command by default. + translator.preprocesses=true + + # The translator is required to run. + translator.required=true + + # stkrc doesn't do any optimization, it just translates + translator.optimizes=no + + # stkrc doesn't handle the -On options + translator.groks_dash_O=no + +########################################################## # Optimizer definitions - optimizer.command=opt @in@ -o @out@ +########################################################## + + # For optimization, we use the LLVM "opt" program + optimizer.command=opt @in@ -o @out@ @opt@ @time@ @stats@ + # opt doesn't (yet) grok -On + optimizer.groks_dash_O=no + + # opt doesn't translate + optimizer.translates = no + + # opt doesn't preprocess + optimizer.preprocesses=no + +########################################################## # Assembler definitions - assembler.command=llc @in@ -o @out@ +########################################################## + assembler.command=llc @in@ -o @out@ @target@ "-regalloc=linearscan" \ + @time@ @stats@ +########################################################## # Linker definitions - linker.command=llvm-link @in@ -o @out@ +########################################################## + linker.command=gccld @in@ -o @out@ -lstkr_runtime