aboutsummaryrefslogtreecommitdiff
path: root/tools/llvmc/CompilerDriver.cpp
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 /tools/llvmc/CompilerDriver.cpp
parent8831db745bb0c3ed7939df475f924f53f43254a2 (diff)
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
Diffstat (limited to 'tools/llvmc/CompilerDriver.cpp')
-rw-r--r--tools/llvmc/CompilerDriver.cpp384
1 files changed, 252 insertions, 132 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;
}