| //===- 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/Bytecode/Reader.h" |
| #include "llvm/Support/Timer.h" |
| #include "llvm/System/Signals.h" |
| #include "llvm/ADT/SetVector.h" |
| #include "llvm/ADT/StringExtras.h" |
| #include <iostream> |
| #include "llvm/Config/alloca.h" |
| |
| 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); |
| } |
| |
| /// 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* DefaultFastCompileOptimizations[] = { |
| "-simplifycfg", "-mem2reg", "-instcombine" |
| }; |
| |
| class CompilerDriverImpl : public CompilerDriver { |
| /// @name Constructors |
| /// @{ |
| public: |
| CompilerDriverImpl(ConfigDataProvider& confDatProv ) |
| : cdp(&confDatProv) |
| , finalPhase(LINKING) |
| , optLevel(OPT_FAST_COMPILE) |
| , Flags(0) |
| , machine() |
| , LibraryPaths() |
| , TempDir() |
| , AdditionalArgs() |
| { |
| TempDir = sys::Path::GetTemporaryDirectory(); |
| sys::RemoveDirectoryOnSignal(TempDir); |
| 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.setDirectory(*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.setDirectory(*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)) { |
| if (TempDir.isDirectory() && TempDir.writable()) |
| TempDir.destroyDirectory(/*remove_contents=*/true); |
| } else { |
| std::cout << "Temporary files are in " << TempDir << "\n"; |
| } |
| } |
| |
| sys::Path MakeTempFile(const std::string& basename, |
| const std::string& suffix ) { |
| sys::Path result(TempDir); |
| if (!result.appendFile(basename)) |
| throw basename + ": can't use this file name"; |
| if (!result.appendSuffix(suffix)) |
| throw suffix + ": can't use this file suffix"; |
| 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->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] == '%' && 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 '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 == "%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 |
| 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; |
| } |
| |
| bool DoAction(Action*action) { |
| 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.executable()) |
| 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()+1)); |
| for (unsigned i = 0; i != action->args.size(); ++i) |
| Args[i] = action->args[i].c_str(); |
| Args[action->args.size()] = 0; // null terminate list. |
| if (isSet(TIME_ACTIONS_FLAG)) { |
| Timer timer(action->program.toString()); |
| timer.startTimer(); |
| int resultCode = sys::Program::ExecuteAndWait(action->program, Args); |
| timer.stopTimer(); |
| timer.print(timer,std::cerr); |
| return resultCode == 0; |
| } |
| else |
| return 0 == sys::Program::ExecuteAndWait(action->program, Args); |
| } |
| return true; |
| } |
| |
| /// 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.setFile(link_item); |
| if (fullpath.readable()) |
| return fullpath; |
| for (PathVector::iterator PI = LibraryPaths.begin(), |
| PE = LibraryPaths.end(); PI != PE; ++PI) { |
| fullpath.setDirectory(PI->toString()); |
| fullpath.appendFile(link_item); |
| if (fullpath.readable()) |
| return fullpath; |
| if (native) { |
| fullpath.appendSuffix("a"); |
| } else { |
| fullpath.appendSuffix("bc"); |
| if (fullpath.readable()) |
| return fullpath; |
| fullpath.elideSuffix(); |
| fullpath.appendSuffix("o"); |
| if (fullpath.readable()) |
| return fullpath; |
| fullpath = *PI; |
| fullpath.appendFile(std::string("lib") + link_item); |
| fullpath.appendSuffix("a"); |
| if (fullpath.readable()) |
| return fullpath; |
| fullpath.elideSuffix(); |
| fullpath.appendSuffix("so"); |
| if (fullpath.readable()) |
| return fullpath; |
| } |
| } |
| |
| // Didn't find one. |
| fullpath.clear(); |
| return fullpath; |
| } |
| |
| /// This method processes a linkage item. The item could be a |
| /// Bytecode file needing translation to native code and that is |
| /// dependent on other bytecode 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.readable()) { |
| // 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 bytecode file ... |
| if (fullpath.isBytecodeFile()) { |
| // Process the dependent libraries recursively |
| Module::LibraryListType modlibs; |
| if (GetBytecodeDependentLibraries(fullpath.toString(),modlibs)) { |
| // 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; |
| } |
| } |
| return true; |
| } |
| |
| /// @} |
| /// @name Methods |
| /// @{ |
| public: |
| virtual int execute(const InputList& InpList, const sys::Path& Output ) { |
| 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, bytecode 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")); |
| 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")); |
| 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 bytecode |
| Action* action = new Action(); |
| action->program.setFile("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")); |
| 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 bytecode with llvm-as |
| Action* action = new Action(); |
| action->program.setFile("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.setFile("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.setFile("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) { |
| if (!DoAction(*AI)) |
| throw std::string("Action failed"); |
| 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.setFile("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 |
| if (!DoAction(link)) |
| throw std::string("Action failed"); |
| } |
| } 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::Path 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* |
| 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); |
| } |
| |
| // vim: sw=2 smartindent smarttab tw=80 autoindent expandtab |