diff options
Diffstat (limited to 'tools/llvmc/CompilerDriver.cpp')
-rw-r--r-- | tools/llvmc/CompilerDriver.cpp | 1032 |
1 files changed, 1032 insertions, 0 deletions
diff --git a/tools/llvmc/CompilerDriver.cpp b/tools/llvmc/CompilerDriver.cpp new file mode 100644 index 0000000..4be9f13 --- /dev/null +++ b/tools/llvmc/CompilerDriver.cpp @@ -0,0 +1,1032 @@ +//===- CompilerDriver.cpp - The LLVM Compiler Driver ------------*- C++ -*-===// +// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Reid Spencer and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the bulk of the LLVM Compiler Driver (llvmc). +// +//===----------------------------------------------------------------------===// + +#include "CompilerDriver.h" +#include "ConfigLexer.h" +#include "llvm/Module.h" +#include "llvm/ModuleProvider.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Timer.h" +#include "llvm/System/Signals.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Config/alloca.h" +#include <iostream> +using namespace llvm; + + +namespace { + +void WriteAction(CompilerDriver::Action* action ) { + std::cerr << action->program.c_str(); + std::vector<std::string>::const_iterator I = action->args.begin(); + while (I != action->args.end()) { + std::cerr << ' ' << *I; + ++I; + } + std::cerr << '\n'; +} + +void DumpAction(CompilerDriver::Action* action) { + std::cerr << "command = " << action->program.c_str(); + std::vector<std::string>::const_iterator I = action->args.begin(); + while (I != action->args.end()) { + std::cerr << ' ' << *I; + ++I; + } + std::cerr << '\n'; + std::cerr << "flags = " << action->flags << '\n'; +} + +void DumpConfigData(CompilerDriver::ConfigData* cd, const std::string& type ){ + std::cerr << "Configuration Data For '" << cd->langName << "' (" << type + << ")\n"; + std::cerr << "PreProcessor: "; + DumpAction(&cd->PreProcessor); + std::cerr << "Translator: "; + DumpAction(&cd->Translator); + std::cerr << "Optimizer: "; + DumpAction(&cd->Optimizer); + std::cerr << "Assembler: "; + DumpAction(&cd->Assembler); + std::cerr << "Linker: "; + DumpAction(&cd->Linker); +} + +static bool GetBitcodeDependentLibraries(const std::string &fname, + Module::LibraryListType& deplibs, + std::string* ErrMsg) { + ModuleProvider *MP = 0; + if (MemoryBuffer *Buffer = MemoryBuffer::getFileOrSTDIN(fname)) { + MP = getBitcodeModuleProvider(Buffer); + if (MP == 0) delete Buffer; + } + if (!MP) { + deplibs.clear(); + return true; + } + deplibs = MP->getModule()->getLibraries(); + delete MP; + return false; +} + + +class CompilerDriverImpl : public CompilerDriver { +/// @name Constructors +/// @{ +public: + CompilerDriverImpl(ConfigDataProvider& confDatProv ) + : cdp(&confDatProv) + , finalPhase(LINKING) + , optLevel(OPT_FAST_COMPILE) + , Flags(0) + , machine() + , LibraryPaths() + , TempDir() + , AdditionalArgs() + { + AdditionalArgs.reserve(NUM_PHASES); + StringVector emptyVec; + for (unsigned i = 0; i < NUM_PHASES; ++i) + AdditionalArgs.push_back(emptyVec); + } + + virtual ~CompilerDriverImpl() { + cleanup(); + cdp = 0; + LibraryPaths.clear(); + IncludePaths.clear(); + Defines.clear(); + TempDir.clear(); + AdditionalArgs.clear(); + fOptions.clear(); + MOptions.clear(); + WOptions.clear(); + } + +/// @} +/// @name Methods +/// @{ +public: + virtual void setFinalPhase(Phases phase) { + finalPhase = phase; + } + + virtual void setOptimization(OptimizationLevels level) { + optLevel = level; + } + + virtual void setDriverFlags(unsigned flags) { + Flags = flags & DRIVER_FLAGS_MASK; + } + + virtual void setOutputMachine(const std::string& machineName) { + machine = machineName; + } + + virtual void setPhaseArgs(Phases phase, const StringVector& opts) { + assert(phase <= LINKING && phase >= PREPROCESSING); + AdditionalArgs[phase] = opts; + } + + virtual void setIncludePaths(const StringVector& paths) { + StringVector::const_iterator I = paths.begin(); + StringVector::const_iterator E = paths.end(); + while (I != E) { + sys::Path tmp; + tmp.set(*I); + IncludePaths.push_back(tmp); + ++I; + } + } + + virtual void setSymbolDefines(const StringVector& defs) { + Defines = defs; + } + + virtual void setLibraryPaths(const StringVector& paths) { + StringVector::const_iterator I = paths.begin(); + StringVector::const_iterator E = paths.end(); + while (I != E) { + sys::Path tmp; + tmp.set(*I); + LibraryPaths.push_back(tmp); + ++I; + } + } + + virtual void addLibraryPath(const sys::Path& libPath) { + LibraryPaths.push_back(libPath); + } + + virtual void addToolPath(const sys::Path& toolPath) { + ToolPaths.push_back(toolPath); + } + + virtual void setfPassThrough(const StringVector& fOpts) { + fOptions = fOpts; + } + + /// @brief Set the list of -M options to be passed through + virtual void setMPassThrough(const StringVector& MOpts) { + MOptions = MOpts; + } + + /// @brief Set the list of -W options to be passed through + virtual void setWPassThrough(const StringVector& WOpts) { + WOptions = WOpts; + } + +/// @} +/// @name Functions +/// @{ +private: + bool isSet(DriverFlags flag) { + return 0 != ((flag & DRIVER_FLAGS_MASK) & Flags); + } + + void cleanup() { + if (!isSet(KEEP_TEMPS_FLAG)) { + const sys::FileStatus *Status = TempDir.getFileStatus(); + if (Status && Status->isDir) + TempDir.eraseFromDisk(/*remove_contents=*/true); + } else { + std::cout << "Temporary files are in " << TempDir << "\n"; + } + } + + sys::Path MakeTempFile(const std::string& basename, + const std::string& suffix, + std::string* ErrMsg) { + if (TempDir.isEmpty()) { + TempDir = sys::Path::GetTemporaryDirectory(ErrMsg); + if (TempDir.isEmpty()) + return sys::Path(); + sys::RemoveDirectoryOnSignal(TempDir); + } + sys::Path result(TempDir); + if (!result.appendComponent(basename)) { + if (ErrMsg) + *ErrMsg = basename + ": can't use this file name"; + return sys::Path(); + } + if (!result.appendSuffix(suffix)) { + if (ErrMsg) + *ErrMsg = suffix + ": can't use this file suffix"; + return sys::Path(); + } + return result; + } + + Action* GetAction(ConfigData* cd, + const sys::Path& input, + const sys::Path& output, + Phases phase) + { + 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; + case TRANSLATION: pat = &cd->Translator; break; + case OPTIMIZATION: pat = &cd->Optimizer; break; + case ASSEMBLY: pat = &cd->Assembler; break; + case LINKING: pat = &cd->Linker; break; + default: + assert(!"Invalid driver phase!"); + break; + } + assert(pat != 0 && "Invalid command pattern"); + + // Copy over some pattern things that don't need to change + action->flags = pat->flags; + + // See if program starts with wildcard... + std::string programName=pat->program.toString(); + if (programName[0] == '%' && programName.length() >2) { + switch(programName[1]){ + case 'b': + if (programName.substr(0,8) == "%bindir%") { + std::string tmp(LLVM_BINDIR); + tmp.append(programName.substr(8)); + pat->program.set(tmp); + } + break; + case 'l': + if (programName.substr(0,12) == "%llvmgccdir%"){ + std::string tmp(LLVMGCCDIR); + tmp.append(programName.substr(12)); + pat->program.set(tmp); + }else if (programName.substr(0,13) == "%llvmgccarch%"){ + std::string tmp(LLVMGCCARCH); + tmp.append(programName.substr(13)); + pat->program.set(tmp); + }else if (programName.substr(0,9) == "%llvmgcc%"){ + std::string tmp(LLVMGCC); + tmp.append(programName.substr(9)); + pat->program.set(tmp); + }else if (programName.substr(0,9) == "%llvmgxx%"){ + std::string tmp(LLVMGXX); + tmp.append(programName.substr(9)); + pat->program.set(tmp); + }else if (programName.substr(0,9) == "%llvmcc1%"){ + std::string tmp(LLVMCC1); + tmp.append(programName.substr(9)); + pat->program.set(tmp); + }else if (programName.substr(0,13) == "%llvmcc1plus%"){ + std::string tmp(LLVMCC1PLUS); + tmp.append(programName.substr(13)); + pat->program.set(tmp); + }else if (programName.substr(0,8) == "%libdir%") { + std::string tmp(LLVM_LIBDIR); + tmp.append(programName.substr(8)); + pat->program.set(tmp); + } + break; + } + } + action->program = pat->program; + + // 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] == '%' && PI->length() >2) { + bool found = true; + switch ((*PI)[1]) { + case 'a': + if (*PI == "%args%") { + if (AdditionalArgs.size() > unsigned(phase)) + if (!AdditionalArgs[phase].empty()) { + // Get specific options for each kind of action type + StringVector& addargs = AdditionalArgs[phase]; + // Add specific options for each kind of action type + action->args.insert(action->args.end(), addargs.begin(), + addargs.end()); + } + } else + found = false; + break; + case 'b': + if (*PI == "%bindir%") { + std::string tmp(*PI); + tmp.replace(0,8,LLVM_BINDIR); + action->args.push_back(tmp); + } else + found = false; + break; + case 'd': + if (*PI == "%defs%") { + StringVector::iterator I = Defines.begin(); + StringVector::iterator E = Defines.end(); + while (I != E) { + action->args.push_back( std::string("-D") + *I); + ++I; + } + } else + found = false; + break; + case 'f': + if (*PI == "%fOpts%") { + if (!fOptions.empty()) + action->args.insert(action->args.end(), fOptions.begin(), + fOptions.end()); + } else + found = false; + break; + case 'i': + if (*PI == "%in%") { + action->args.push_back(input.toString()); + } else if (*PI == "%incls%") { + PathVector::iterator I = IncludePaths.begin(); + PathVector::iterator E = IncludePaths.end(); + while (I != E) { + action->args.push_back( std::string("-I") + I->toString() ); + ++I; + } + } else + found = false; + break; + case 'l': + if ((*PI)[1] == 'l') { + std::string tmp(*PI); + if (*PI == "%llvmgccdir%") + tmp.replace(0,12,LLVMGCCDIR); + else if (*PI == "%llvmgccarch%") + tmp.replace(0,13,LLVMGCCARCH); + else if (*PI == "%llvmgcc%") + tmp.replace(0,9,LLVMGCC); + else if (*PI == "%llvmgxx%") + tmp.replace(0,9,LLVMGXX); + else if (*PI == "%llvmcc1%") + tmp.replace(0,9,LLVMCC1); + else if (*PI == "%llvmcc1plus%") + tmp.replace(0,9,LLVMCC1); + else + found = false; + if (found) + action->args.push_back(tmp); + } else if (*PI == "%libs%") { + PathVector::iterator I = LibraryPaths.begin(); + PathVector::iterator E = LibraryPaths.end(); + while (I != E) { + action->args.push_back( std::string("-L") + I->toString() ); + ++I; + } + } else if (*PI == "%libdir%") { + std::string tmp(*PI); + tmp.replace(0,8,LLVM_LIBDIR); + action->args.push_back(tmp); + } else + found = false; + break; + case 'o': + if (*PI == "%out%") { + action->args.push_back(output.toString()); + } else if (*PI == "%opt%") { + if (!isSet(EMIT_RAW_FLAG)) { + 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 + throw std::string("Optimization options for level ") + + utostr(unsigned(optLevel)) + " were not specified"; + } + } else + found = false; + break; + case 's': + if (*PI == "%stats%") { + if (isSet(SHOW_STATS_FLAG)) + action->args.push_back("-stats"); + } else + found = false; + break; + case 't': + if (*PI == "%target%") { + action->args.push_back(std::string("-march=") + machine); + } else if (*PI == "%time%") { + if (isSet(TIME_PASSES_FLAG)) + action->args.push_back("-time-passes"); + } else + found = false; + break; + case 'v': + if (*PI == "%verbose%") { + if (isSet(VERBOSE_FLAG)) + action->args.push_back("-v"); + } else + found = false; + break; + case 'M': + if (*PI == "%Mopts%") { + if (!MOptions.empty()) + action->args.insert(action->args.end(), MOptions.begin(), + MOptions.end()); + } else + found = false; + break; + case 'W': + if (*PI == "%Wopts%") { + for (StringVector::iterator I = WOptions.begin(), + E = WOptions.end(); I != E ; ++I ) { + action->args.push_back(std::string("-W") + *I); + } + } else + found = false; + break; + default: + found = false; + break; + } + if (!found) { + // Did it even look like a substitution? + if (PI->length()>1 && (*PI)[0] == '%' && + (*PI)[PI->length()-1] == '%') { + throw std::string("Invalid substitution token: '") + *PI + + "' for command '" + pat->program.toString() + "'"; + } else if (!PI->empty()) { + // It's not a legal substitution, just pass it through + action->args.push_back(*PI); + } + } + } else if (!PI->empty()) { + // Its not a substitution, just put it in the action + action->args.push_back(*PI); + } + PI++; + } + + // Finally, we're done + return action; + } + + int DoAction(Action*action, std::string& ErrMsg) { + assert(action != 0 && "Invalid Action!"); + if (isSet(VERBOSE_FLAG)) + WriteAction(action); + if (!isSet(DRY_RUN_FLAG)) { + sys::Path progpath = sys::Program::FindProgramByName( + action->program.toString()); + if (progpath.isEmpty()) + throw std::string("Can't find program '" + + action->program.toString()+"'"); + else if (progpath.canExecute()) + action->program = progpath; + else + throw std::string("Program '"+action->program.toString()+ + "' is not executable."); + + // Invoke the program + const char** Args = (const char**) + alloca(sizeof(const char*)*(action->args.size()+2)); + Args[0] = action->program.toString().c_str(); + for (unsigned i = 1; i <= action->args.size(); ++i) + Args[i] = action->args[i-1].c_str(); + Args[action->args.size()+1] = 0; // null terminate list. + if (isSet(TIME_ACTIONS_FLAG)) { + Timer timer(action->program.toString()); + timer.startTimer(); + int resultCode = + sys::Program::ExecuteAndWait(action->program, Args,0,0,0,0, &ErrMsg); + timer.stopTimer(); + timer.print(timer,std::cerr); + return resultCode; + } + else + return + sys::Program::ExecuteAndWait(action->program, Args, 0,0,0,0, &ErrMsg); + } + return 0; + } + + /// This method tries various variants of a linkage item's file + /// name to see if it can find an appropriate file to link with + /// in the directories of the LibraryPaths. + llvm::sys::Path GetPathForLinkageItem(const std::string& link_item, + bool native = false) { + sys::Path fullpath; + fullpath.set(link_item); + if (fullpath.canRead()) + return fullpath; + for (PathVector::iterator PI = LibraryPaths.begin(), + PE = LibraryPaths.end(); PI != PE; ++PI) { + fullpath.set(PI->toString()); + fullpath.appendComponent(link_item); + if (fullpath.canRead()) + return fullpath; + if (native) { + fullpath.appendSuffix("a"); + } else { + fullpath.appendSuffix("bc"); + if (fullpath.canRead()) + return fullpath; + fullpath.eraseSuffix(); + fullpath.appendSuffix("o"); + if (fullpath.canRead()) + return fullpath; + fullpath = *PI; + fullpath.appendComponent(std::string("lib") + link_item); + fullpath.appendSuffix("a"); + if (fullpath.canRead()) + return fullpath; + fullpath.eraseSuffix(); + fullpath.appendSuffix("so"); + if (fullpath.canRead()) + return fullpath; + } + } + + // Didn't find one. + fullpath.clear(); + return fullpath; + } + + /// This method processes a linkage item. The item could be a + /// Bitcode file needing translation to native code and that is + /// dependent on other bitcode libraries, or a native code + /// library that should just be linked into the program. + bool ProcessLinkageItem(const llvm::sys::Path& link_item, + SetVector<sys::Path>& set, + std::string& err) { + // First, see if the unadorned file name is not readable. If so, + // we must track down the file in the lib search path. + sys::Path fullpath; + if (!link_item.canRead()) { + // look for the library using the -L arguments specified + // on the command line. + fullpath = GetPathForLinkageItem(link_item.toString()); + + // If we didn't find the file in any of the library search paths + // we have to bail. No where else to look. + if (fullpath.isEmpty()) { + err = + std::string("Can't find linkage item '") + link_item.toString() + "'"; + return false; + } + } else { + fullpath = link_item; + } + + // If we got here fullpath is the path to the file, and its readable. + set.insert(fullpath); + + // If its an LLVM bitcode file ... + if (fullpath.isBitcodeFile()) { + // Process the dependent libraries recursively + Module::LibraryListType modlibs; + if (GetBitcodeDependentLibraries(fullpath.toString(),modlibs, &err)) { + // Traverse the dependent libraries list + Module::lib_iterator LI = modlibs.begin(); + Module::lib_iterator LE = modlibs.end(); + while ( LI != LE ) { + if (!ProcessLinkageItem(sys::Path(*LI),set,err)) { + if (err.empty()) { + err = std::string("Library '") + *LI + + "' is not valid for linking but is required by file '" + + fullpath.toString() + "'"; + } else { + err += " which is required by file '" + fullpath.toString() + "'"; + } + return false; + } + ++LI; + } + } else if (err.empty()) { + err = std::string( + "The dependent libraries could not be extracted from '") + + fullpath.toString(); + return false; + } else + return false; + } + return true; + } + +/// @} +/// @name Methods +/// @{ +public: + virtual int execute(const InputList& InpList, const sys::Path& Output, std::string& ErrMsg ) { + try { + // Echo the configuration of options if we're running verbose + if (isSet(DEBUG_FLAG)) { + std::cerr << "Compiler Driver Options:\n"; + std::cerr << "DryRun = " << isSet(DRY_RUN_FLAG) << "\n"; + std::cerr << "Verbose = " << isSet(VERBOSE_FLAG) << " \n"; + std::cerr << "TimeActions = " << isSet(TIME_ACTIONS_FLAG) << "\n"; + std::cerr << "TimePasses = " << isSet(TIME_PASSES_FLAG) << "\n"; + std::cerr << "ShowStats = " << isSet(SHOW_STATS_FLAG) << "\n"; + std::cerr << "EmitRawCode = " << isSet(EMIT_RAW_FLAG) << "\n"; + std::cerr << "EmitNativeCode = " << isSet(EMIT_NATIVE_FLAG) << "\n"; + std::cerr << "KeepTemps = " << isSet(KEEP_TEMPS_FLAG) << "\n"; + std::cerr << "OutputMachine = " << machine << "\n"; + InputList::const_iterator I = InpList.begin(); + while ( I != InpList.end() ) { + std::cerr << "Input: " << I->first << "(" << I->second + << ")\n"; + ++I; + } + std::cerr << "Output: " << Output << "\n"; + } + + // If there's no input, we're done. + if (InpList.empty()) + throw std::string("Nothing to compile."); + + // If they are asking for linking and didn't provide an output + // file then its an error (no way for us to "make up" a meaningful + // file name based on the various linker input files). + if (finalPhase == LINKING && Output.isEmpty()) + throw std::string( + "An output file name must be specified for linker output"); + + // If they are not asking for linking, provided an output file and + // there is more than one input file, its an error + if (finalPhase != LINKING && !Output.isEmpty() && InpList.size() > 1) + throw std::string("An output file name cannot be specified ") + + "with more than one input file name when not linking"; + + // This vector holds all the resulting actions of the following loop. + std::vector<Action*> actions; + + /// PRE-PROCESSING / TRANSLATION / OPTIMIZATION / ASSEMBLY phases + // for each input item + SetVector<sys::Path> LinkageItems; + StringVector LibFiles; + InputList::const_iterator I = InpList.begin(); + for (InputList::const_iterator I = InpList.begin(), E = InpList.end(); + I != E; ++I ) { + // Get the suffix of the file name + const std::string& ftype = I->second; + + // If its a library, bitcode file, or object file, save + // it for linking below and short circuit the + // pre-processing/translation/assembly phases + if (ftype.empty() || ftype == "o" || ftype == "bc" || ftype=="a") { + // We shouldn't get any of these types of files unless we're + // later going to link. Enforce this limit now. + if (finalPhase != LINKING) { + throw std::string( + "Pre-compiled objects found but linking not requested"); + } + if (ftype.empty()) + LibFiles.push_back(I->first.toString()); + else + LinkageItems.insert(I->first); + continue; // short circuit remainder of loop + } + + // At this point, we know its something we need to translate + // and/or optimize. See if we can get the configuration data + // for this kind of file. + ConfigData* cd = cdp->ProvideConfigData(I->second); + if (cd == 0) + throw std::string("Files of type '") + I->second + + "' are not recognized."; + if (isSet(DEBUG_FLAG)) + DumpConfigData(cd,I->second); + + // Add the config data's library paths to the end of the list + for (StringVector::iterator LPI = cd->libpaths.begin(), + LPE = cd->libpaths.end(); LPI != LPE; ++LPI){ + LibraryPaths.push_back(sys::Path(*LPI)); + } + + // Initialize the input and output files + sys::Path InFile(I->first); + sys::Path OutFile(I->first.getBasename()); + + // PRE-PROCESSING PHASE + Action& action = cd->PreProcessor; + + // Get the preprocessing action, if needed, or error if appropriate + if (!action.program.isEmpty()) { + if (action.isSet(REQUIRED_FLAG) || finalPhase == PREPROCESSING) { + if (finalPhase == PREPROCESSING) { + if (Output.isEmpty()) { + OutFile.appendSuffix("E"); + actions.push_back(GetAction(cd,InFile,OutFile,PREPROCESSING)); + } else { + actions.push_back(GetAction(cd,InFile,Output,PREPROCESSING)); + } + } else { + sys::Path TempFile( + MakeTempFile(I->first.getBasename(),"E",&ErrMsg)); + if (TempFile.isEmpty()) + return 1; + actions.push_back(GetAction(cd,InFile,TempFile, + PREPROCESSING)); + InFile = TempFile; + } + } + } else if (finalPhase == PREPROCESSING) { + throw cd->langName + " does not support pre-processing"; + } else if (action.isSet(REQUIRED_FLAG)) { + throw 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) { continue; }; + + /// TRANSLATION PHASE + action = cd->Translator; + + // Get the translation action, if needed, or error if appropriate + if (!action.program.isEmpty()) { + if (action.isSet(REQUIRED_FLAG) || finalPhase == TRANSLATION) { + if (finalPhase == TRANSLATION) { + if (Output.isEmpty()) { + OutFile.appendSuffix("o"); + actions.push_back(GetAction(cd,InFile,OutFile,TRANSLATION)); + } else { + actions.push_back(GetAction(cd,InFile,Output,TRANSLATION)); + } + } else { + sys::Path TempFile( + MakeTempFile(I->first.getBasename(),"trans", &ErrMsg)); + if (TempFile.isEmpty()) + return 1; + actions.push_back(GetAction(cd,InFile,TempFile,TRANSLATION)); + InFile = TempFile; + } + + // 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 bitcode + Action* action = new Action(); + action->program.set("llvm-as"); + action->args.push_back(InFile.toString()); + action->args.push_back("-o"); + InFile.appendSuffix("bc"); + action->args.push_back(InFile.toString()); + actions.push_back(action); + } + } + } else if (finalPhase == TRANSLATION) { + throw cd->langName + " does not support translation"; + } else if (action.isSet(REQUIRED_FLAG)) { + throw std::string("Don't know how to translate ") + + cd->langName + " files"; + } + + // Short-circuit remaining actions if all they want is translation + if (finalPhase == TRANSLATION) { continue; } + + /// OPTIMIZATION PHASE + action = cd->Optimizer; + + // Get the optimization action, if needed, or error if appropriate + if (!isSet(EMIT_RAW_FLAG)) { + if (!action.program.isEmpty()) { + if (action.isSet(REQUIRED_FLAG) || finalPhase == OPTIMIZATION) { + if (finalPhase == OPTIMIZATION) { + if (Output.isEmpty()) { + OutFile.appendSuffix("o"); + actions.push_back(GetAction(cd,InFile,OutFile,OPTIMIZATION)); + } else { + actions.push_back(GetAction(cd,InFile,Output,OPTIMIZATION)); + } + } else { + sys::Path TempFile( + MakeTempFile(I->first.getBasename(),"opt", &ErrMsg)); + if (TempFile.isEmpty()) + return 1; + actions.push_back(GetAction(cd,InFile,TempFile,OPTIMIZATION)); + InFile = TempFile; + } + // ll -> bc Helper + if (action.isSet(OUTPUT_IS_ASM_FLAG)) { + /// The output of the optimizer is an LLVM Assembly program + /// We need to translate it to bitcode with llvm-as + Action* action = new Action(); + action->program.set("llvm-as"); + action->args.push_back(InFile.toString()); + action->args.push_back("-f"); + action->args.push_back("-o"); + InFile.appendSuffix("bc"); + action->args.push_back(InFile.toString()); + actions.push_back(action); + } + } + } else if (finalPhase == OPTIMIZATION) { + throw cd->langName + " does not support optimization"; + } else if (action.isSet(REQUIRED_FLAG)) { + throw std::string("Don't know how to optimize ") + + cd->langName + " files"; + } + } + + // Short-circuit remaining actions if all they want is optimization + if (finalPhase == OPTIMIZATION) { continue; } + + /// ASSEMBLY PHASE + action = cd->Assembler; + + if (finalPhase == ASSEMBLY) { + + // Build either a native compilation action or a disassembly action + Action* action = new Action(); + if (isSet(EMIT_NATIVE_FLAG)) { + // Use llc to get the native assembly file + action->program.set("llc"); + action->args.push_back(InFile.toString()); + action->args.push_back("-f"); + action->args.push_back("-o"); + if (Output.isEmpty()) { + OutFile.appendSuffix("o"); + action->args.push_back(OutFile.toString()); + } else { + action->args.push_back(Output.toString()); + } + actions.push_back(action); + } else { + // Just convert back to llvm assembly with llvm-dis + action->program.set("llvm-dis"); + action->args.push_back(InFile.toString()); + action->args.push_back("-f"); + action->args.push_back("-o"); + if (Output.isEmpty()) { + OutFile.appendSuffix("ll"); + action->args.push_back(OutFile.toString()); + } else { + action->args.push_back(Output.toString()); + } + } + + // Put the action on the list + actions.push_back(action); + + // Short circuit the rest of the loop, we don't want to link + continue; + } + + // Register the result of the actions as a link candidate + LinkageItems.insert(InFile); + + } // end while loop over each input file + + /// RUN THE COMPILATION ACTIONS + std::vector<Action*>::iterator AI = actions.begin(); + std::vector<Action*>::iterator AE = actions.end(); + while (AI != AE) { + int ActionResult = DoAction(*AI, ErrMsg); + if (ActionResult != 0) + return ActionResult; + AI++; + } + + /// LINKING PHASE + if (finalPhase == LINKING) { + + // Insert the platform-specific system libraries to the path list + std::vector<sys::Path> SysLibs; + sys::Path::GetSystemLibraryPaths(SysLibs); + LibraryPaths.insert(LibraryPaths.end(), SysLibs.begin(), SysLibs.end()); + + // Set up the linking action with llvm-ld + Action* link = new Action(); + link->program.set("llvm-ld"); + + // Add in the optimization level requested + switch (optLevel) { + case OPT_FAST_COMPILE: + link->args.push_back("-O1"); + break; + case OPT_SIMPLE: + link->args.push_back("-O2"); + break; + case OPT_AGGRESSIVE: + link->args.push_back("-O3"); + break; + case OPT_LINK_TIME: + link->args.push_back("-O4"); + break; + case OPT_AGGRESSIVE_LINK_TIME: + link->args.push_back("-O5"); + break; + case OPT_NONE: + break; + } + + // Add in all the linkage items we generated. This includes the + // output from the translation/optimization phases as well as any + // -l arguments specified. + for (PathVector::const_iterator I=LinkageItems.begin(), + E=LinkageItems.end(); I != E; ++I ) + link->args.push_back(I->toString()); + + // Add in all the libraries we found. + for (StringVector::const_iterator I=LibFiles.begin(), + E=LibFiles.end(); I != E; ++I ) + link->args.push_back(std::string("-l")+*I); + + // Add in all the library paths to the command line + for (PathVector::const_iterator I=LibraryPaths.begin(), + E=LibraryPaths.end(); I != E; ++I) + link->args.push_back( std::string("-L") + I->toString()); + + // Add in the additional linker arguments requested + for (StringVector::const_iterator I=AdditionalArgs[LINKING].begin(), + E=AdditionalArgs[LINKING].end(); I != E; ++I) + link->args.push_back( *I ); + + // Add in other optional flags + if (isSet(EMIT_NATIVE_FLAG)) + link->args.push_back("-native"); + if (isSet(VERBOSE_FLAG)) + link->args.push_back("-v"); + if (isSet(TIME_PASSES_FLAG)) + link->args.push_back("-time-passes"); + if (isSet(SHOW_STATS_FLAG)) + link->args.push_back("-stats"); + if (isSet(STRIP_OUTPUT_FLAG)) + link->args.push_back("-s"); + if (isSet(DEBUG_FLAG)) { + link->args.push_back("-debug"); + link->args.push_back("-debug-pass=Details"); + } + + // Add in mandatory flags + link->args.push_back("-o"); + link->args.push_back(Output.toString()); + + // Execute the link + int ActionResult = DoAction(link, ErrMsg); + if (ActionResult != 0) + return ActionResult; + } + } catch (std::string& msg) { + cleanup(); + throw; + } catch (...) { + cleanup(); + throw std::string("Unspecified error"); + } + cleanup(); + return 0; + } + +/// @} +/// @name Data +/// @{ +private: + ConfigDataProvider* cdp; ///< Where we get configuration data from + Phases finalPhase; ///< The final phase of compilation + OptimizationLevels optLevel; ///< The optimization level to apply + unsigned Flags; ///< The driver flags + std::string machine; ///< Target machine name + PathVector LibraryPaths; ///< -L options + PathVector IncludePaths; ///< -I options + PathVector ToolPaths; ///< -B options + StringVector Defines; ///< -D options + sys::PathWithStatus TempDir; ///< Name of the temporary directory. + StringTable AdditionalArgs; ///< The -Txyz options + StringVector fOptions; ///< -f options + StringVector MOptions; ///< -M options + StringVector WOptions; ///< -W options + +/// @} +}; +} + +CompilerDriver::~CompilerDriver() { +} + +CompilerDriver::ConfigDataProvider::~ConfigDataProvider() {} + +CompilerDriver* +CompilerDriver::Get(ConfigDataProvider& CDP) { + return new CompilerDriverImpl(CDP); +} + +CompilerDriver::ConfigData::ConfigData() + : langName() + , PreProcessor() + , Translator() + , Optimizer() + , Assembler() + , Linker() +{ + StringVector emptyVec; + for (unsigned i = 0; i < NUM_PHASES; ++i) + opts.push_back(emptyVec); +} |