aboutsummaryrefslogtreecommitdiff
path: root/tools/llvmc
diff options
context:
space:
mode:
Diffstat (limited to 'tools/llvmc')
-rw-r--r--tools/llvmc/CompilerDriver.cpp384
-rw-r--r--tools/llvmc/CompilerDriver.h81
-rw-r--r--tools/llvmc/ConfigData.cpp112
-rw-r--r--tools/llvmc/ConfigLexer.h13
-rw-r--r--tools/llvmc/ConfigLexer.l187
-rw-r--r--tools/llvmc/Configuration.cpp112
-rw-r--r--tools/llvmc/Makefile2
-rw-r--r--tools/llvmc/ll1
-rw-r--r--tools/llvmc/llvmc.cpp214
-rw-r--r--tools/llvmc/st70
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/