Index: include/clang/Driver/Compilation.h =================================================================== --- include/clang/Driver/Compilation.h +++ include/clang/Driver/Compilation.h @@ -14,6 +14,7 @@ #include "clang/Driver/Util.h" #include "llvm/ADT/DenseMap.h" #include "llvm/Support/Path.h" +#include "llvm/Analysis/DecisionTree.h" namespace llvm { namespace opt { @@ -69,6 +70,8 @@ /// Redirection for stdout, stderr, etc. const StringRef **Redirects; + llvm::ModuleDecisionTrees *moduleDecisionTrees; + /// Whether we're compiling for diagnostic purposes. bool ForDiagnostics; @@ -107,6 +110,10 @@ /// Returns the sysroot path. StringRef getSysRoot() const; + llvm::ModuleDecisionTrees *getModuleDecisionTrees() const { return moduleDecisionTrees; } + + void setModuleDecisionTrees(llvm::ModuleDecisionTrees *x) { moduleDecisionTrees = x; } + /// getArgsForToolChain - Return the derived argument list for the /// tool chain \p TC (or the default tool chain, if TC is not specified). /// Index: include/clang/Driver/Driver.h =================================================================== --- include/clang/Driver/Driver.h +++ include/clang/Driver/Driver.h @@ -18,6 +18,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" +#include "llvm/Analysis/DecisionTree.h" #include "llvm/Support/Path.h" // FIXME: Kill when CompilationInfo #include // lands. @@ -153,6 +154,9 @@ /// Whether the driver is generating diagnostics for debugging purposes. unsigned CCGenDiagnostics : 1; + /// Module decision trees for iterative compilation. + llvm::ModuleDecisionTrees *moduleDecisionTrees; + private: /// Name to use when invoking gcc/g++. std::string CCCGenericGCCName; @@ -199,6 +203,9 @@ /// @name Accessors /// @{ + llvm::ModuleDecisionTrees *getModuleDecisionTrees() const { return moduleDecisionTrees; } + void setModuleDecisionTrees(llvm::ModuleDecisionTrees *x) { moduleDecisionTrees = x; } + /// Name to use when invoking gcc/g++. const std::string &getCCCGenericGCCName() const { return CCCGenericGCCName; } Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -482,6 +482,8 @@ HelpText<"Emit all declarations, even if unused">; def fencoding_EQ : Joined<["-"], "fencoding=">, Group; def ferror_limit_EQ : Joined<["-"], "ferror-limit=">, Group, Flags<[CoreOption]>; +def fiterative_comp_EQ : Joined<["-"], "fiterative-comp=">, Group, + HelpText<"Number of iterations for iterative compilation">; def fexceptions : Flag<["-"], "fexceptions">, Group, Flags<[CC1Option]>, HelpText<"Enable support for exception handling">; def fexcess_precision_EQ : Joined<["-"], "fexcess-precision=">, Index: lib/CodeGen/BackendUtil.cpp =================================================================== --- lib/CodeGen/BackendUtil.cpp +++ lib/CodeGen/BackendUtil.cpp @@ -39,6 +39,7 @@ #include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/ObjCARC.h" #include "llvm/Transforms/Scalar.h" +#include "llvm/Analysis/Passes.h" #include using namespace clang; using namespace llvm; @@ -198,6 +199,7 @@ if (Builder.OptLevel > 0) { PM.add(createEarlyCSEPass()); PM.add(createReassociatePass()); + PM.add(createICSetCurrentFuncPass()); PM.add(createLICMPass()); PM.add(createGVNPass()); PM.add(createInstructionCombiningPass()); Index: lib/Driver/Driver.cpp =================================================================== --- lib/Driver/Driver.cpp +++ lib/Driver/Driver.cpp @@ -55,8 +55,8 @@ CCPrintOptionsFilename(nullptr), CCPrintHeadersFilename(nullptr), CCLogDiagnosticsFilename(nullptr), CCCPrintBindings(false), - CCPrintHeaders(false), CCLogDiagnostics(false), - CCGenDiagnostics(false), CCCGenericGCCName(""), CheckInputsExist(true), + CCGenDiagnostics(false), moduleDecisionTrees(0), + CCCGenericGCCName(""), CheckInputsExist(true), CCCUsePCH(true), SuppressMissingInputWarning(false) { Name = llvm::sys::path::stem(ClangExecutable); @@ -373,6 +373,8 @@ // The compilation takes ownership of Args. Compilation *C = new Compilation(*this, TC, Args, TranslatedArgs); + C->setModuleDecisionTrees(moduleDecisionTrees); + if (!HandleImmediateArgs(*C)) return C; Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -38,6 +38,8 @@ #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Analysis/DecisionTree.h" +#include using namespace clang::driver; using namespace clang::driver::tools; @@ -3534,6 +3536,30 @@ CmdArgs.push_back(A->getValue()); else CmdArgs.push_back("19"); + if (Arg *A = Args.getLastArg(options::OPT_fiterative_comp_EQ)) { + std::string Val = A->getValue(); + int IterNo; + std::stringstream Convert(Val); + Convert >> IterNo; + if (IterNo > 1) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-fiterative-comp"); + CmdArgs.push_back("-mllvm"); + llvm::ModuleDecisionTrees *ModDecisionTrees = + C.getModuleDecisionTrees(); + std::string &OptIF = ModDecisionTrees->getICInputFileOpt(); + OptIF = "-fic-input-file=" + ModDecisionTrees->getICInputFile(); + CmdArgs.push_back(OptIF.c_str()); + CmdArgs.push_back("-mllvm"); + std::string &OptRF = ModDecisionTrees->getICResultsFileOpt(); + OptRF = "-fic-results-file=" + ModDecisionTrees->getICResultsFile(); + CmdArgs.push_back(OptRF.c_str()); + CmdArgs.push_back("-mllvm"); + std::string &OptRF2 = ModDecisionTrees->getICResultsFile2Opt(); + OptRF2 = "-fic-results2-file=" + ModDecisionTrees->getICResultsFile2(); + CmdArgs.push_back(OptRF2.c_str()); + } + } if (Arg *A = Args.getLastArg(options::OPT_fmacro_backtrace_limit_EQ)) { CmdArgs.push_back("-fmacro-backtrace-limit"); Index: tools/driver/driver.cpp =================================================================== --- tools/driver/driver.cpp +++ tools/driver/driver.cpp @@ -47,6 +47,10 @@ #include "llvm/Support/raw_ostream.h" #include #include +#include "llvm/Analysis/DecisionTree.h" +#include "llvm/Support/Program.h" +#include +#include using namespace clang; using namespace clang::driver; using namespace llvm::opt; @@ -443,6 +447,33 @@ DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient); ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false); + // Get number of iterations for iterative compilation. + int ICNumberOfIterations = 0; + std::string ICInputFile; + std::string ICResultsFile; + std::string ICResultsFile2; + + std::unique_ptr CCopts(createDriverOptTable()); + unsigned MissingArgIndex, MissingArgCount; + std::unique_ptr Args(CCopts->ParseArgs(argv.begin()+1, argv.end(), + MissingArgIndex, MissingArgCount)); + if (Args->getLastArg(options::OPT_fiterative_comp_EQ)) { + std::string Val = Args->getLastArgValue(options::OPT_fiterative_comp_EQ, "1"); + std::stringstream Convert(Val); + Convert >> ICNumberOfIterations; + } + if (!ICNumberOfIterations) + ICNumberOfIterations = 1; // Default value is 1. + + llvm::ModuleDecisionTrees moduleDecisionTrees; + + int CurrentIteration = 0; + int Res = 0; + + llvm::FnNameAndPhase::IterativeCompilationPhase ICPhase = + llvm::FnNameAndPhase::ModulePhase; + + for (; CurrentIteration < ICNumberOfIterations; CurrentIteration++) { Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags); SetInstallDir(argv, TheDriver); @@ -451,12 +482,107 @@ SetBackdoorDriverOutputsFromEnvVars(TheDriver); + if (ICNumberOfIterations > 1) { + std::string ErrMsg; + SmallString<128> InputPath; + if (llvm::sys::fs::createTemporaryFile("ic-input", ".json", InputPath)) { + llvm::errs() << "Error creating temporary file: " << ErrMsg << "\n"; + ICNumberOfIterations = 1; + } + ICInputFile = InputPath.c_str(); + + SmallString<128> ResPath; + if (llvm::sys::fs::createTemporaryFile("ic-results", ".json", ResPath)) { + llvm::errs() << "Error creating temporary file: " << ErrMsg << "\n"; + ICNumberOfIterations = 1; + } + ICResultsFile = ResPath.c_str(); + + SmallString<128> ResPath1; + if (llvm::sys::fs::createTemporaryFile("ic-results2", ".json", ResPath1)) { + llvm::errs() << "Error creating temporary file: " << ErrMsg << "\n"; + ICNumberOfIterations = 1; + } + ICResultsFile2 = ResPath1.c_str(); + + moduleDecisionTrees.getICInputFile() = ICInputFile; + moduleDecisionTrees.getICResultsFile() = ICResultsFile; + moduleDecisionTrees.getICResultsFile2() = ICResultsFile2; + TheDriver.setModuleDecisionTrees(&moduleDecisionTrees); + + std::map paths; + moduleDecisionTrees.getPaths(paths); + moduleDecisionTrees.startNewIteration(); + std::string pathsStr = + llvm::ModuleDecisionTrees::generateMdtPathsString(paths); + llvm::DecisionTree::writeToFile(ICInputFile, pathsStr); + } + std::unique_ptr C(TheDriver.BuildCompilation(argv)); - int Res = 0; SmallVector, 4> FailingCommands; if (C.get()) Res = TheDriver.ExecuteCompilation(*C, FailingCommands); + if (ICNumberOfIterations > 1) { + std::string ResultsStrJson = llvm::DecisionTree::readFromFile(ICResultsFile); + std::vector ResultsJson; + std::string ErrorMsg; + if (!llvm::ModuleDecisionTrees::parseMdtResults(ResultsJson, + ResultsStrJson, ErrorMsg)) { + llvm::errs() << "ITERATIVE COMPILATION ERROR:" << ErrorMsg << "\n"; + return 1; + } + + std::string ResultsStr2Json = llvm::DecisionTree::readFromFile(ICResultsFile2); + std::vector Results2Json; + if (!llvm::ModuleDecisionTrees::parseMdtResults(Results2Json, + ResultsStr2Json, ErrorMsg)) { + llvm::errs() << "ITERATIVE COMPILATION ERROR:" << ErrorMsg << "\n"; + return 1; + } + + llvm::sys::fs::remove(ICInputFile); + llvm::sys::fs::remove(ICResultsFile); + llvm::sys::fs::remove(ICResultsFile2); + + std::vector MergerdResults; + for (const auto &res : Results2Json) { + if (res.FunctionNameAndPhase.getName() != "module-id") + MergerdResults.push_back(res); + } + MergerdResults.insert(MergerdResults.end(), ResultsJson.begin(), ResultsJson.end()); + + // Calculate the new decision three paths. + if (ICPhase == llvm::FnNameAndPhase::ModulePhase) { + int TotalFittness = + llvm::ModuleDecisionTrees::calculateTotalFitness(MergerdResults); + std::string ModuleNameId = "module-id"; + + llvm::MdtResults *ModuleResults = 0; + for (unsigned i = 0; i < MergerdResults.size(); i++) { + llvm::MdtResults &res = MergerdResults[i]; + if (res.FunctionNameAndPhase.getName() == ModuleNameId) + ModuleResults = &res; + } + + llvm::DecisionTree &dt = + moduleDecisionTrees.getDecisionTree( + llvm::FnNameAndPhase(ModuleNameId, + llvm::FnNameAndPhase::ModulePhase)); + if (ModuleResults) + dt.applyResults(*ModuleResults); + dt.setFunctionFitness(TotalFittness); + dt.updateBestFunctionFitness(CurrentIteration); + + bool FinalIteration = false; + if (CurrentIteration >= ICNumberOfIterations - 2) + FinalIteration = true; + bool finished = dt.selectPath(FinalIteration); + if (finished && CurrentIteration < (ICNumberOfIterations - 2)) + CurrentIteration = ICNumberOfIterations - 2; + } + } + // Force a crash to test the diagnostics. if (::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH")) { Diags.Report(diag::err_drv_force_crash) << "FORCE_CLANG_DIAGNOSTICS_CRASH"; @@ -487,7 +613,7 @@ // If any timers were active but haven't been destroyed yet, print their // results now. This happens in -disable-free mode. llvm::TimerGroup::printAll(llvm::errs()); - + } // iterative compiler llvm::llvm_shutdown(); #ifdef LLVM_ON_WIN32