summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReid Spencer <rspencer@reidspencer.com>2004-08-19 04:49:47 +0000
committerReid Spencer <rspencer@reidspencer.com>2004-08-19 04:49:47 +0000
commitbae6825e1db794806958d556a86976c5bfa03f7b (patch)
tree9a1b3a5911bb945a6fccbfdde9b6df81ff71764b
parent8831db745bb0c3ed7939df475f924f53f43254a2 (diff)
downloadllvm-bae6825e1db794806958d556a86976c5bfa03f7b.tar.gz
llvm-bae6825e1db794806958d556a86976c5bfa03f7b.tar.bz2
llvm-bae6825e1db794806958d556a86976c5bfa03f7b.tar.xz
Implement many new features for llvmc. This is the first version that will
actually execute actions and it is been shown to optimize a Stacker program git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@15912 91177308-0d34-0410-b5e6-96231b3b80d8
-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/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 c0f42a3d90..70c0fbfc18 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
-LINKER linker|Linker|LINKER
-NAME name|Name|NAME
-REQUIRED required|Required|REQUIRED
+BadSubst \@[^iots][a-zA-Z]\@
COMMAND command|Command|COMMAND
-PREPROCESSES preprocesses|PreProcesses|PREPROCESSES
+Comment \#[^\n]*\n
+NewLine \n
+Eq \=
+EscNewLine \\\n
GROKS_DASH_O groks_dash_O|Groks_Dash_O|GROKS_DASH_O
-GROKS_O10N groks_optimization|Groks_Optimization|GROKS_OPTIMIZATION
-OPTIMIZES optimizes|Optimizes|OPTIMIZES
+LANG lang|Lang|LANG
+LINKER linker|Linker|LINKER
+NAME name|Name|NAME
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; }
-
-{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
+{Comment} { /* Ignore comments */
+ ConfigLexerState.in_value = false;
+ ConfigLexerState.lineNum++;
+ return EOLTOK;
+ }
+
+{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 cfea9eb435..a92550a9d3 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 <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/Makefile b/tools/llvmc/Makefile
index 94cb209e93..4db26fd14c 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 f32ec5a205..56736f3baf 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 1640803cd4..6c519cf29d 100644
--- a/tools/llvmc/llvmc.cpp
+++ b/tools/llvmc/llvmc.cpp
@@ -26,7 +26,7 @@ namespace {
//===------------------------------------------------------------------------===
//=== PHASE OPTIONS
//===------------------------------------------------------------------------===
-static cl::opt<CompilerDriver::Phases> FinalPhase(
+cl::opt<CompilerDriver::Phases> FinalPhase(
cl::desc("Choose final phase of compilation:"),
cl::init(CompilerDriver::LINKING),
cl::values(
@@ -45,7 +45,7 @@ static cl::opt<CompilerDriver::Phases> FinalPhase(
//===------------------------------------------------------------------------===
//=== OPTIMIZATION OPTIONS
//===------------------------------------------------------------------------===
-static cl::opt<CompilerDriver::OptimizationLevels> OptLevel(
+cl::opt<CompilerDriver::OptimizationLevels> OptLevel(
cl::desc("Choose level of optimization to apply:"),
cl::init(CompilerDriver::OPT_FAST_COMPILE),
cl::values(
@@ -69,23 +69,23 @@ static cl::opt<CompilerDriver::OptimizationLevels> OptLevel(
//=== TOOL OPTIONS
//===------------------------------------------------------------------------===
-static cl::list<std::string> PreprocessorToolOpts("Tpre", cl::ZeroOrMore,
+cl::list<std::string> PreprocessorToolOpts("Tpre", cl::ZeroOrMore,
cl::desc("Pass specific options to the pre-processor"),
cl::value_desc("option"));
-static cl::list<std::string> TranslatorToolOpts("Ttrn", cl::ZeroOrMore,
+cl::list<std::string> TranslatorToolOpts("Ttrn", cl::ZeroOrMore,
cl::desc("Pass specific options to the assembler"),
cl::value_desc("option"));
-static cl::list<std::string> AssemblerToolOpts("Tasm", cl::ZeroOrMore,
+cl::list<std::string> AssemblerToolOpts("Tasm", cl::ZeroOrMore,
cl::desc("Pass specific options to the assembler"),
cl::value_desc("option"));
-static cl::list<std::string> OptimizerToolOpts("Topt", cl::ZeroOrMore,
+cl::list<std::string> OptimizerToolOpts("Topt", cl::ZeroOrMore,
cl::desc("Pass specific options to the optimizer"),
cl::value_desc("option"));
-static cl::list<std::string> LinkerToolOpts("Tlnk", cl::ZeroOrMore,
+cl::list<std::string> LinkerToolOpts("Tlnk", cl::ZeroOrMore,
cl::desc("Pass specific options to the linker"),
cl::value_desc("option"));
@@ -93,10 +93,10 @@ static cl::list<std::string> LinkerToolOpts("Tlnk", cl::ZeroOrMore,
//=== INPUT OPTIONS
//===------------------------------------------------------------------------===
-static cl::list<std::string> LibPaths("L", cl::Prefix,
+cl::list<std::string> LibPaths("L", cl::Prefix,
cl::desc("Specify a library search path"), cl::value_desc("directory"));
-static cl::list<std::string> Libraries("l", cl::Prefix,
+cl::list<std::string> Libraries("l", cl::Prefix,
cl::desc("Specify libraries to link to"), cl::value_desc("library prefix"));
@@ -104,40 +104,46 @@ static cl::list<std::string> Libraries("l", cl::Prefix,
//=== OUTPUT OPTIONS
//===------------------------------------------------------------------------===
-static cl::opt<std::string> OutputFilename("o",
+cl::opt<std::string> OutputFilename("o",
cl::desc("Override output filename"), cl::value_desc("filename"));
-static cl::opt<std::string> OutputMachine("m", cl::Prefix,
+cl::opt<std::string> OutputMachine("m", cl::Prefix,
cl::desc("Specify a target machine"), cl::value_desc("machine"));
-static cl::opt<bool> Native("native", cl::init(false),
+cl::opt<bool> Native("native", cl::init(false),
cl::desc("Generative native object and executables instead of bytecode"));
//===------------------------------------------------------------------------===
//=== INFORMATION OPTIONS
//===------------------------------------------------------------------------===
-static cl::opt<bool> DryRun("dry-run", cl::Optional, cl::init(false),
+cl::opt<bool> 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<bool> Verbose("verbose", cl::Optional, cl::init(false),
+cl::opt<bool> 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<bool> Debug("debug", cl::Optional, cl::init(false),
+cl::opt<bool> 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<bool> TimeActions("time-actions", cl::Optional, cl::init(false),
+cl::opt<bool> TimeActions("time-actions", cl::Optional, cl::init(false),
cl::desc("Print execution time for each action taken"));
+cl::opt<bool> TimePasses("time-passes", cl::Optional, cl::init(false),
+ cl::desc("Print execution time for each optimization pass"));
+
+cl::opt<bool> ShowStats("stats", cl::Optional, cl::init(false),
+ cl::desc("Print statistics accumulated during optimization"));
+
//===------------------------------------------------------------------------===
//=== ADVANCED OPTIONS
//===------------------------------------------------------------------------===
@@ -152,6 +158,9 @@ static cl::opt<bool> EmitRawCode("emit-raw-code", cl::Hidden, cl::Optional,
static cl::opt<bool> PipeCommands("pipe", cl::Optional,
cl::desc("Invoke sub-commands by linking input/output with pipes"));
+static cl::opt<bool> 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();
-
- // 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";
-
- // 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 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);
-
- // Prepare the list of files to be compiled by the CompilerDriver.
- CompilerDriver::InputList InpList;
- std::vector<std::string>::iterator fileIt = Files.begin();
- std::vector<std::string>::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;
+ 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"
+ );
+
+ // 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";
+
+ // Construct the ConfigDataProvider object
+ LLVMC_ConfigDataProvider Provider;
+ Provider.setConfigDir(ConfigDir);
+
+ // 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.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<std::string>::iterator fileIt = Files.begin();
+ std::vector<std::string>::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;
+ }
+ 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 f9afb1b519..93d5c5b286 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