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. @@ -157,6 +158,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; @@ -209,6 +213,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 @@ -515,6 +515,8 @@ def fno_emulated_tls : Flag<["-"], "fno-emulated-tls">, Group; 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 @@ -40,6 +40,7 @@ #include "llvm/Transforms/ObjCARC.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils/SymbolRewriter.h" +#include "llvm/Analysis/Passes.h" #include using namespace clang; using namespace llvm; @@ -224,6 +225,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,7 +55,8 @@ CCPrintHeadersFilename(nullptr), CCLogDiagnosticsFilename(nullptr), CCCPrintBindings(false), CCPrintHeaders(false), CCLogDiagnostics(false), CCGenDiagnostics(false), CCCGenericGCCName(""), CheckInputsExist(true), - CCCUsePCH(true), SuppressMissingInputWarning(false) { + CCCUsePCH(true), SuppressMissingInputWarning(false), + moduleDecisionTrees(0) { Name = llvm::sys::path::filename(ClangExecutable); Dir = llvm::sys::path::parent_path(ClangExecutable); @@ -453,6 +454,8 @@ // The compilation takes ownership of Args. Compilation *C = new Compilation(*this, TC, UArgs.release(), TranslatedArgs); + C->setModuleDecisionTrees(moduleDecisionTrees); + if (!HandleImmediateArgs(*C)) return C; Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -41,6 +41,8 @@ #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Analysis/DecisionTree.h" +#include #ifdef LLVM_ON_UNIX #include // For getuid(). @@ -3996,6 +3998,34 @@ 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"); + llvm::ModuleDecisionTrees *ModDecisionTrees = + C.getModuleDecisionTrees(); + CmdArgs.push_back("-mllvm"); + std::string &OptIF = ModDecisionTrees->getICInputFileOpt(); + OptIF = "-fic-input-file=" + ModDecisionTrees->getICInputFile(); + CmdArgs.push_back(OptIF.c_str()); + CmdArgs.push_back("-mllvm"); + std::string &OptIF2 = ModDecisionTrees->getICInputFile2Opt(); + OptIF2 = "-fic-input2-file=" + ModDecisionTrees->getICInputFile2(); + CmdArgs.push_back(OptIF2.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 @@ -50,6 +50,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; @@ -470,6 +474,35 @@ Diags.takeClient(), std::move(SerializedConsumer))); } + // Get number of iterations for iterative compilation. + int ICNumberOfIterations = 0; + std::string ICInputFile; + std::string ICInputFile2; + std::string ICResultsFile; + std::string ICResultsFile2; + + std::unique_ptr CCopts(createDriverOptTable()); + unsigned MissingArgIndex, MissingArgCount; + ArrayRef argv_ref(argv); + InputArgList Args = CCopts->ParseArgs(argv_ref.slice(1), + 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::ICPhase CurrICPhase = llvm::FnNameAndPhase::ModulePhase; + + for (; CurrentIteration < ICNumberOfIterations; CurrentIteration++) { + ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false); Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags); @@ -480,12 +513,138 @@ SetBackdoorDriverOutputsFromEnvVars(TheDriver); + std::stringstream filename; + + if (ICNumberOfIterations > 1) { + std::string ErrMsg; + SmallString<128> InputPath; + filename << "ic-input-" << CurrentIteration; + if (llvm::sys::fs::createTemporaryFile(filename.str(), ".json", InputPath)) { + llvm::errs() << "Error creating temporary file: " << ErrMsg << "\n"; + ICNumberOfIterations = 1; + } + ICInputFile = InputPath.c_str(); + + SmallString<128> InputPath2; + + filename.str(""); + filename << "ic-input2-" << CurrentIteration; + if (llvm::sys::fs::createTemporaryFile(filename.str(), ".json", InputPath2)) { + llvm::errs() << "Error creating temporary file: " << ErrMsg << "\n"; + ICNumberOfIterations = 1; + } + ICInputFile2 = InputPath2.c_str(); + + SmallString<128> ResPath; + filename.str(""); + filename << "ic-results-" << CurrentIteration; + if (llvm::sys::fs::createTemporaryFile(filename.str(), ".json", ResPath)) { + llvm::errs() << "Error creating temporary file: " << ErrMsg << "\n"; + ICNumberOfIterations = 1; + } + ICResultsFile = ResPath.c_str(); + + SmallString<128> ResPath2; + filename.str(""); + filename << "ic-results2-" << CurrentIteration; + if (llvm::sys::fs::createTemporaryFile(filename.str(), ".json", ResPath2)) { + llvm::errs() << "Error creating temporary file: " << ErrMsg << "\n"; + ICNumberOfIterations = 1; + } + ICResultsFile2 = ResPath2.c_str(); + + moduleDecisionTrees.getICInputFile() = ICInputFile; + moduleDecisionTrees.getICInputFile2() = ICInputFile2; + moduleDecisionTrees.getICResultsFile() = ICResultsFile; + moduleDecisionTrees.getICResultsFile2() = ICResultsFile2; + TheDriver.setModuleDecisionTrees(&moduleDecisionTrees); + + std::map paths; + std::map paths1; + std::map paths2; + moduleDecisionTrees.getPaths(paths); + moduleDecisionTrees.startNewIteration(); + moduleDecisionTrees.splitPaths(paths, paths1, paths2); + std::string pathsStr = + llvm::ModuleDecisionTrees::generateMdtPathsString(paths1); + llvm::DecisionTree::writeToFile(ICInputFile, pathsStr); + std::string pathsStr2 = + llvm::ModuleDecisionTrees::generateMdtPathsString(paths2); + llvm::DecisionTree::writeToFile(ICInputFile2, pathsStr2); + } + 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(ICInputFile2); + llvm::sys::fs::remove(ICResultsFile); + llvm::sys::fs::remove(ICResultsFile2); + + std::vector MergerdResults; + llvm::ModuleDecisionTrees::mergeMdtResults(MergerdResults, + ResultsJson, Results2Json); + + std::string mergedResultsStr = llvm::ModuleDecisionTrees::generateMdtResultsString( + MergerdResults); + + // Calculate the new decision three paths. + if (CurrICPhase == 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; + + dt.dumpToJSON(CurrentIteration); + } + } + // Force a crash to test the diagnostics. if (::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH")) { Diags.Report(diag::err_drv_force_crash) << "FORCE_CLANG_DIAGNOSTICS_CRASH"; @@ -522,7 +681,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