Index: llvm/lib/Transforms/IPO/HotColdSplitting.cpp =================================================================== --- llvm/lib/Transforms/IPO/HotColdSplitting.cpp +++ llvm/lib/Transforms/IPO/HotColdSplitting.cpp @@ -84,6 +84,9 @@ cl::desc("Base penalty for splitting cold code (as a " "multiple of TCC_Basic)")); +static cl::opt EnableRandomOutlining("hot-cold-randomly-outline-cold-code", + cl::init(false), cl::Hidden); + namespace { /// A sequence of basic blocks. @@ -106,6 +109,20 @@ return !(isa(I) || isa(I)); } +static Optional> +hasSingleSuccAndPred(const BasicBlock &BB) { + auto FirstSucc = succ_begin(&BB); + auto SuccEnd = succ_end(&BB); + if (FirstSucc == SuccEnd || ++FirstSucc != SuccEnd) + return None; + auto FirstPred = pred_begin(&BB); + auto PredEnd = pred_end(&BB); + if (FirstPred == PredEnd || ++FirstPred != PredEnd) + return None; + return Optional>( + {*succ_begin(&BB), *pred_begin(&BB)}); +} + bool unlikelyExecuted(BasicBlock &BB) { // Exception handling blocks are unlikely executed. if (BB.isEHPad() || isa(BB.getTerminator())) @@ -128,7 +145,30 @@ return true; } - return false; + if (!EnableRandomOutlining) + return false; + + // Game of chance hypothesis: when most (80:20 rule) of the code is cold, + // a randomly selected basic block has a higher chance of being cold. Do this + // if the basic block is part of a diamond structure (if-else). + // NB: This causes non-deterministic outlining. + if (auto SuccPred = hasSingleSuccAndPred(BB)) { + auto Succ = SuccPred->first; + int SuccPredCount = 0; + for (auto X : predecessors(Succ)) + ++SuccPredCount; + if (SuccPredCount < 2) + return false; + auto Pred = SuccPred->second; + int PredSuccCount = 0; + for (auto X : successors(Pred)) + ++PredSuccCount; + if (PredSuccCount < 2) + return false; + double Chance = (std::rand() % PredSuccCount) / double(PredSuccCount); + // Threshold can be decreased to enable aggressive outlining. + return (Chance < 0.5); + } } /// Check whether it's safe to outline \p BB.