diff options
Diffstat (limited to 'llvm')
| -rw-r--r-- | llvm/tools/llvmc/CompilerDriver.cpp | 1083 | ||||
| -rw-r--r-- | llvm/tools/llvmc/CompilerDriver.h | 134 | ||||
| -rw-r--r-- | llvm/tools/llvmc/ConfigLexer.h | 2 | ||||
| -rw-r--r-- | llvm/tools/llvmc/ConfigLexer.l | 6 | ||||
| -rw-r--r-- | llvm/tools/llvmc/Configuration.cpp | 69 | ||||
| -rw-r--r-- | llvm/tools/llvmc/Configuration.h | 7 | ||||
| -rw-r--r-- | llvm/tools/llvmc/Makefile | 2 | ||||
| -rw-r--r-- | llvm/tools/llvmc/llvmc.cpp | 66 | ||||
| -rw-r--r-- | llvm/tools/llvmc/st | 4 | 
9 files changed, 686 insertions, 687 deletions
diff --git a/llvm/tools/llvmc/CompilerDriver.cpp b/llvm/tools/llvmc/CompilerDriver.cpp index 08d60929a01..7dadf433261 100644 --- a/llvm/tools/llvmc/CompilerDriver.cpp +++ b/llvm/tools/llvmc/CompilerDriver.cpp @@ -14,26 +14,19 @@  #include "CompilerDriver.h"  #include "ConfigLexer.h" -#include "llvm/Bytecode/Reader.h"  #include "llvm/Module.h" +#include "llvm/Bytecode/Reader.h"  #include "Support/FileUtilities.h" -#include "Support/SystemUtils.h" +#include "Support/SetVector.h"  #include "Support/StringExtras.h"  #include <iostream>  using namespace llvm;  namespace { -  inline std::string RemoveSuffix(const std::string& fullName) { -    size_t dotpos = fullName.rfind('.',fullName.size()); -    if ( dotpos == std::string::npos ) return fullName; -    return fullName.substr(0, dotpos); -  } - -  const char OutputSuffix[] = ".o";    void WriteAction(CompilerDriver::Action* action ) { -    std::cerr << action->program; +    std::cerr << action->program.c_str();      std::vector<std::string>::iterator I = action->args.begin();      while (I != action->args.end()) {        std::cerr << " " + *I; @@ -43,7 +36,7 @@ namespace {    }    void DumpAction(CompilerDriver::Action* action) { -    std::cerr << "command = " << action->program; +    std::cerr << "command = " << action->program.c_str();      std::vector<std::string>::iterator I = action->args.begin();      while (I != action->args.end()) {        std::cerr << " " + *I; @@ -74,558 +67,610 @@ namespace {    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 { - -  bool FileIsReadable(const std::string& fname) { -    return 0 == access(fname.c_str(), F_OK | R_OK); -  } - -  void CleanupTempFile(const std::string& fname) { -    if (FileIsReadable(fname)) -      unlink(fname.c_str()); -  } -  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; -  } +  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); +      } -  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--; +      virtual ~CompilerDriverImpl() { +        cleanup(); +        cdp = 0; +        LibraryPaths.clear(); +        AdditionalArgs.clear();        } -    } -    // If we fell out, we ran out of directories in PATH to search, return failure -    return ""; -  } -} +    /// @} +    /// @name Methods +    /// @{ +    public: +      virtual void setFinalPhase( Phases phase ) {  +        finalPhase = phase;  +      } -CompilerDriver::CompilerDriver(ConfigDataProvider& confDatProv ) -  : cdp(&confDatProv) -  , finalPhase(LINKING) -  , optLevel(OPT_FAST_COMPILE)  -  , isDryRun(false) -  , isVerbose(false) -  , isDebug(false) -  , timeActions(false) -  , emitRawCode(false) -  , emitNativeCode(false) -  , keepTemps(false) -  , machine() -  , LibraryPaths() -  , 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); -} +      virtual void setOptimization( OptimizationLevels level ) {  +        optLevel = level;  +      } -CompilerDriver::~CompilerDriver() { -  cdp = 0; -  LibraryPaths.clear(); -  AdditionalArgs.clear(); -} +      virtual void setDriverFlags( unsigned flags ) { +        Flags = flags & DRIVER_FLAGS_MASK;  +      } -CompilerDriver::ConfigData::ConfigData() -  : langName() -  , PreProcessor() -  , Translator() -  , Optimizer() -  , Assembler() -  , Linker() -{ -  StringVector emptyVec; -  for (unsigned i = 0; i < NUM_PHASES; ++i) -    opts.push_back(emptyVec); -} +      virtual void setOutputMachine( const std::string& machineName ) { +        machine = machineName; +      } -void CompilerDriver::error( const std::string& errmsg ) { -  std::cerr << "llvmc: Error: " << errmsg << ".\n"; -  exit(1); -} +      virtual void setPhaseArgs(Phases phase, const StringVector& opts) { +        assert(phase <= LINKING && phase >= PREPROCESSING); +        AdditionalArgs[phase] = opts; +      } -CompilerDriver::Action* CompilerDriver::GetAction(ConfigData* cd,  -                          const std::string& input,  -                          const std::string& 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); -      } 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 (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("Optimization options for level " + utostr(unsigned(optLevel)) +  -                  " were not specified"); +      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;          } -      } 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 { -        error("Invalid substitution name" + *PI);        } -    } else { -      // Its not a substitution, just put it in the action -      action->args.push_back(*PI); -    } -    PI++; -  } +      virtual void addLibraryPath( const sys::Path& libPath ) { +        LibraryPaths.push_back(libPath); +      } -  // Finally, we're done -  return action; -} - -bool CompilerDriver::DoAction(Action*action) { -  assert(action != 0 && "Invalid Action!"); -  if (isVerbose) -    WriteAction(action); -  if (!isDryRun) { -    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; -} - -/// 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. -std::string CompilerDriver::GetPathForLinkageItem(const std::string& link_item, -                                                  const std::string& dir) { -  std::string fullpath(dir + "/" + link_item + ".o"); -  if (::sys::FileIsReadable(fullpath))  -    return fullpath; -  fullpath = dir + "/" + link_item + ".bc"; -  if (::sys::FileIsReadable(fullpath))  -    return fullpath; -  fullpath = dir + "/lib" + link_item + ".a"; -  if (::sys::FileIsReadable(fullpath)) -    return fullpath; -  fullpath = dir + "/lib" + link_item + ".so"; -  if (::sys::FileIsReadable(fullpath)) -    return fullpath; -  return ""; -} +    /// @} +    /// @name Functions +    /// @{ +    private: +      bool isSet(DriverFlags flag) { +        return 0 != ((flag & DRIVER_FLAGS_MASK) & Flags); +      } -/// 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 CompilerDriver::ProcessLinkageItem(const std::string& link_item, -                                        SetVector<std::string>& 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. -  std::string fullpath; -  if (!sys::FileIsReadable(link_item)) { -    // First, look for the library using the -L arguments specified -    // on the command line. -    StringVector::iterator PI = LibraryPaths.begin(); -    StringVector::iterator PE = LibraryPaths.end(); -    while (PI != PE && fullpath.empty()) { -      fullpath = GetPathForLinkageItem(link_item,*PI); -      ++PI; -    } +      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"; +        } +      } -    // 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.empty()) { -      err = std::string("Can't find linkage item '") + link_item + "'"; -      return false; -    } -  } else { -    fullpath = link_item; -  } +      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; +      } -  // 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, "llvm")) { -    // Process the dependent libraries recursively -    Module::LibraryListType modlibs; -    if (GetBytecodeDependentLibraries(fullpath,modlibs)) { -      // Traverse the dependent libraries list -      Module::lib_iterator LI = modlibs.begin(); -      Module::lib_iterator LE = modlibs.end(); -      while ( LI != LE ) { -        if (!ProcessLinkageItem(*LI,set,err)) { -          if (err.empty()) { -            err = std::string("Library '") + *LI +  -                  "' is not valid for linking but is required by file '" + -                  fullpath + "'"; +      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<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 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 { -            err += " which is required by file '" + fullpath + "'"; +            // Its not a substitution, just put it in the action +            action->args.push_back(*PI);            } -          return false; +          PI++;          } -        ++LI; -      } -    } else if (err.empty()) { -      err = std::string("The dependent libraries could not be extracted from '") -                        + fullpath; -      return false; -    } -  } -  return true; -} -int CompilerDriver::execute(const InputList& InpList,  -                            const std::string& Output ) { -  // Echo the configuration of options if we're running verbose -  if (isDebug) -  { -    std::cerr << "Compiler Driver Options:\n"; -    std::cerr << "DryRun = " << isDryRun << "\n"; -    std::cerr << "Verbose = " << isVerbose << " \n"; -    std::cerr << "TimeActions = " << timeActions << "\n"; -    std::cerr << "EmitRawCode = " << emitRawCode << "\n"; -    std::cerr << "OutputMachine = " << machine << "\n"; -    std::cerr << "EmitNativeCode = " << emitNativeCode << "\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()) -    error("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.empty()) -    error("An output file name must be specified for linker output"); - -  // This vector holds all the resulting actions of the following loop. -  std::vector<Action*> actions; - -  // Create a temporary directory for our temporary files -  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 -  std::vector<std::string> LinkageItems; -  std::string 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) { -        error("Pre-compiled objects found but linking not requested"); +        // Finally, we're done +        return action;        } -      LinkageItems.push_back(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) -      error(std::string("Files of type '") + I->second +  -            "' are not recognized." );  -    if (isDebug) -      DumpConfigData(cd,I->second); - -    // Initialize the input file -    std::string InFile(I->first); - -    // PRE-PROCESSING PHASE -    Action& action = cd->PreProcessor; - -    // Get the preprocessing action, if needed, or error if appropriate -    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; +      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;        } -    } else if (finalPhase == PREPROCESSING) { -      error(cd->langName + " does not support pre-processing"); -    } 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; }; +      /// 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; +      } -    /// TRANSLATION PHASE -    action = cd->Translator; +      /// 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()) { +          // 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; +          } -    // Get the translation action, if needed, or error if appropriate -    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; +          // 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;          } -        // 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); +        // 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;        } -    } else if (finalPhase == TRANSLATION) { -      error(cd->langName + " does not support translation"); -    } 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 -    action = cd->Optimizer; - -    // Get the optimization action, if needed, or error if appropriate -    if (!emitRawCode) { -      if (!action.program.empty()) { -        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; +    /// @} +    /// @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";            } -          // 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("-f"); -            action->args.push_back("-o"); -            InFile += ".bc"; -            action->args.push_back(InFile); -            actions.push_back(action); + +          // 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<Action*> actions; + +          /// PRE-PROCESSING / TRANSLATION / OPTIMIZATION / ASSEMBLY phases +          // for each input item +          SetVector<sys::Path> 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;            } -        } -      } else if (finalPhase == OPTIMIZATION) { -        error(cd->langName + " does not support optimization"); -      } 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; } +          /// 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 "Action failed"; +            AI++; +          } -    /// ASSEMBLY PHASE -    action = cd->Assembler; +          /// 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<sys::Path>::const_iterator I = LinkageItems.begin(); +              SetVector<sys::Path>::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); +            } +          } -    if (finalPhase == ASSEMBLY || emitNativeCode) { -      if (emitNativeCode) { -        if (action.program.empty()) { -          error(std::string("Native Assembler not specified for ") + -                cd->langName + " files"); -        } else if (finalPhase == ASSEMBLY) { -          actions.push_back(GetAction(cd,InFile,OutFile,ASSEMBLY)); -        } else { -          actions.push_back(GetAction(cd,InFile,TempAssemblerOut,ASSEMBLY)); -          InFile = TempAssemblerOut; +          /// 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");          } -      } else { -        // Just convert back to llvm assembly with llvm-dis -        Action* action = new Action(); -        action->program = "llvm-dis"; -        action->args.push_back(InFile); -        action->args.push_back("-f"); -        action->args.push_back("-o"); -        action->args.push_back(OutFile); -        actions.push_back(action); +        cleanup(); +        return 0;        } -    } - -    // Short-circuit remaining actions if all they want is assembly output -    if (finalPhase == ASSEMBLY) { ++I; continue; } -       -    // Register the OutFile as a link candidate -    LinkageItems.push_back(InFile); - -    // Go to next file to be processed -    ++I; -  } - -  /// RUN THE COMPILATION ACTIONS -  std::vector<Action*>::iterator aIter = actions.begin(); -  while (aIter != actions.end()) { -    if (!DoAction(*aIter)) -      error("Action failed"); -    aIter++; -  } -  /// LINKING PHASE -  if (finalPhase == LINKING) { -    if (emitNativeCode) { -      error("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. -      StringVector::const_iterator I = LinkageItems.begin(); -      StringVector::const_iterator E = LinkageItems.end(); -      SetVector<std::string> link_items; -      std::string errmsg; -      while (I != E && ProcessLinkageItem(*I,link_items,errmsg)) -        ++I; - -      if (!errmsg.empty()) -        error(errmsg); - -      // We're emitting bytecode so let's build an llvm-link Action -      Action* link = new Action(); -      link->program = "llvm-link"; -      link->args = LinkageItems; -      link->args.insert(link->args.end(), link_items.begin(), link_items.end()); -      link->args.push_back("-f"); -      link->args.push_back("-o"); -      link->args.push_back(OutFile); -      if (timePasses) -        link->args.push_back("-time-passes"); -      if (showStats) -        link->args.push_back("-stats"); -      actions.push_back(link); -    } -  } +    /// @} +    /// @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 + +    /// @} +  }; +} -  if (!keepTemps) { -    // Cleanup files -    ::sys::CleanupTempFile(TempPreprocessorOut); -    ::sys::CleanupTempFile(TempTranslatorOut); -    ::sys::CleanupTempFile(TempOptimizerOut); +CompilerDriver::~CompilerDriver() { +} -    // Cleanup temporary directory we created -    if (::sys::FileIsReadable(TempDir)) -      rmdir(TempDir.c_str()); -  } +CompilerDriver* +CompilerDriver::Get(ConfigDataProvider& CDP) { +  return new CompilerDriverImpl(CDP); +} -  return 0; +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 diff --git a/llvm/tools/llvmc/CompilerDriver.h b/llvm/tools/llvmc/CompilerDriver.h index a6d0be084b6..ea999b44d99 100644 --- a/llvm/tools/llvmc/CompilerDriver.h +++ b/llvm/tools/llvmc/CompilerDriver.h @@ -16,7 +16,7 @@  #include <string>  #include <vector> -#include "Support/SetVector.h" +#include "llvm/System/Program.h"  namespace llvm {    /// This class provides the high level interface to the LLVM Compiler Driver. @@ -30,9 +30,12 @@ namespace llvm {      /// @name Types      /// @{      public: -      /// @brief A vector of strings, commonly used +      /// @brief A vector of strings, used for argument lists        typedef std::vector<std::string> StringVector; +      /// @brief A vector of sys::Path, used for path lists +      typedef std::vector<sys::Path> PathVector; +        /// @brief A table of strings, indexed typically by Phases        typedef std::vector<StringVector> StringTable; @@ -65,11 +68,26 @@ namespace llvm {          FLAGS_MASK           = 0x000F, ///< Union of all flags        }; +      /// @brief Driver specific flags +      enum DriverFlags { +        DRY_RUN_FLAG         = 0x0001, ///< Do everything but execute actions +        FORCE_FLAG           = 0x0002, ///< Force overwrite of output files +        VERBOSE_FLAG         = 0x0004, ///< Print each action +        DEBUG_FLAG           = 0x0008, ///< Print debug information +        TIME_PASSES_FLAG     = 0x0010, ///< Time the passes as they execute +        TIME_ACTIONS_FLAG    = 0x0020, ///< Time the actions as they execute +        SHOW_STATS_FLAG      = 0x0040, ///< Show pass statistics +        EMIT_NATIVE_FLAG     = 0x0080, ///< Emit native code instead of bc +        EMIT_RAW_FLAG        = 0x0100, ///< Emit raw, unoptimized bytecode +        KEEP_TEMPS_FLAG      = 0x0200, ///< Don't delete temporary files +        DRIVER_FLAGS_MASK    = 0x02FF, ///< Union of the above flags +      }; +        /// This type is the input list to the CompilerDriver. It provides -      /// a vector of filename/filetype pairs. The filetype is used to look up +      /// a vector of pathname/filetype pairs. The filetype is used to look up        /// the configuration of the actions to be taken by the driver.        /// @brief The Input Data to the execute method -      typedef std::vector<std::pair<std::string,std::string> > InputList; +      typedef std::vector<std::pair<sys::Path,std::string> > InputList;        /// This type is read from configuration files or otherwise provided to        /// the CompilerDriver through a "ConfigDataProvider". It serves as both @@ -78,7 +96,7 @@ namespace llvm {        /// language.        struct Action {          Action() : flags(0) {} -        std::string program;   ///< The program to execve +        sys::Program program;  ///< The program to execve          StringVector args;     ///< Arguments to the program          unsigned flags;        ///< Action specific flags          void set(unsigned fl ) { flags |= fl; } @@ -107,127 +125,49 @@ namespace llvm {        class ConfigDataProvider {        public:          virtual ConfigData* ProvideConfigData(const std::string& filetype) = 0; -        virtual void setConfigDir(const std::string& dirName) = 0; +        virtual void setConfigDir(const sys::Path& dirName) = 0;        };      /// @}      /// @name Constructors      /// @{      public: -      CompilerDriver(ConfigDataProvider& cdp ); +      /// @brief Static Constructor +      static CompilerDriver* Get(ConfigDataProvider& CDP); + +      /// @brief Virtual destructor        virtual ~CompilerDriver();      /// @}      /// @name Methods      /// @{      public: -      /// @brief Handle an error -      virtual void error(const std::string& errmsg); -        /// @brief Execute the actions requested for the given input list. -      virtual int execute(const InputList& list, const std::string& output); +      virtual int execute(const InputList& list, const sys::Path& output) = 0; -    /// @} -    /// @name Mutators -    /// @{ -    public:        /// @brief Set the final phase at which compilation terminates -      void setFinalPhase( Phases phase ) { finalPhase = phase; } +      virtual void setFinalPhase(Phases phase) = 0;        /// @brief Set the optimization level for the compilation -      void setOptimization( OptimizationLevels level ) { optLevel = level; } - -      /// @brief Prevent the CompilerDriver from taking any actions -      void setDryRun( bool TF ) { isDryRun = TF; } - -      /// @brief Cause the CompilerDriver to print to stderr all the -      /// actions it is taking. -      void setVerbose( bool TF ) { isVerbose = TF; } - -      /// @brief Cause the CompilerDriver to print to stderr very verbose -      /// information that might be useful in debugging the driver's actions -      void setDebug( bool TF ) { isDebug = TF; } - -      /// @brief Cause the CompilerDriver to print to stderr the  -      /// execution time of each action taken. -      void setTimeActions( bool TF ) { timeActions = TF; } - -      /// @brief Cause the CompilerDriver to print timings for each pass. -      void setTimePasses( bool TF ) { timePasses = TF; } +      virtual void setOptimization(OptimizationLevels level) = 0; -      /// @brief Cause the CompilerDriver to show statistics gathered -      void setShowStats( bool TF ) { showStats = TF; } - -      /// @brief Indicate that native code is to be generated instead -      /// of LLVM bytecode. -      void setEmitNativeCode( bool TF ) { emitNativeCode = TF; } - -      /// @brief Indicate that raw, unoptimized code is to be generated. -      void setEmitRawCode(bool TF ) { emitRawCode = TF; } - -      void setKeepTemporaries(bool TF) { keepTemps = TF; } +      /// @brief Set the driver flags. +      virtual void setDriverFlags(unsigned flags) = 0;        /// @brief Set the output machine name. -      void setOutputMachine( const std::string& machineName ) { -        machine = machineName; -      } +      virtual void setOutputMachine(const std::string& machineName) = 0;        /// @brief Set Preprocessor specific options -      void setPhaseArgs(Phases phase, const std::vector<std::string>& opts) { -        assert(phase <= LINKING && phase >= PREPROCESSING); -        AdditionalArgs[phase] = opts; -      } +      virtual void setPhaseArgs(Phases phase, const StringVector& opts) = 0;         /// @brief Set Library Paths -      void setLibraryPaths(const std::vector<std::string>& paths) { -        LibraryPaths = paths; -      } +      virtual void setLibraryPaths(const StringVector& paths) = 0;        /// @brief Set the list of library paths to be searched for        /// libraries. -      void addLibraryPath( const std::string& libPath ) { -        LibraryPaths.push_back(libPath); -      } +      virtual void addLibraryPath( const sys::Path& libPath )  = 0;      /// @} -    /// @name Functions -    /// @{ -    private: -      Action* GetAction(ConfigData* cd, const std::string& input,  -                       const std::string& output, Phases phase ); - -      bool DoAction(Action* a); - -      std::string GetPathForLinkageItem(const std::string& link_item, -                                        const std::string& dir); - -      bool ProcessLinkageItem(const std::string& link_item, -                              SetVector<std::string>& set, -                              std::string& err); - -    /// @} -    /// @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 -      bool isDryRun;                ///< Prevent actions ? -      bool isVerbose;               ///< Print actions? -      bool isDebug;                 ///< Print lotsa debug info? -      bool timeActions;             ///< Time the actions executed ? -      bool timePasses;              ///< Time each pass and print timing ? -      bool showStats;               ///< Show gathered statistics ? -      bool emitRawCode;             ///< Emit Raw (unoptimized) code? -      bool emitNativeCode;          ///< Emit native code instead of bytecode? -      bool keepTemps;               ///< Keep temporary files? -      std::string machine;          ///< Target machine name -      StringVector LibraryPaths;    ///< -L options -      StringTable  AdditionalArgs;  ///< The -Txyz options -      std::string TempDir;          ///< Name of the temporary directory. - -    /// @} -    };  } diff --git a/llvm/tools/llvmc/ConfigLexer.h b/llvm/tools/llvmc/ConfigLexer.h index 1808ac95f4e..bb731d3c6f0 100644 --- a/llvm/tools/llvmc/ConfigLexer.h +++ b/llvm/tools/llvmc/ConfigLexer.h @@ -57,6 +57,7 @@ enum ConfigLexerTokens {    COMMAND,      ///< The name "command" (and variants)    EQUALS,       ///< The equals sign, =    FALSETOK,     ///< A boolean false value (false/no/off) +  FORCE_SUBST,  ///< The substitution item %force%    IN_SUBST,     ///< The substitution item %in%    INTEGER,      ///< An integer     LANG,         ///< The name "lang" (and variants) @@ -85,6 +86,7 @@ enum ConfigLexerTokens {    TRANSLATES,   ///< The name "translates" (and variants)    TRANSLATOR,   ///< The name "translator" (and variants)    TRUETOK,      ///< A boolean true value (true/yes/on) +  VERBOSE_SUBST,///< The substitution item %verbose%    VERSION,      ///< The name "version" (and variants)  }; diff --git a/llvm/tools/llvmc/ConfigLexer.l b/llvm/tools/llvmc/ConfigLexer.l index d9a44c1d228..21f5fe1a0bc 100644 --- a/llvm/tools/llvmc/ConfigLexer.l +++ b/llvm/tools/llvmc/ConfigLexer.l @@ -160,12 +160,14 @@ White           [ \t]*  {LINKER}        { return handleNameContext(LINKER); }  %args%          { return handleSubstitution(ARGS_SUBST); } +%force%         { return handleSubstitution(FORCE_SUBST); }  %in%            { return handleSubstitution(IN_SUBST); } +%opt%           { return handleSubstitution(OPT_SUBST); }  %out%           { return handleSubstitution(OUT_SUBST); } -%time%          { return handleSubstitution(TIME_SUBST); }  %stats%         { return handleSubstitution(STATS_SUBST); } -%opt%           { return handleSubstitution(OPT_SUBST); }  %target%        { return handleSubstitution(TARGET_SUBST); } +%time%          { return handleSubstitution(TIME_SUBST); } +%verbose%       { return handleSubstitution(VERBOSE_SUBST); }  {BadSubst}      { YY_FATAL_ERROR("Invalid substitution token"); }  {Assembly}      { return handleValueContext(ASSEMBLY); } diff --git a/llvm/tools/llvmc/Configuration.cpp b/llvm/tools/llvmc/Configuration.cpp index 4770875833c..a8c6791545e 100644 --- a/llvm/tools/llvmc/Configuration.cpp +++ b/llvm/tools/llvmc/Configuration.cpp @@ -90,19 +90,19 @@ namespace {      InputProvider* provider;      CompilerDriver::ConfigData* confDat; -    int next() {  +    inline int next() {         token = Configlex();        if (DumpTokens)           std::cerr << token << "\n";        return token;      } -    bool next_is_real() {  +    inline bool next_is_real() {         next();        return (token != EOLTOK) && (token != ERRORTOK) && (token != 0);      } -    void eatLineRemnant() { +    inline void eatLineRemnant() {        while (next_is_real()) ;      } @@ -162,6 +162,8 @@ namespace {          case STATS_SUBST:       optList.push_back("%stats%"); break;          case OPT_SUBST:         optList.push_back("%opt%"); break;          case TARGET_SUBST:      optList.push_back("%target%"); break; +        case FORCE_SUBST:       optList.push_back("%force%"); break; +        case VERBOSE_SUBST:     optList.push_back("%verbose%"); break;          default:            return false;        } @@ -229,7 +231,7 @@ namespace {            action.args.clear();          } else {            if (token == STRING || token == OPTION) { -            action.program = ConfigLexerState.StringVal; +            action.program.set_file(ConfigLexerState.StringVal);            } else {              error("Expecting a program name");            } @@ -415,42 +417,46 @@ namespace {  CompilerDriver::ConfigData*  LLVMC_ConfigDataProvider::ReadConfigData(const std::string& ftype) {    CompilerDriver::ConfigData* result = 0; -  std::string dir_name; -  if (configDir.empty()) { +  sys::Path confFile; +  if (configDir.is_empty()) {      // Try the environment variable      const char* conf = getenv("LLVM_CONFIG_DIR");      if (conf) { -      dir_name = conf; -      dir_name += "/"; -      if (!::sys::FileIsReadable(dir_name + ftype)) +      confFile.set_directory(conf); +      confFile.append_file(ftype); +      if (!confFile.readable())          throw "Configuration file for '" + ftype + "' is not available.";      } else {        // Try the user's home directory -      const char* home = getenv("HOME"); -      if (home) { -        dir_name = home; -        dir_name += "/.llvm/etc/"; -        if (!::sys::FileIsReadable(dir_name + ftype)) { -          // Okay, try the LLVM installation directory -          dir_name = LLVM_ETCDIR; -          dir_name += "/"; -          if (!::sys::FileIsReadable(dir_name + ftype)) { -            // Okay, try the "standard" place -            dir_name = "/etc/llvm/"; -            if (!::sys::FileIsReadable(dir_name + ftype)) { -              throw "Configuration file for '" + ftype + "' is not available."; -            } +      confFile = sys::Path::GetUserHomeDirectory(); +      if (!confFile.is_empty()) { +        confFile.append_directory(".llvm"); +        confFile.append_directory("etc"); +        confFile.append_file(ftype); +        if (!confFile.readable()) +          confFile.clear(); +      } +      if (!confFile.is_empty()) { +        // Okay, try the LLVM installation directory +        confFile = sys::Path::GetLLVMConfigDir(); +        confFile.append_file(ftype); +        if (!confFile.readable()) { +          // Okay, try the "standard" place +          confFile = sys::Path::GetLLVMDefaultConfigDir(); +          confFile.append_file(ftype); +          if (!confFile.readable()) { +            throw "Configuration file for '" + ftype + "' is not available.";            }          }        }      }    } else { -    dir_name = configDir + "/"; -    if (!::sys::FileIsReadable(dir_name + ftype)) { +    confFile = configDir; +    confFile.append_file(ftype); +    if (!confFile.readable())        throw "Configuration file for '" + ftype + "' is not available."; -    }    } -  FileInputProvider fip( dir_name + ftype ); +  FileInputProvider fip( confFile.get() );    if (!fip.okay()) {      throw "Configuration file for '" + ftype + "' is not available.";    } @@ -459,13 +465,6 @@ LLVMC_ConfigDataProvider::ReadConfigData(const std::string& ftype) {    return result;  } -LLVMC_ConfigDataProvider::LLVMC_ConfigDataProvider()  -  : Configurations()  -  , configDir()  -{ -  Configurations.clear(); -} -  LLVMC_ConfigDataProvider::~LLVMC_ConfigDataProvider()  {    ConfigDataMap::iterator cIt = Configurations.begin(); @@ -491,7 +490,7 @@ LLVMC_ConfigDataProvider::ProvideConfigData(const std::string& filetype) {      // The configuration data doesn't exist, we have to go read it.      result = ReadConfigData(filetype);      // If we got one, cache it -    if ( result != 0 ) +    if (result != 0)        Configurations.insert(std::make_pair(filetype,result));    }    return result; // Might return 0 diff --git a/llvm/tools/llvmc/Configuration.h b/llvm/tools/llvmc/Configuration.h index 59335aa92f6..2ed565a80ed 100644 --- a/llvm/tools/llvmc/Configuration.h +++ b/llvm/tools/llvmc/Configuration.h @@ -29,7 +29,6 @@ namespace llvm {      /// @name Constructor      /// @{      public: -      LLVMC_ConfigDataProvider();        virtual ~LLVMC_ConfigDataProvider();      /// @name Methods @@ -40,7 +39,9 @@ namespace llvm {          ProvideConfigData(const std::string& filetype);        /// @brief Allow the configuration directory to be set -      virtual void setConfigDir(const std::string& dirName) { configDir = dirName; } +      virtual void setConfigDir(const sys::Path& dirName) {  +        configDir = dirName;  +      }      private:        CompilerDriver::ConfigData* ReadConfigData(const std::string& ftype); @@ -53,7 +54,7 @@ namespace llvm {        typedef hash_map<std::string,CompilerDriver::ConfigData*,            hash<std::string>,std::equal_to<std::string> > ConfigDataMap;        ConfigDataMap Configurations; ///< The cache of configurations -      std::string configDir; +      sys::Path configDir;      /// @}    };  } diff --git a/llvm/tools/llvmc/Makefile b/llvm/tools/llvmc/Makefile index 6cbe4fa2efb..71f04292736 100644 --- a/llvm/tools/llvmc/Makefile +++ b/llvm/tools/llvmc/Makefile @@ -8,7 +8,7 @@  ##===----------------------------------------------------------------------===##  LEVEL = ../..  TOOLNAME = llvmc -USEDLIBS = bcreader vmcore support.a +USEDLIBS = bcreader vmcore support.a LLVMsystem.a  CONFIG_FILES = st ll  include $(LEVEL)/Makefile.common diff --git a/llvm/tools/llvmc/llvmc.cpp b/llvm/tools/llvmc/llvmc.cpp index 8c5102a0c4a..ad0d2187aae 100644 --- a/llvm/tools/llvmc/llvmc.cpp +++ b/llvm/tools/llvmc/llvmc.cpp @@ -108,6 +108,9 @@ cl::list<std::string> Libraries("l", cl::Prefix,  cl::opt<std::string> OutputFilename("o",     cl::desc("Override output filename"), cl::value_desc("filename")); +cl::opt<bool> ForceOutput("f", cl::Optional, cl::init(false), +  cl::desc("Force output files to be overridden")); +  cl::opt<std::string> OutputMachine("m", cl::Prefix,    cl::desc("Specify a target machine"), cl::value_desc("machine")); @@ -156,7 +159,7 @@ static cl::opt<bool> EmitRawCode("emit-raw-code", cl::Hidden, cl::Optional,  static cl::opt<bool> PipeCommands("pipe", cl::Optional,    cl::desc("Invoke sub-commands by linking input/output with pipes")); -static cl::opt<bool> KeepTemporaries("keep-temps", cl::Optional, +static cl::opt<bool> KeepTemps("keep-temps", cl::Optional,    cl::desc("Don't delete the temporary files created during compilation"));  //===------------------------------------------------------------------------=== @@ -199,15 +202,16 @@ const std::string GetFileType(const std::string& fname, unsigned pos ) {  /// @brief The main program for llvmc  int main(int argc, char **argv) { +  // Make sure we print stack trace if we get bad signals +  sys::PrintStackTraceOnErrorSignal(); +    try { -    // Make sure we print stack trace if we get bad signals -    PrintStackTraceOnErrorSignal();      // Parse the command line options      cl::ParseCommandLineOptions(argc, argv,  -      " LLVM Compilation Driver (llvmc)\n\n" +      " LLVM Compiler Driver (llvmc)\n\n"        "  This program provides easy invocation of the LLVM tool set\n" -      "  and source language compiler tools.\n" +      "  and other compiler tools.\n"      );      // Deal with unimplemented options. @@ -220,13 +224,12 @@ int main(int argc, char **argv) {        else          throw "An output file must be specified. Please use the -o option"; -      // Construct the ConfigDataProvider object      LLVMC_ConfigDataProvider Provider; -    Provider.setConfigDir(ConfigDir); +    Provider.setConfigDir(sys::Path(ConfigDir));      // Construct the CompilerDriver object -    CompilerDriver CD(Provider); +    CompilerDriver* CD = CompilerDriver::Get(Provider);      // If the LLVM_LIB_SEARCH_PATH environment variable is      // set, append it to the list of places to search for libraries @@ -234,30 +237,37 @@ int main(int argc, char **argv) {      if (!srchPath.empty())        LibPaths.push_back(srchPath); -    // Configure the driver based on options -    CD.setVerbose(Verbose); -    CD.setDebug(Debug); -    CD.setDryRun(DryRun); -    CD.setFinalPhase(FinalPhase); -    CD.setOptimization(OptLevel); -    CD.setOutputMachine(OutputMachine); -    CD.setEmitNativeCode(Native); -    CD.setEmitRawCode(EmitRawCode); -    CD.setTimeActions(TimeActions); -    CD.setTimePasses(TimePassesIsEnabled); -    CD.setShowStats(ShowStats); -    CD.setKeepTemporaries(KeepTemporaries); -    CD.setLibraryPaths(LibPaths); +    // Set the driver flags based on command line options +    unsigned flags = 0; +    if (Verbose)        flags |= CompilerDriver::VERBOSE_FLAG; +    if (Debug)          flags |= CompilerDriver::DEBUG_FLAG; +    if (DryRun)         flags |= CompilerDriver::DRY_RUN_FLAG; +    if (ForceOutput)    flags |= CompilerDriver::FORCE_FLAG; +    if (Native)         flags |= CompilerDriver::EMIT_NATIVE_FLAG; +    if (EmitRawCode)    flags |= CompilerDriver::EMIT_RAW_FLAG; +    if (KeepTemps)      flags |= CompilerDriver::KEEP_TEMPS_FLAG; +    if (ShowStats)      flags |= CompilerDriver::SHOW_STATS_FLAG; +    if (TimeActions)    flags |= CompilerDriver::TIME_ACTIONS_FLAG; +    if (TimePassesIsEnabled) flags |= CompilerDriver::TIME_PASSES_FLAG; +    CD->setDriverFlags(flags); + +    // Specify requred parameters +    CD->setFinalPhase(FinalPhase); +    CD->setOptimization(OptLevel); +    CD->setOutputMachine(OutputMachine); +    CD->setLibraryPaths(LibPaths); + +    // Provide additional tool arguments      if (!PreprocessorToolOpts.empty()) -        CD.setPhaseArgs(CompilerDriver::PREPROCESSING, PreprocessorToolOpts); +        CD->setPhaseArgs(CompilerDriver::PREPROCESSING, PreprocessorToolOpts);      if (!TranslatorToolOpts.empty()) -        CD.setPhaseArgs(CompilerDriver::TRANSLATION, TranslatorToolOpts); +        CD->setPhaseArgs(CompilerDriver::TRANSLATION, TranslatorToolOpts);      if (!OptimizerToolOpts.empty()) -        CD.setPhaseArgs(CompilerDriver::OPTIMIZATION, OptimizerToolOpts); +        CD->setPhaseArgs(CompilerDriver::OPTIMIZATION, OptimizerToolOpts);      if (!AssemblerToolOpts.empty()) -        CD.setPhaseArgs(CompilerDriver::ASSEMBLY,AssemblerToolOpts); +        CD->setPhaseArgs(CompilerDriver::ASSEMBLY,AssemblerToolOpts);      if (!LinkerToolOpts.empty()) -        CD.setPhaseArgs(CompilerDriver::LINKING, LinkerToolOpts); +        CD->setPhaseArgs(CompilerDriver::LINKING, LinkerToolOpts);      // Prepare the list of files to be compiled by the CompilerDriver.      CompilerDriver::InputList InpList; @@ -288,7 +298,7 @@ int main(int argc, char **argv) {      }      // Tell the driver to do its thing -    int result = CD.execute(InpList,OutputFilename); +    int result = CD->execute(InpList,sys::Path(OutputFilename));      if (result != 0) {        throw "Error executing actions. Terminated.\n";        return result; diff --git a/llvm/tools/llvmc/st b/llvm/tools/llvmc/st index c08c8d1c7c2..9cedc3d068a 100644 --- a/llvm/tools/llvmc/st +++ b/llvm/tools/llvmc/st @@ -34,7 +34,7 @@    # To compile stacker source, we just run the stacker    # compiler with a default stack size of 2048 entries.    translator.command=stkrc -s 2048 %in% -o %out% %time% \ -    %stats% %args% +    %stats% %force% %args%    # stkrc doesn't preprocess but we set this to true so    # that we don't run the cp command by default. @@ -52,7 +52,7 @@    # For optimization, we use the LLVM "opt" program    optimizer.command=opt %in% -o %out% %opt% %time% %stats% \ -    %args% +    %force% %args%    optimizer.required = true  | 

