//===- 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 "Support/FileUtilities.h" #include "Support/SetVector.h" #include "Support/StringExtras.h" #include using namespace llvm; namespace { void WriteAction(CompilerDriver::Action* action ) { std::cerr << action->program.c_str(); std::vector::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::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(); AdditionalArgs.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 setLibraryPaths(const StringVector& paths) { StringVector::const_iterator I = paths.begin(); StringVector::const_iterator E = paths.end(); while (I != E) { sys::Path tmp; tmp.set_directory(*I); LibraryPaths.push_back(tmp); ++I; } } virtual void addLibraryPath( const sys::Path& libPath ) { LibraryPaths.push_back(libPath); } /// @} /// @name Functions /// @{ private: bool isSet(DriverFlags flag) { return 0 != ((flag & DRIVER_FLAGS_MASK) & Flags); } void cleanup() { if (!isSet(KEEP_TEMPS_FLAG)) { if (TempDir.is_directory() && TempDir.writable()) TempDir.destroy_directory(/*remove_contents=*/true); } else { std::cout << "Temporary files are in " << TempDir.get() << "\n"; } } sys::Path MakeTempFile(const std::string& basename, const std::string& suffix ) { sys::Path result(TempDir); if (!result.append_file(basename)) throw basename + ": can't use this file name"; if (!result.append_suffix(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] == '%') { if (*PI == "%in%") { action->args.push_back(input.get()); } else if (*PI == "%out%") { action->args.push_back(output.get()); } else if (*PI == "%time%") { if (isSet(TIME_PASSES_FLAG)) action->args.push_back("-time-passes"); } else if (*PI == "%stats%") { if (isSet(SHOW_STATS_FLAG)) action->args.push_back("-stats"); } else if (*PI == "%force%") { if (isSet(FORCE_FLAG)) action->args.push_back("-f"); } else if (*PI == "%verbose%") { if (isSet(VERBOSE_FLAG)) action->args.push_back("-v"); } else if (*PI == "%target%") { // FIXME: Ignore for now } else if (*PI == "%opt%") { if (!isSet(EMIT_RAW_FLAG)) { if (cd->opts.size() > static_cast(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 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 { throw "Invalid substitution name" + *PI; } } else { // 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)) { action->program = sys::Program::FindProgramByName(action->program.get()); if (action->program.is_empty()) throw "Can't find program '" + action->program.get() + "'"; // Invoke the program return 0 == action->program.ExecuteAndWait(action->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 directory specified. llvm::sys::Path GetPathForLinkageItem(const std::string& link_item, const sys::Path& dir) { sys::Path fullpath(dir); fullpath.append_file(link_item); fullpath.append_suffix("bc"); if (fullpath.readable()) return fullpath; fullpath.elide_suffix(); fullpath.append_suffix("o"); if (fullpath.readable()) return fullpath; fullpath = dir; fullpath.append_file(std::string("lib") + link_item); fullpath.append_suffix("a"); if (fullpath.readable()) return fullpath; fullpath.elide_suffix(); fullpath.append_suffix("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& 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()) { // First, look for the library using the -L arguments specified // on the command line. PathVector::iterator PI = LibraryPaths.begin(); PathVector::iterator PE = LibraryPaths.end(); while (PI != PE && fullpath.is_empty()) { fullpath = GetPathForLinkageItem(link_item.get(),*PI); ++PI; } // If we didn't find the file in any of the library search paths // so we have to bail. No where else to look. if (fullpath.is_empty()) { err = std::string("Can't find linkage item '") + link_item.get() + "'"; 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 (CheckMagic(fullpath.get(), "llvm")) { // Process the dependent libraries recursively Module::LibraryListType modlibs; if (GetBytecodeDependentLibraries(fullpath.get(),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.get() + "'"; } else { err += " which is required by file '" + fullpath.get() + "'"; } return false; } ++LI; } } else if (err.empty()) { err = std::string("The dependent libraries could not be extracted from '") + fullpath.get(); 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 << "ForceOutput = " << isSet(FORCE_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.get() << "(" << I->second << ")\n"; ++I; } std::cerr << "Output: " << Output.get() << "\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.is_empty()) throw std::string( "An output file name must be specified for linker output"); // This vector holds all the resulting actions of the following loop. std::vector actions; /// PRE-PROCESSING / TRANSLATION / OPTIMIZATION / ASSEMBLY phases // for each input item SetVector LinkageItems; sys::Path OutFile(Output); InputList::const_iterator I = InpList.begin(); while ( I != InpList.end() ) { // 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") { // 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"); } LinkageItems.insert(I->first); ++I; 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); // Initialize the input file sys::Path InFile(I->first); // PRE-PROCESSING PHASE Action& action = cd->PreProcessor; // Get the preprocessing action, if needed, or error if appropriate if (!action.program.is_empty()) { if (action.isSet(REQUIRED_FLAG) || finalPhase == PREPROCESSING) { if (finalPhase == PREPROCESSING) actions.push_back(GetAction(cd,InFile,OutFile,PREPROCESSING)); else { sys::Path TempFile(MakeTempFile(I->first.get(),"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) { ++I; continue; }; /// TRANSLATION PHASE action = cd->Translator; // Get the translation action, if needed, or error if appropriate if (!action.program.is_empty()) { if (action.isSet(REQUIRED_FLAG) || finalPhase == TRANSLATION) { if (finalPhase == TRANSLATION) actions.push_back(GetAction(cd,InFile,OutFile,TRANSLATION)); else { sys::Path TempFile(MakeTempFile(I->first.get(),"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.set_file("llvm-as"); action->args.push_back(InFile.get()); action->args.push_back("-o"); InFile.append_suffix("bc"); action->args.push_back(InFile.get()); 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) { ++I; continue; } /// OPTIMIZATION PHASE action = cd->Optimizer; // Get the optimization action, if needed, or error if appropriate if (!isSet(EMIT_RAW_FLAG)) { if (!action.program.is_empty()) { if (action.isSet(REQUIRED_FLAG) || finalPhase == OPTIMIZATION) { if (finalPhase == OPTIMIZATION) actions.push_back(GetAction(cd,InFile,OutFile,OPTIMIZATION)); else { sys::Path TempFile(MakeTempFile(I->first.get(),"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 translator is an LLVM Assembly program /// We need to translate it to bytecode Action* action = new Action(); action->program.set_file("llvm-as"); action->args.push_back(InFile.get()); action->args.push_back("-f"); action->args.push_back("-o"); InFile.append_suffix("bc"); action->args.push_back(InFile.get()); 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) { ++I; continue; } /// ASSEMBLY PHASE action = cd->Assembler; if (finalPhase == ASSEMBLY || isSet(EMIT_NATIVE_FLAG)) { if (isSet(EMIT_NATIVE_FLAG)) { if (action.program.is_empty()) { throw std::string("Native Assembler not specified for ") + cd->langName + " files"; } else if (finalPhase == ASSEMBLY) { actions.push_back(GetAction(cd,InFile,OutFile,ASSEMBLY)); } else { sys::Path TempFile(MakeTempFile(I->first.get(),"S")); actions.push_back(GetAction(cd,InFile,TempFile,ASSEMBLY)); InFile = TempFile; } } else { // Just convert back to llvm assembly with llvm-dis Action* action = new Action(); action->program.set_file("llvm-dis"); action->args.push_back(InFile.get()); action->args.push_back("-f"); action->args.push_back("-o"); action->args.push_back(OutFile.get()); actions.push_back(action); } } // Short-circuit remaining actions if all they want is assembly output if (finalPhase == ASSEMBLY) { ++I; continue; } // Register the OutFile as a link candidate LinkageItems.insert(InFile); // Go to next file to be processed ++I; } /// RUN THE COMPILATION ACTIONS std::vector::iterator AI = actions.begin(); std::vector::iterator AE = actions.end(); while (AI != AE) { if (!DoAction(*AI)) throw "Action failed"; AI++; } /// LINKING PHASE actions.clear(); if (finalPhase == LINKING) { if (isSet(EMIT_NATIVE_FLAG)) { throw "llvmc doesn't know how to link native code yet"; } else { // First, we need to examine the files to ensure that they all contain // bytecode files. Since the final output is bytecode, we can only // link bytecode. SetVector::const_iterator I = LinkageItems.begin(); SetVector::const_iterator E = LinkageItems.end(); std::string errmsg; while (I != E && ProcessLinkageItem(*I,LinkageItems,errmsg)) ++I; if (!errmsg.empty()) throw errmsg; // Insert the system libraries. LibraryPaths.push_back(sys::Path::GetSystemLibraryPath1()); LibraryPaths.push_back(sys::Path::GetSystemLibraryPath2()); // We're emitting bytecode so let's build an llvm-link Action Action* link = new Action(); link->program.set_file("llvm-link"); for (PathVector::const_iterator I=LinkageItems.begin(), E=LinkageItems.end(); I != E; ++I ) link->args.push_back(I->get()); if (isSet(VERBOSE_FLAG)) link->args.push_back("-v"); link->args.push_back("-f"); link->args.push_back("-o"); link->args.push_back(OutFile.get()); if (isSet(TIME_PASSES_FLAG)) link->args.push_back("-time-passes"); if (isSet(SHOW_STATS_FLAG)) link->args.push_back("-stats"); actions.push_back(link); } } /// RUN THE LINKING ACTIONS AI = actions.begin(); AE = actions.end(); while (AI != AE) { if (!DoAction(*AI)) throw std::string("Action failed"); AI++; } } 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 sys::Path TempDir; ///< Name of the temporary directory. StringTable AdditionalArgs; ///< The -Txyz 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