xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/Instrumentation/ControlHeightReduction.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- ControlHeightReduction.cpp - Control Height Reduction -------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This pass merges conditional blocks of code and reduces the number of
100b57cec5SDimitry Andric // conditional branches in the hot paths based on profiles.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "llvm/Transforms/Instrumentation/ControlHeightReduction.h"
150b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
160b57cec5SDimitry Andric #include "llvm/ADT/DenseSet.h"
170b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
180b57cec5SDimitry Andric #include "llvm/ADT/StringSet.h"
190b57cec5SDimitry Andric #include "llvm/Analysis/BlockFrequencyInfo.h"
200b57cec5SDimitry Andric #include "llvm/Analysis/GlobalsModRef.h"
210b57cec5SDimitry Andric #include "llvm/Analysis/OptimizationRemarkEmitter.h"
220b57cec5SDimitry Andric #include "llvm/Analysis/ProfileSummaryInfo.h"
230b57cec5SDimitry Andric #include "llvm/Analysis/RegionInfo.h"
240b57cec5SDimitry Andric #include "llvm/Analysis/RegionIterator.h"
250b57cec5SDimitry Andric #include "llvm/Analysis/ValueTracking.h"
260b57cec5SDimitry Andric #include "llvm/IR/CFG.h"
270b57cec5SDimitry Andric #include "llvm/IR/Dominators.h"
280b57cec5SDimitry Andric #include "llvm/IR/IRBuilder.h"
2981ad6265SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
300b57cec5SDimitry Andric #include "llvm/IR/MDBuilder.h"
31*0fca6ea1SDimitry Andric #include "llvm/IR/Module.h"
32fe6060f1SDimitry Andric #include "llvm/IR/PassManager.h"
33bdd1243dSDimitry Andric #include "llvm/IR/ProfDataUtils.h"
340b57cec5SDimitry Andric #include "llvm/Support/BranchProbability.h"
35480093f4SDimitry Andric #include "llvm/Support/CommandLine.h"
360b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
370b57cec5SDimitry Andric #include "llvm/Transforms/Utils.h"
380b57cec5SDimitry Andric #include "llvm/Transforms/Utils/BasicBlockUtils.h"
390b57cec5SDimitry Andric #include "llvm/Transforms/Utils/Cloning.h"
400b57cec5SDimitry Andric #include "llvm/Transforms/Utils/ValueMapper.h"
410b57cec5SDimitry Andric 
42bdd1243dSDimitry Andric #include <optional>
430b57cec5SDimitry Andric #include <set>
440b57cec5SDimitry Andric #include <sstream>
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric using namespace llvm;
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric #define DEBUG_TYPE "chr"
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric #define CHR_DEBUG(X) LLVM_DEBUG(X)
510b57cec5SDimitry Andric 
52bdd1243dSDimitry Andric static cl::opt<bool> DisableCHR("disable-chr", cl::init(false), cl::Hidden,
53bdd1243dSDimitry Andric                                 cl::desc("Disable CHR for all functions"));
54bdd1243dSDimitry Andric 
550b57cec5SDimitry Andric static cl::opt<bool> ForceCHR("force-chr", cl::init(false), cl::Hidden,
560b57cec5SDimitry Andric                               cl::desc("Apply CHR for all functions"));
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric static cl::opt<double> CHRBiasThreshold(
590b57cec5SDimitry Andric     "chr-bias-threshold", cl::init(0.99), cl::Hidden,
600b57cec5SDimitry Andric     cl::desc("CHR considers a branch bias greater than this ratio as biased"));
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric static cl::opt<unsigned> CHRMergeThreshold(
630b57cec5SDimitry Andric     "chr-merge-threshold", cl::init(2), cl::Hidden,
640b57cec5SDimitry Andric     cl::desc("CHR merges a group of N branches/selects where N >= this value"));
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric static cl::opt<std::string> CHRModuleList(
670b57cec5SDimitry Andric     "chr-module-list", cl::init(""), cl::Hidden,
680b57cec5SDimitry Andric     cl::desc("Specify file to retrieve the list of modules to apply CHR to"));
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric static cl::opt<std::string> CHRFunctionList(
710b57cec5SDimitry Andric     "chr-function-list", cl::init(""), cl::Hidden,
720b57cec5SDimitry Andric     cl::desc("Specify file to retrieve the list of functions to apply CHR to"));
730b57cec5SDimitry Andric 
74bdd1243dSDimitry Andric static cl::opt<unsigned> CHRDupThreshsold(
75bdd1243dSDimitry Andric     "chr-dup-threshold", cl::init(3), cl::Hidden,
76bdd1243dSDimitry Andric     cl::desc("Max number of duplications by CHR for a region"));
77bdd1243dSDimitry Andric 
780b57cec5SDimitry Andric static StringSet<> CHRModules;
790b57cec5SDimitry Andric static StringSet<> CHRFunctions;
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric static void parseCHRFilterFiles() {
820b57cec5SDimitry Andric   if (!CHRModuleList.empty()) {
830b57cec5SDimitry Andric     auto FileOrErr = MemoryBuffer::getFile(CHRModuleList);
840b57cec5SDimitry Andric     if (!FileOrErr) {
850b57cec5SDimitry Andric       errs() << "Error: Couldn't read the chr-module-list file " << CHRModuleList << "\n";
860b57cec5SDimitry Andric       std::exit(1);
870b57cec5SDimitry Andric     }
880b57cec5SDimitry Andric     StringRef Buf = FileOrErr->get()->getBuffer();
890b57cec5SDimitry Andric     SmallVector<StringRef, 0> Lines;
900b57cec5SDimitry Andric     Buf.split(Lines, '\n');
910b57cec5SDimitry Andric     for (StringRef Line : Lines) {
920b57cec5SDimitry Andric       Line = Line.trim();
930b57cec5SDimitry Andric       if (!Line.empty())
940b57cec5SDimitry Andric         CHRModules.insert(Line);
950b57cec5SDimitry Andric     }
960b57cec5SDimitry Andric   }
970b57cec5SDimitry Andric   if (!CHRFunctionList.empty()) {
980b57cec5SDimitry Andric     auto FileOrErr = MemoryBuffer::getFile(CHRFunctionList);
990b57cec5SDimitry Andric     if (!FileOrErr) {
1000b57cec5SDimitry Andric       errs() << "Error: Couldn't read the chr-function-list file " << CHRFunctionList << "\n";
1010b57cec5SDimitry Andric       std::exit(1);
1020b57cec5SDimitry Andric     }
1030b57cec5SDimitry Andric     StringRef Buf = FileOrErr->get()->getBuffer();
1040b57cec5SDimitry Andric     SmallVector<StringRef, 0> Lines;
1050b57cec5SDimitry Andric     Buf.split(Lines, '\n');
1060b57cec5SDimitry Andric     for (StringRef Line : Lines) {
1070b57cec5SDimitry Andric       Line = Line.trim();
1080b57cec5SDimitry Andric       if (!Line.empty())
1090b57cec5SDimitry Andric         CHRFunctions.insert(Line);
1100b57cec5SDimitry Andric     }
1110b57cec5SDimitry Andric   }
1120b57cec5SDimitry Andric }
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric namespace {
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric struct CHRStats {
11781ad6265SDimitry Andric   CHRStats() = default;
1180b57cec5SDimitry Andric   void print(raw_ostream &OS) const {
1190b57cec5SDimitry Andric     OS << "CHRStats: NumBranches " << NumBranches
1200b57cec5SDimitry Andric        << " NumBranchesDelta " << NumBranchesDelta
1210b57cec5SDimitry Andric        << " WeightedNumBranchesDelta " << WeightedNumBranchesDelta;
1220b57cec5SDimitry Andric   }
12381ad6265SDimitry Andric   // The original number of conditional branches / selects
12481ad6265SDimitry Andric   uint64_t NumBranches = 0;
12581ad6265SDimitry Andric   // The decrease of the number of conditional branches / selects in the hot
12681ad6265SDimitry Andric   // paths due to CHR.
12781ad6265SDimitry Andric   uint64_t NumBranchesDelta = 0;
12881ad6265SDimitry Andric   // NumBranchesDelta weighted by the profile count at the scope entry.
12981ad6265SDimitry Andric   uint64_t WeightedNumBranchesDelta = 0;
1300b57cec5SDimitry Andric };
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric // RegInfo - some properties of a Region.
1330b57cec5SDimitry Andric struct RegInfo {
13481ad6265SDimitry Andric   RegInfo() = default;
13581ad6265SDimitry Andric   RegInfo(Region *RegionIn) : R(RegionIn) {}
13681ad6265SDimitry Andric   Region *R = nullptr;
13781ad6265SDimitry Andric   bool HasBranch = false;
1380b57cec5SDimitry Andric   SmallVector<SelectInst *, 8> Selects;
1390b57cec5SDimitry Andric };
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric typedef DenseMap<Region *, DenseSet<Instruction *>> HoistStopMapTy;
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric // CHRScope - a sequence of regions to CHR together. It corresponds to a
1440b57cec5SDimitry Andric // sequence of conditional blocks. It can have subscopes which correspond to
1450b57cec5SDimitry Andric // nested conditional blocks. Nested CHRScopes form a tree.
1460b57cec5SDimitry Andric class CHRScope {
1470b57cec5SDimitry Andric  public:
1480b57cec5SDimitry Andric   CHRScope(RegInfo RI) : BranchInsertPoint(nullptr) {
1490b57cec5SDimitry Andric     assert(RI.R && "Null RegionIn");
1500b57cec5SDimitry Andric     RegInfos.push_back(RI);
1510b57cec5SDimitry Andric   }
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric   Region *getParentRegion() {
1540b57cec5SDimitry Andric     assert(RegInfos.size() > 0 && "Empty CHRScope");
1550b57cec5SDimitry Andric     Region *Parent = RegInfos[0].R->getParent();
1560b57cec5SDimitry Andric     assert(Parent && "Unexpected to call this on the top-level region");
1570b57cec5SDimitry Andric     return Parent;
1580b57cec5SDimitry Andric   }
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric   BasicBlock *getEntryBlock() {
1610b57cec5SDimitry Andric     assert(RegInfos.size() > 0 && "Empty CHRScope");
1620b57cec5SDimitry Andric     return RegInfos.front().R->getEntry();
1630b57cec5SDimitry Andric   }
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric   BasicBlock *getExitBlock() {
1660b57cec5SDimitry Andric     assert(RegInfos.size() > 0 && "Empty CHRScope");
1670b57cec5SDimitry Andric     return RegInfos.back().R->getExit();
1680b57cec5SDimitry Andric   }
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric   bool appendable(CHRScope *Next) {
1710b57cec5SDimitry Andric     // The next scope is appendable only if this scope is directly connected to
1720b57cec5SDimitry Andric     // it (which implies it post-dominates this scope) and this scope dominates
1730b57cec5SDimitry Andric     // it (no edge to the next scope outside this scope).
1740b57cec5SDimitry Andric     BasicBlock *NextEntry = Next->getEntryBlock();
1750b57cec5SDimitry Andric     if (getExitBlock() != NextEntry)
1760b57cec5SDimitry Andric       // Not directly connected.
1770b57cec5SDimitry Andric       return false;
1780b57cec5SDimitry Andric     Region *LastRegion = RegInfos.back().R;
1790b57cec5SDimitry Andric     for (BasicBlock *Pred : predecessors(NextEntry))
1800b57cec5SDimitry Andric       if (!LastRegion->contains(Pred))
1810b57cec5SDimitry Andric         // There's an edge going into the entry of the next scope from outside
1820b57cec5SDimitry Andric         // of this scope.
1830b57cec5SDimitry Andric         return false;
1840b57cec5SDimitry Andric     return true;
1850b57cec5SDimitry Andric   }
1860b57cec5SDimitry Andric 
1870b57cec5SDimitry Andric   void append(CHRScope *Next) {
1880b57cec5SDimitry Andric     assert(RegInfos.size() > 0 && "Empty CHRScope");
1890b57cec5SDimitry Andric     assert(Next->RegInfos.size() > 0 && "Empty CHRScope");
1900b57cec5SDimitry Andric     assert(getParentRegion() == Next->getParentRegion() &&
1910b57cec5SDimitry Andric            "Must be siblings");
1920b57cec5SDimitry Andric     assert(getExitBlock() == Next->getEntryBlock() &&
1930b57cec5SDimitry Andric            "Must be adjacent");
1945ffd83dbSDimitry Andric     RegInfos.append(Next->RegInfos.begin(), Next->RegInfos.end());
1955ffd83dbSDimitry Andric     Subs.append(Next->Subs.begin(), Next->Subs.end());
1960b57cec5SDimitry Andric   }
1970b57cec5SDimitry Andric 
1980b57cec5SDimitry Andric   void addSub(CHRScope *SubIn) {
1990b57cec5SDimitry Andric #ifndef NDEBUG
2000b57cec5SDimitry Andric     bool IsChild = false;
2010b57cec5SDimitry Andric     for (RegInfo &RI : RegInfos)
2020b57cec5SDimitry Andric       if (RI.R == SubIn->getParentRegion()) {
2030b57cec5SDimitry Andric         IsChild = true;
2040b57cec5SDimitry Andric         break;
2050b57cec5SDimitry Andric       }
2060b57cec5SDimitry Andric     assert(IsChild && "Must be a child");
2070b57cec5SDimitry Andric #endif
2080b57cec5SDimitry Andric     Subs.push_back(SubIn);
2090b57cec5SDimitry Andric   }
2100b57cec5SDimitry Andric 
2110b57cec5SDimitry Andric   // Split this scope at the boundary region into two, which will belong to the
2120b57cec5SDimitry Andric   // tail and returns the tail.
2130b57cec5SDimitry Andric   CHRScope *split(Region *Boundary) {
2140b57cec5SDimitry Andric     assert(Boundary && "Boundary null");
2150b57cec5SDimitry Andric     assert(RegInfos.begin()->R != Boundary &&
2160b57cec5SDimitry Andric            "Can't be split at beginning");
2175ffd83dbSDimitry Andric     auto BoundaryIt = llvm::find_if(
2185ffd83dbSDimitry Andric         RegInfos, [&Boundary](const RegInfo &RI) { return Boundary == RI.R; });
2190b57cec5SDimitry Andric     if (BoundaryIt == RegInfos.end())
2200b57cec5SDimitry Andric       return nullptr;
2215ffd83dbSDimitry Andric     ArrayRef<RegInfo> TailRegInfos(BoundaryIt, RegInfos.end());
2220b57cec5SDimitry Andric     DenseSet<Region *> TailRegionSet;
2235ffd83dbSDimitry Andric     for (const RegInfo &RI : TailRegInfos)
2240b57cec5SDimitry Andric       TailRegionSet.insert(RI.R);
2255ffd83dbSDimitry Andric 
2265ffd83dbSDimitry Andric     auto TailIt =
2275ffd83dbSDimitry Andric         std::stable_partition(Subs.begin(), Subs.end(), [&](CHRScope *Sub) {
2280b57cec5SDimitry Andric           assert(Sub && "null Sub");
2290b57cec5SDimitry Andric           Region *Parent = Sub->getParentRegion();
2305ffd83dbSDimitry Andric           if (TailRegionSet.count(Parent))
2315ffd83dbSDimitry Andric             return false;
2325ffd83dbSDimitry Andric 
233e8d8bef9SDimitry Andric           assert(llvm::any_of(
234e8d8bef9SDimitry Andric                      RegInfos,
235e8d8bef9SDimitry Andric                      [&Parent](const RegInfo &RI) { return Parent == RI.R; }) &&
2360b57cec5SDimitry Andric                  "Must be in head");
2375ffd83dbSDimitry Andric           return true;
2385ffd83dbSDimitry Andric         });
2395ffd83dbSDimitry Andric     ArrayRef<CHRScope *> TailSubs(TailIt, Subs.end());
2405ffd83dbSDimitry Andric 
2410b57cec5SDimitry Andric     assert(HoistStopMap.empty() && "MapHoistStops must be empty");
2425ffd83dbSDimitry Andric     auto *Scope = new CHRScope(TailRegInfos, TailSubs);
2435ffd83dbSDimitry Andric     RegInfos.erase(BoundaryIt, RegInfos.end());
2445ffd83dbSDimitry Andric     Subs.erase(TailIt, Subs.end());
2455ffd83dbSDimitry Andric     return Scope;
2460b57cec5SDimitry Andric   }
2470b57cec5SDimitry Andric 
2480b57cec5SDimitry Andric   bool contains(Instruction *I) const {
2490b57cec5SDimitry Andric     BasicBlock *Parent = I->getParent();
2500b57cec5SDimitry Andric     for (const RegInfo &RI : RegInfos)
2510b57cec5SDimitry Andric       if (RI.R->contains(Parent))
2520b57cec5SDimitry Andric         return true;
2530b57cec5SDimitry Andric     return false;
2540b57cec5SDimitry Andric   }
2550b57cec5SDimitry Andric 
2560b57cec5SDimitry Andric   void print(raw_ostream &OS) const;
2570b57cec5SDimitry Andric 
2580b57cec5SDimitry Andric   SmallVector<RegInfo, 8> RegInfos; // Regions that belong to this scope
2590b57cec5SDimitry Andric   SmallVector<CHRScope *, 8> Subs;  // Subscopes.
2600b57cec5SDimitry Andric 
2610b57cec5SDimitry Andric   // The instruction at which to insert the CHR conditional branch (and hoist
2620b57cec5SDimitry Andric   // the dependent condition values).
2630b57cec5SDimitry Andric   Instruction *BranchInsertPoint;
2640b57cec5SDimitry Andric 
2650b57cec5SDimitry Andric   // True-biased and false-biased regions (conditional blocks),
2660b57cec5SDimitry Andric   // respectively. Used only for the outermost scope and includes regions in
2670b57cec5SDimitry Andric   // subscopes. The rest are unbiased.
2680b57cec5SDimitry Andric   DenseSet<Region *> TrueBiasedRegions;
2690b57cec5SDimitry Andric   DenseSet<Region *> FalseBiasedRegions;
2700b57cec5SDimitry Andric   // Among the biased regions, the regions that get CHRed.
2710b57cec5SDimitry Andric   SmallVector<RegInfo, 8> CHRRegions;
2720b57cec5SDimitry Andric 
2730b57cec5SDimitry Andric   // True-biased and false-biased selects, respectively. Used only for the
2740b57cec5SDimitry Andric   // outermost scope and includes ones in subscopes.
2750b57cec5SDimitry Andric   DenseSet<SelectInst *> TrueBiasedSelects;
2760b57cec5SDimitry Andric   DenseSet<SelectInst *> FalseBiasedSelects;
2770b57cec5SDimitry Andric 
2780b57cec5SDimitry Andric   // Map from one of the above regions to the instructions to stop
2790b57cec5SDimitry Andric   // hoisting instructions at through use-def chains.
2800b57cec5SDimitry Andric   HoistStopMapTy HoistStopMap;
2810b57cec5SDimitry Andric 
2820b57cec5SDimitry Andric  private:
2835ffd83dbSDimitry Andric    CHRScope(ArrayRef<RegInfo> RegInfosIn, ArrayRef<CHRScope *> SubsIn)
2845ffd83dbSDimitry Andric        : RegInfos(RegInfosIn.begin(), RegInfosIn.end()),
2855ffd83dbSDimitry Andric          Subs(SubsIn.begin(), SubsIn.end()), BranchInsertPoint(nullptr) {}
2860b57cec5SDimitry Andric };
2870b57cec5SDimitry Andric 
2880b57cec5SDimitry Andric class CHR {
2890b57cec5SDimitry Andric  public:
2900b57cec5SDimitry Andric   CHR(Function &Fin, BlockFrequencyInfo &BFIin, DominatorTree &DTin,
2910b57cec5SDimitry Andric       ProfileSummaryInfo &PSIin, RegionInfo &RIin,
2920b57cec5SDimitry Andric       OptimizationRemarkEmitter &OREin)
2930b57cec5SDimitry Andric       : F(Fin), BFI(BFIin), DT(DTin), PSI(PSIin), RI(RIin), ORE(OREin) {}
2940b57cec5SDimitry Andric 
2950b57cec5SDimitry Andric   ~CHR() {
2960b57cec5SDimitry Andric     for (CHRScope *Scope : Scopes) {
2970b57cec5SDimitry Andric       delete Scope;
2980b57cec5SDimitry Andric     }
2990b57cec5SDimitry Andric   }
3000b57cec5SDimitry Andric 
3010b57cec5SDimitry Andric   bool run();
3020b57cec5SDimitry Andric 
3030b57cec5SDimitry Andric  private:
3040b57cec5SDimitry Andric   // See the comments in CHR::run() for the high level flow of the algorithm and
3050b57cec5SDimitry Andric   // what the following functions do.
3060b57cec5SDimitry Andric 
3070b57cec5SDimitry Andric   void findScopes(SmallVectorImpl<CHRScope *> &Output) {
3080b57cec5SDimitry Andric     Region *R = RI.getTopLevelRegion();
3095ffd83dbSDimitry Andric     if (CHRScope *Scope = findScopes(R, nullptr, nullptr, Output)) {
3100b57cec5SDimitry Andric       Output.push_back(Scope);
3110b57cec5SDimitry Andric     }
3120b57cec5SDimitry Andric   }
3130b57cec5SDimitry Andric   CHRScope *findScopes(Region *R, Region *NextRegion, Region *ParentRegion,
3140b57cec5SDimitry Andric                         SmallVectorImpl<CHRScope *> &Scopes);
3150b57cec5SDimitry Andric   CHRScope *findScope(Region *R);
3160b57cec5SDimitry Andric   void checkScopeHoistable(CHRScope *Scope);
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric   void splitScopes(SmallVectorImpl<CHRScope *> &Input,
3190b57cec5SDimitry Andric                    SmallVectorImpl<CHRScope *> &Output);
3200b57cec5SDimitry Andric   SmallVector<CHRScope *, 8> splitScope(CHRScope *Scope,
3210b57cec5SDimitry Andric                                         CHRScope *Outer,
3220b57cec5SDimitry Andric                                         DenseSet<Value *> *OuterConditionValues,
3230b57cec5SDimitry Andric                                         Instruction *OuterInsertPoint,
3240b57cec5SDimitry Andric                                         SmallVectorImpl<CHRScope *> &Output,
3250b57cec5SDimitry Andric                                         DenseSet<Instruction *> &Unhoistables);
3260b57cec5SDimitry Andric 
3270b57cec5SDimitry Andric   void classifyBiasedScopes(SmallVectorImpl<CHRScope *> &Scopes);
3280b57cec5SDimitry Andric   void classifyBiasedScopes(CHRScope *Scope, CHRScope *OutermostScope);
3290b57cec5SDimitry Andric 
3300b57cec5SDimitry Andric   void filterScopes(SmallVectorImpl<CHRScope *> &Input,
3310b57cec5SDimitry Andric                     SmallVectorImpl<CHRScope *> &Output);
3320b57cec5SDimitry Andric 
3330b57cec5SDimitry Andric   void setCHRRegions(SmallVectorImpl<CHRScope *> &Input,
3340b57cec5SDimitry Andric                      SmallVectorImpl<CHRScope *> &Output);
3350b57cec5SDimitry Andric   void setCHRRegions(CHRScope *Scope, CHRScope *OutermostScope);
3360b57cec5SDimitry Andric 
3370b57cec5SDimitry Andric   void sortScopes(SmallVectorImpl<CHRScope *> &Input,
3380b57cec5SDimitry Andric                   SmallVectorImpl<CHRScope *> &Output);
3390b57cec5SDimitry Andric 
3400b57cec5SDimitry Andric   void transformScopes(SmallVectorImpl<CHRScope *> &CHRScopes);
3410b57cec5SDimitry Andric   void transformScopes(CHRScope *Scope, DenseSet<PHINode *> &TrivialPHIs);
3420b57cec5SDimitry Andric   void cloneScopeBlocks(CHRScope *Scope,
3430b57cec5SDimitry Andric                         BasicBlock *PreEntryBlock,
3440b57cec5SDimitry Andric                         BasicBlock *ExitBlock,
3450b57cec5SDimitry Andric                         Region *LastRegion,
3460b57cec5SDimitry Andric                         ValueToValueMapTy &VMap);
3470b57cec5SDimitry Andric   BranchInst *createMergedBranch(BasicBlock *PreEntryBlock,
3480b57cec5SDimitry Andric                                  BasicBlock *EntryBlock,
3490b57cec5SDimitry Andric                                  BasicBlock *NewEntryBlock,
3500b57cec5SDimitry Andric                                  ValueToValueMapTy &VMap);
351bdd1243dSDimitry Andric   void fixupBranchesAndSelects(CHRScope *Scope, BasicBlock *PreEntryBlock,
352bdd1243dSDimitry Andric                                BranchInst *MergedBR, uint64_t ProfileCount);
353bdd1243dSDimitry Andric   void fixupBranch(Region *R, CHRScope *Scope, IRBuilder<> &IRB,
3540b57cec5SDimitry Andric                    Value *&MergedCondition, BranchProbability &CHRBranchBias);
355bdd1243dSDimitry Andric   void fixupSelect(SelectInst *SI, CHRScope *Scope, IRBuilder<> &IRB,
3560b57cec5SDimitry Andric                    Value *&MergedCondition, BranchProbability &CHRBranchBias);
3570b57cec5SDimitry Andric   void addToMergedCondition(bool IsTrueBiased, Value *Cond,
358bdd1243dSDimitry Andric                             Instruction *BranchOrSelect, CHRScope *Scope,
359bdd1243dSDimitry Andric                             IRBuilder<> &IRB, Value *&MergedCondition);
360bdd1243dSDimitry Andric   unsigned getRegionDuplicationCount(const Region *R) {
361bdd1243dSDimitry Andric     unsigned Count = 0;
362bdd1243dSDimitry Andric     // Find out how many times region R is cloned. Note that if the parent
363bdd1243dSDimitry Andric     // of R is cloned, R is also cloned, but R's clone count is not updated
364bdd1243dSDimitry Andric     // from the clone of the parent. We need to accumlate all the counts
365bdd1243dSDimitry Andric     // from the ancestors to get the clone count.
366bdd1243dSDimitry Andric     while (R) {
367bdd1243dSDimitry Andric       Count += DuplicationCount[R];
368bdd1243dSDimitry Andric       R = R->getParent();
369bdd1243dSDimitry Andric     }
370bdd1243dSDimitry Andric     return Count;
371bdd1243dSDimitry Andric   }
3720b57cec5SDimitry Andric 
3730b57cec5SDimitry Andric   Function &F;
3740b57cec5SDimitry Andric   BlockFrequencyInfo &BFI;
3750b57cec5SDimitry Andric   DominatorTree &DT;
3760b57cec5SDimitry Andric   ProfileSummaryInfo &PSI;
3770b57cec5SDimitry Andric   RegionInfo &RI;
3780b57cec5SDimitry Andric   OptimizationRemarkEmitter &ORE;
3790b57cec5SDimitry Andric   CHRStats Stats;
3800b57cec5SDimitry Andric 
3810b57cec5SDimitry Andric   // All the true-biased regions in the function
3820b57cec5SDimitry Andric   DenseSet<Region *> TrueBiasedRegionsGlobal;
3830b57cec5SDimitry Andric   // All the false-biased regions in the function
3840b57cec5SDimitry Andric   DenseSet<Region *> FalseBiasedRegionsGlobal;
3850b57cec5SDimitry Andric   // All the true-biased selects in the function
3860b57cec5SDimitry Andric   DenseSet<SelectInst *> TrueBiasedSelectsGlobal;
3870b57cec5SDimitry Andric   // All the false-biased selects in the function
3880b57cec5SDimitry Andric   DenseSet<SelectInst *> FalseBiasedSelectsGlobal;
3890b57cec5SDimitry Andric   // A map from biased regions to their branch bias
3900b57cec5SDimitry Andric   DenseMap<Region *, BranchProbability> BranchBiasMap;
3910b57cec5SDimitry Andric   // A map from biased selects to their branch bias
3920b57cec5SDimitry Andric   DenseMap<SelectInst *, BranchProbability> SelectBiasMap;
3930b57cec5SDimitry Andric   // All the scopes.
3940b57cec5SDimitry Andric   DenseSet<CHRScope *> Scopes;
395bdd1243dSDimitry Andric   // This maps records how many times this region is cloned.
396bdd1243dSDimitry Andric   DenseMap<const Region *, unsigned> DuplicationCount;
3970b57cec5SDimitry Andric };
3980b57cec5SDimitry Andric 
3990b57cec5SDimitry Andric } // end anonymous namespace
4000b57cec5SDimitry Andric 
4010b57cec5SDimitry Andric static inline
4020b57cec5SDimitry Andric raw_ostream LLVM_ATTRIBUTE_UNUSED &operator<<(raw_ostream &OS,
4030b57cec5SDimitry Andric                                               const CHRStats &Stats) {
4040b57cec5SDimitry Andric   Stats.print(OS);
4050b57cec5SDimitry Andric   return OS;
4060b57cec5SDimitry Andric }
4070b57cec5SDimitry Andric 
4080b57cec5SDimitry Andric static inline
4090b57cec5SDimitry Andric raw_ostream &operator<<(raw_ostream &OS, const CHRScope &Scope) {
4100b57cec5SDimitry Andric   Scope.print(OS);
4110b57cec5SDimitry Andric   return OS;
4120b57cec5SDimitry Andric }
4130b57cec5SDimitry Andric 
4140b57cec5SDimitry Andric static bool shouldApply(Function &F, ProfileSummaryInfo &PSI) {
415bdd1243dSDimitry Andric   if (DisableCHR)
416bdd1243dSDimitry Andric     return false;
417bdd1243dSDimitry Andric 
4180b57cec5SDimitry Andric   if (ForceCHR)
4190b57cec5SDimitry Andric     return true;
4200b57cec5SDimitry Andric 
4210b57cec5SDimitry Andric   if (!CHRModuleList.empty() || !CHRFunctionList.empty()) {
4220b57cec5SDimitry Andric     if (CHRModules.count(F.getParent()->getName()))
4230b57cec5SDimitry Andric       return true;
4240b57cec5SDimitry Andric     return CHRFunctions.count(F.getName());
4250b57cec5SDimitry Andric   }
4260b57cec5SDimitry Andric 
4270b57cec5SDimitry Andric   return PSI.isFunctionEntryHot(&F);
4280b57cec5SDimitry Andric }
4290b57cec5SDimitry Andric 
4300b57cec5SDimitry Andric static void LLVM_ATTRIBUTE_UNUSED dumpIR(Function &F, const char *Label,
4310b57cec5SDimitry Andric                                          CHRStats *Stats) {
4320b57cec5SDimitry Andric   StringRef FuncName = F.getName();
4330b57cec5SDimitry Andric   StringRef ModuleName = F.getParent()->getName();
4340b57cec5SDimitry Andric   (void)(FuncName); // Unused in release build.
4350b57cec5SDimitry Andric   (void)(ModuleName); // Unused in release build.
4360b57cec5SDimitry Andric   CHR_DEBUG(dbgs() << "CHR IR dump " << Label << " " << ModuleName << " "
4370b57cec5SDimitry Andric             << FuncName);
4380b57cec5SDimitry Andric   if (Stats)
4390b57cec5SDimitry Andric     CHR_DEBUG(dbgs() << " " << *Stats);
4400b57cec5SDimitry Andric   CHR_DEBUG(dbgs() << "\n");
4410b57cec5SDimitry Andric   CHR_DEBUG(F.dump());
4420b57cec5SDimitry Andric }
4430b57cec5SDimitry Andric 
4440b57cec5SDimitry Andric void CHRScope::print(raw_ostream &OS) const {
4450b57cec5SDimitry Andric   assert(RegInfos.size() > 0 && "Empty CHRScope");
4460b57cec5SDimitry Andric   OS << "CHRScope[";
4470b57cec5SDimitry Andric   OS << RegInfos.size() << ", Regions[";
4480b57cec5SDimitry Andric   for (const RegInfo &RI : RegInfos) {
4490b57cec5SDimitry Andric     OS << RI.R->getNameStr();
4500b57cec5SDimitry Andric     if (RI.HasBranch)
4510b57cec5SDimitry Andric       OS << " B";
4520b57cec5SDimitry Andric     if (RI.Selects.size() > 0)
4530b57cec5SDimitry Andric       OS << " S" << RI.Selects.size();
4540b57cec5SDimitry Andric     OS << ", ";
4550b57cec5SDimitry Andric   }
4560b57cec5SDimitry Andric   if (RegInfos[0].R->getParent()) {
4570b57cec5SDimitry Andric     OS << "], Parent " << RegInfos[0].R->getParent()->getNameStr();
4580b57cec5SDimitry Andric   } else {
4590b57cec5SDimitry Andric     // top level region
4600b57cec5SDimitry Andric     OS << "]";
4610b57cec5SDimitry Andric   }
4620b57cec5SDimitry Andric   OS << ", Subs[";
4630b57cec5SDimitry Andric   for (CHRScope *Sub : Subs) {
4640b57cec5SDimitry Andric     OS << *Sub << ", ";
4650b57cec5SDimitry Andric   }
4660b57cec5SDimitry Andric   OS << "]]";
4670b57cec5SDimitry Andric }
4680b57cec5SDimitry Andric 
4690b57cec5SDimitry Andric // Return true if the given instruction type can be hoisted by CHR.
4700b57cec5SDimitry Andric static bool isHoistableInstructionType(Instruction *I) {
4710b57cec5SDimitry Andric   return isa<BinaryOperator>(I) || isa<CastInst>(I) || isa<SelectInst>(I) ||
4720b57cec5SDimitry Andric       isa<GetElementPtrInst>(I) || isa<CmpInst>(I) ||
4730b57cec5SDimitry Andric       isa<InsertElementInst>(I) || isa<ExtractElementInst>(I) ||
4740b57cec5SDimitry Andric       isa<ShuffleVectorInst>(I) || isa<ExtractValueInst>(I) ||
4750b57cec5SDimitry Andric       isa<InsertValueInst>(I);
4760b57cec5SDimitry Andric }
4770b57cec5SDimitry Andric 
4780b57cec5SDimitry Andric // Return true if the given instruction can be hoisted by CHR.
4790b57cec5SDimitry Andric static bool isHoistable(Instruction *I, DominatorTree &DT) {
4800b57cec5SDimitry Andric   if (!isHoistableInstructionType(I))
4810b57cec5SDimitry Andric     return false;
482bdd1243dSDimitry Andric   return isSafeToSpeculativelyExecute(I, nullptr, nullptr, &DT);
4830b57cec5SDimitry Andric }
4840b57cec5SDimitry Andric 
4850b57cec5SDimitry Andric // Recursively traverse the use-def chains of the given value and return a set
4860b57cec5SDimitry Andric // of the unhoistable base values defined within the scope (excluding the
4870b57cec5SDimitry Andric // first-region entry block) or the (hoistable or unhoistable) base values that
4880b57cec5SDimitry Andric // are defined outside (including the first-region entry block) of the
4890b57cec5SDimitry Andric // scope. The returned set doesn't include constants.
4905ffd83dbSDimitry Andric static const std::set<Value *> &
4915ffd83dbSDimitry Andric getBaseValues(Value *V, DominatorTree &DT,
4928bcb0991SDimitry Andric               DenseMap<Value *, std::set<Value *>> &Visited) {
4935ffd83dbSDimitry Andric   auto It = Visited.find(V);
4945ffd83dbSDimitry Andric   if (It != Visited.end()) {
4955ffd83dbSDimitry Andric     return It->second;
4968bcb0991SDimitry Andric   }
4970b57cec5SDimitry Andric   std::set<Value *> Result;
4980b57cec5SDimitry Andric   if (auto *I = dyn_cast<Instruction>(V)) {
4995ffd83dbSDimitry Andric     // We don't stop at a block that's not in the Scope because we would miss
5005ffd83dbSDimitry Andric     // some instructions that are based on the same base values if we stop
5015ffd83dbSDimitry Andric     // there.
5020b57cec5SDimitry Andric     if (!isHoistable(I, DT)) {
5030b57cec5SDimitry Andric       Result.insert(I);
5045ffd83dbSDimitry Andric       return Visited.insert(std::make_pair(V, std::move(Result))).first->second;
5050b57cec5SDimitry Andric     }
5060b57cec5SDimitry Andric     // I is hoistable above the Scope.
5070b57cec5SDimitry Andric     for (Value *Op : I->operands()) {
5085ffd83dbSDimitry Andric       const std::set<Value *> &OpResult = getBaseValues(Op, DT, Visited);
5090b57cec5SDimitry Andric       Result.insert(OpResult.begin(), OpResult.end());
5100b57cec5SDimitry Andric     }
5115ffd83dbSDimitry Andric     return Visited.insert(std::make_pair(V, std::move(Result))).first->second;
5120b57cec5SDimitry Andric   }
5130b57cec5SDimitry Andric   if (isa<Argument>(V)) {
5140b57cec5SDimitry Andric     Result.insert(V);
5150b57cec5SDimitry Andric   }
5160b57cec5SDimitry Andric   // We don't include others like constants because those won't lead to any
5170b57cec5SDimitry Andric   // chance of folding of conditions (eg two bit checks merged into one check)
5180b57cec5SDimitry Andric   // after CHR.
5195ffd83dbSDimitry Andric   return Visited.insert(std::make_pair(V, std::move(Result))).first->second;
5200b57cec5SDimitry Andric }
5210b57cec5SDimitry Andric 
5220b57cec5SDimitry Andric // Return true if V is already hoisted or can be hoisted (along with its
5230b57cec5SDimitry Andric // operands) above the insert point. When it returns true and HoistStops is
5240b57cec5SDimitry Andric // non-null, the instructions to stop hoisting at through the use-def chains are
5250b57cec5SDimitry Andric // inserted into HoistStops.
5260b57cec5SDimitry Andric static bool
5270b57cec5SDimitry Andric checkHoistValue(Value *V, Instruction *InsertPoint, DominatorTree &DT,
5280b57cec5SDimitry Andric                 DenseSet<Instruction *> &Unhoistables,
5290b57cec5SDimitry Andric                 DenseSet<Instruction *> *HoistStops,
5300b57cec5SDimitry Andric                 DenseMap<Instruction *, bool> &Visited) {
5310b57cec5SDimitry Andric   assert(InsertPoint && "Null InsertPoint");
5320b57cec5SDimitry Andric   if (auto *I = dyn_cast<Instruction>(V)) {
5335ffd83dbSDimitry Andric     auto It = Visited.find(I);
5345ffd83dbSDimitry Andric     if (It != Visited.end()) {
5355ffd83dbSDimitry Andric       return It->second;
5360b57cec5SDimitry Andric     }
5370b57cec5SDimitry Andric     assert(DT.getNode(I->getParent()) && "DT must contain I's parent block");
5380b57cec5SDimitry Andric     assert(DT.getNode(InsertPoint->getParent()) && "DT must contain Destination");
5390b57cec5SDimitry Andric     if (Unhoistables.count(I)) {
5400b57cec5SDimitry Andric       // Don't hoist if they are not to be hoisted.
5410b57cec5SDimitry Andric       Visited[I] = false;
5420b57cec5SDimitry Andric       return false;
5430b57cec5SDimitry Andric     }
5440b57cec5SDimitry Andric     if (DT.dominates(I, InsertPoint)) {
5450b57cec5SDimitry Andric       // We are already above the insert point. Stop here.
5460b57cec5SDimitry Andric       if (HoistStops)
5470b57cec5SDimitry Andric         HoistStops->insert(I);
5480b57cec5SDimitry Andric       Visited[I] = true;
5490b57cec5SDimitry Andric       return true;
5500b57cec5SDimitry Andric     }
5510b57cec5SDimitry Andric     // We aren't not above the insert point, check if we can hoist it above the
5520b57cec5SDimitry Andric     // insert point.
5530b57cec5SDimitry Andric     if (isHoistable(I, DT)) {
5540b57cec5SDimitry Andric       // Check operands first.
5550b57cec5SDimitry Andric       DenseSet<Instruction *> OpsHoistStops;
5560b57cec5SDimitry Andric       bool AllOpsHoisted = true;
5570b57cec5SDimitry Andric       for (Value *Op : I->operands()) {
5580b57cec5SDimitry Andric         if (!checkHoistValue(Op, InsertPoint, DT, Unhoistables, &OpsHoistStops,
5590b57cec5SDimitry Andric                              Visited)) {
5600b57cec5SDimitry Andric           AllOpsHoisted = false;
5610b57cec5SDimitry Andric           break;
5620b57cec5SDimitry Andric         }
5630b57cec5SDimitry Andric       }
5640b57cec5SDimitry Andric       if (AllOpsHoisted) {
5650b57cec5SDimitry Andric         CHR_DEBUG(dbgs() << "checkHoistValue " << *I << "\n");
5660b57cec5SDimitry Andric         if (HoistStops)
5670b57cec5SDimitry Andric           HoistStops->insert(OpsHoistStops.begin(), OpsHoistStops.end());
5680b57cec5SDimitry Andric         Visited[I] = true;
5690b57cec5SDimitry Andric         return true;
5700b57cec5SDimitry Andric       }
5710b57cec5SDimitry Andric     }
5720b57cec5SDimitry Andric     Visited[I] = false;
5730b57cec5SDimitry Andric     return false;
5740b57cec5SDimitry Andric   }
5750b57cec5SDimitry Andric   // Non-instructions are considered hoistable.
5760b57cec5SDimitry Andric   return true;
5770b57cec5SDimitry Andric }
5780b57cec5SDimitry Andric 
579bdd1243dSDimitry Andric // Constructs the true and false branch probabilities if the the instruction has
580bdd1243dSDimitry Andric // valid branch weights. Returns true when this was successful, false otherwise.
581bdd1243dSDimitry Andric static bool extractBranchProbabilities(Instruction *I,
582bdd1243dSDimitry Andric                                        BranchProbability &TrueProb,
5830b57cec5SDimitry Andric                                        BranchProbability &FalseProb) {
584bdd1243dSDimitry Andric   uint64_t TrueWeight;
585bdd1243dSDimitry Andric   uint64_t FalseWeight;
586bdd1243dSDimitry Andric   if (!extractBranchWeights(*I, TrueWeight, FalseWeight))
5870b57cec5SDimitry Andric     return false;
588bdd1243dSDimitry Andric   uint64_t SumWeight = TrueWeight + FalseWeight;
5890b57cec5SDimitry Andric 
590bdd1243dSDimitry Andric   assert(SumWeight >= TrueWeight && SumWeight >= FalseWeight &&
5910b57cec5SDimitry Andric          "Overflow calculating branch probabilities.");
5920b57cec5SDimitry Andric 
593480093f4SDimitry Andric   // Guard against 0-to-0 branch weights to avoid a division-by-zero crash.
594bdd1243dSDimitry Andric   if (SumWeight == 0)
595480093f4SDimitry Andric     return false;
596480093f4SDimitry Andric 
597bdd1243dSDimitry Andric   TrueProb = BranchProbability::getBranchProbability(TrueWeight, SumWeight);
598bdd1243dSDimitry Andric   FalseProb = BranchProbability::getBranchProbability(FalseWeight, SumWeight);
5990b57cec5SDimitry Andric   return true;
6000b57cec5SDimitry Andric }
6010b57cec5SDimitry Andric 
6020b57cec5SDimitry Andric static BranchProbability getCHRBiasThreshold() {
6030b57cec5SDimitry Andric   return BranchProbability::getBranchProbability(
6040b57cec5SDimitry Andric       static_cast<uint64_t>(CHRBiasThreshold * 1000000), 1000000);
6050b57cec5SDimitry Andric }
6060b57cec5SDimitry Andric 
6070b57cec5SDimitry Andric // A helper for CheckBiasedBranch and CheckBiasedSelect. If TrueProb >=
6080b57cec5SDimitry Andric // CHRBiasThreshold, put Key into TrueSet and return true. If FalseProb >=
6090b57cec5SDimitry Andric // CHRBiasThreshold, put Key into FalseSet and return true. Otherwise, return
6100b57cec5SDimitry Andric // false.
6110b57cec5SDimitry Andric template <typename K, typename S, typename M>
6120b57cec5SDimitry Andric static bool checkBias(K *Key, BranchProbability TrueProb,
6130b57cec5SDimitry Andric                       BranchProbability FalseProb, S &TrueSet, S &FalseSet,
6140b57cec5SDimitry Andric                       M &BiasMap) {
6150b57cec5SDimitry Andric   BranchProbability Threshold = getCHRBiasThreshold();
6160b57cec5SDimitry Andric   if (TrueProb >= Threshold) {
6170b57cec5SDimitry Andric     TrueSet.insert(Key);
6180b57cec5SDimitry Andric     BiasMap[Key] = TrueProb;
6190b57cec5SDimitry Andric     return true;
6200b57cec5SDimitry Andric   } else if (FalseProb >= Threshold) {
6210b57cec5SDimitry Andric     FalseSet.insert(Key);
6220b57cec5SDimitry Andric     BiasMap[Key] = FalseProb;
6230b57cec5SDimitry Andric     return true;
6240b57cec5SDimitry Andric   }
6250b57cec5SDimitry Andric   return false;
6260b57cec5SDimitry Andric }
6270b57cec5SDimitry Andric 
6280b57cec5SDimitry Andric // Returns true and insert a region into the right biased set and the map if the
6290b57cec5SDimitry Andric // branch of the region is biased.
6300b57cec5SDimitry Andric static bool checkBiasedBranch(BranchInst *BI, Region *R,
6310b57cec5SDimitry Andric                               DenseSet<Region *> &TrueBiasedRegionsGlobal,
6320b57cec5SDimitry Andric                               DenseSet<Region *> &FalseBiasedRegionsGlobal,
6330b57cec5SDimitry Andric                               DenseMap<Region *, BranchProbability> &BranchBiasMap) {
6340b57cec5SDimitry Andric   if (!BI->isConditional())
6350b57cec5SDimitry Andric     return false;
6360b57cec5SDimitry Andric   BranchProbability ThenProb, ElseProb;
637bdd1243dSDimitry Andric   if (!extractBranchProbabilities(BI, ThenProb, ElseProb))
6380b57cec5SDimitry Andric     return false;
6390b57cec5SDimitry Andric   BasicBlock *IfThen = BI->getSuccessor(0);
6400b57cec5SDimitry Andric   BasicBlock *IfElse = BI->getSuccessor(1);
6410b57cec5SDimitry Andric   assert((IfThen == R->getExit() || IfElse == R->getExit()) &&
6420b57cec5SDimitry Andric          IfThen != IfElse &&
6430b57cec5SDimitry Andric          "Invariant from findScopes");
6440b57cec5SDimitry Andric   if (IfThen == R->getExit()) {
6450b57cec5SDimitry Andric     // Swap them so that IfThen/ThenProb means going into the conditional code
6460b57cec5SDimitry Andric     // and IfElse/ElseProb means skipping it.
6470b57cec5SDimitry Andric     std::swap(IfThen, IfElse);
6480b57cec5SDimitry Andric     std::swap(ThenProb, ElseProb);
6490b57cec5SDimitry Andric   }
6500b57cec5SDimitry Andric   CHR_DEBUG(dbgs() << "BI " << *BI << " ");
6510b57cec5SDimitry Andric   CHR_DEBUG(dbgs() << "ThenProb " << ThenProb << " ");
6520b57cec5SDimitry Andric   CHR_DEBUG(dbgs() << "ElseProb " << ElseProb << "\n");
6530b57cec5SDimitry Andric   return checkBias(R, ThenProb, ElseProb,
6540b57cec5SDimitry Andric                    TrueBiasedRegionsGlobal, FalseBiasedRegionsGlobal,
6550b57cec5SDimitry Andric                    BranchBiasMap);
6560b57cec5SDimitry Andric }
6570b57cec5SDimitry Andric 
6580b57cec5SDimitry Andric // Returns true and insert a select into the right biased set and the map if the
6590b57cec5SDimitry Andric // select is biased.
6600b57cec5SDimitry Andric static bool checkBiasedSelect(
6610b57cec5SDimitry Andric     SelectInst *SI, Region *R,
6620b57cec5SDimitry Andric     DenseSet<SelectInst *> &TrueBiasedSelectsGlobal,
6630b57cec5SDimitry Andric     DenseSet<SelectInst *> &FalseBiasedSelectsGlobal,
6640b57cec5SDimitry Andric     DenseMap<SelectInst *, BranchProbability> &SelectBiasMap) {
6650b57cec5SDimitry Andric   BranchProbability TrueProb, FalseProb;
666bdd1243dSDimitry Andric   if (!extractBranchProbabilities(SI, TrueProb, FalseProb))
6670b57cec5SDimitry Andric     return false;
6680b57cec5SDimitry Andric   CHR_DEBUG(dbgs() << "SI " << *SI << " ");
6690b57cec5SDimitry Andric   CHR_DEBUG(dbgs() << "TrueProb " << TrueProb << " ");
6700b57cec5SDimitry Andric   CHR_DEBUG(dbgs() << "FalseProb " << FalseProb << "\n");
6710b57cec5SDimitry Andric   return checkBias(SI, TrueProb, FalseProb,
6720b57cec5SDimitry Andric                    TrueBiasedSelectsGlobal, FalseBiasedSelectsGlobal,
6730b57cec5SDimitry Andric                    SelectBiasMap);
6740b57cec5SDimitry Andric }
6750b57cec5SDimitry Andric 
6760b57cec5SDimitry Andric // Returns the instruction at which to hoist the dependent condition values and
6770b57cec5SDimitry Andric // insert the CHR branch for a region. This is the terminator branch in the
6780b57cec5SDimitry Andric // entry block or the first select in the entry block, if any.
6790b57cec5SDimitry Andric static Instruction* getBranchInsertPoint(RegInfo &RI) {
6800b57cec5SDimitry Andric   Region *R = RI.R;
6810b57cec5SDimitry Andric   BasicBlock *EntryBB = R->getEntry();
6820b57cec5SDimitry Andric   // The hoist point is by default the terminator of the entry block, which is
6830b57cec5SDimitry Andric   // the same as the branch instruction if RI.HasBranch is true.
6840b57cec5SDimitry Andric   Instruction *HoistPoint = EntryBB->getTerminator();
6850b57cec5SDimitry Andric   for (SelectInst *SI : RI.Selects) {
6860b57cec5SDimitry Andric     if (SI->getParent() == EntryBB) {
6870b57cec5SDimitry Andric       // Pick the first select in Selects in the entry block.  Note Selects is
6880b57cec5SDimitry Andric       // sorted in the instruction order within a block (asserted below).
6890b57cec5SDimitry Andric       HoistPoint = SI;
6900b57cec5SDimitry Andric       break;
6910b57cec5SDimitry Andric     }
6920b57cec5SDimitry Andric   }
6930b57cec5SDimitry Andric   assert(HoistPoint && "Null HoistPoint");
6940b57cec5SDimitry Andric #ifndef NDEBUG
6950b57cec5SDimitry Andric   // Check that HoistPoint is the first one in Selects in the entry block,
6960b57cec5SDimitry Andric   // if any.
6970b57cec5SDimitry Andric   DenseSet<Instruction *> EntryBlockSelectSet;
6980b57cec5SDimitry Andric   for (SelectInst *SI : RI.Selects) {
6990b57cec5SDimitry Andric     if (SI->getParent() == EntryBB) {
7000b57cec5SDimitry Andric       EntryBlockSelectSet.insert(SI);
7010b57cec5SDimitry Andric     }
7020b57cec5SDimitry Andric   }
7030b57cec5SDimitry Andric   for (Instruction &I : *EntryBB) {
704e8d8bef9SDimitry Andric     if (EntryBlockSelectSet.contains(&I)) {
7050b57cec5SDimitry Andric       assert(&I == HoistPoint &&
7060b57cec5SDimitry Andric              "HoistPoint must be the first one in Selects");
7070b57cec5SDimitry Andric       break;
7080b57cec5SDimitry Andric     }
7090b57cec5SDimitry Andric   }
7100b57cec5SDimitry Andric #endif
7110b57cec5SDimitry Andric   return HoistPoint;
7120b57cec5SDimitry Andric }
7130b57cec5SDimitry Andric 
7140b57cec5SDimitry Andric // Find a CHR scope in the given region.
7150b57cec5SDimitry Andric CHRScope * CHR::findScope(Region *R) {
7160b57cec5SDimitry Andric   CHRScope *Result = nullptr;
7170b57cec5SDimitry Andric   BasicBlock *Entry = R->getEntry();
7180b57cec5SDimitry Andric   BasicBlock *Exit = R->getExit();  // null if top level.
7190b57cec5SDimitry Andric   assert(Entry && "Entry must not be null");
7200b57cec5SDimitry Andric   assert((Exit == nullptr) == (R->isTopLevelRegion()) &&
7210b57cec5SDimitry Andric          "Only top level region has a null exit");
7220b57cec5SDimitry Andric   if (Entry)
7230b57cec5SDimitry Andric     CHR_DEBUG(dbgs() << "Entry " << Entry->getName() << "\n");
7240b57cec5SDimitry Andric   else
7250b57cec5SDimitry Andric     CHR_DEBUG(dbgs() << "Entry null\n");
7260b57cec5SDimitry Andric   if (Exit)
7270b57cec5SDimitry Andric     CHR_DEBUG(dbgs() << "Exit " << Exit->getName() << "\n");
7280b57cec5SDimitry Andric   else
7290b57cec5SDimitry Andric     CHR_DEBUG(dbgs() << "Exit null\n");
7300b57cec5SDimitry Andric   // Exclude cases where Entry is part of a subregion (hence it doesn't belong
7310b57cec5SDimitry Andric   // to this region).
7320b57cec5SDimitry Andric   bool EntryInSubregion = RI.getRegionFor(Entry) != R;
7330b57cec5SDimitry Andric   if (EntryInSubregion)
7340b57cec5SDimitry Andric     return nullptr;
7350b57cec5SDimitry Andric   // Exclude loops
7360b57cec5SDimitry Andric   for (BasicBlock *Pred : predecessors(Entry))
7370b57cec5SDimitry Andric     if (R->contains(Pred))
7380b57cec5SDimitry Andric       return nullptr;
739fe6060f1SDimitry Andric   // If any of the basic blocks have address taken, we must skip this region
740fe6060f1SDimitry Andric   // because we cannot clone basic blocks that have address taken.
74181ad6265SDimitry Andric   for (BasicBlock *BB : R->blocks()) {
742fe6060f1SDimitry Andric     if (BB->hasAddressTaken())
743fe6060f1SDimitry Andric       return nullptr;
74481ad6265SDimitry Andric     // If we encounter llvm.coro.id, skip this region because if the basic block
74581ad6265SDimitry Andric     // is cloned, we end up inserting a token type PHI node to the block with
74681ad6265SDimitry Andric     // llvm.coro.begin.
74781ad6265SDimitry Andric     // FIXME: This could lead to less optimal codegen, because the region is
74881ad6265SDimitry Andric     // excluded, it can prevent CHR from merging adjacent regions into bigger
74981ad6265SDimitry Andric     // scope and hoisting more branches.
75081ad6265SDimitry Andric     for (Instruction &I : *BB)
75181ad6265SDimitry Andric       if (auto *II = dyn_cast<IntrinsicInst>(&I))
75281ad6265SDimitry Andric         if (II->getIntrinsicID() == Intrinsic::coro_id)
75381ad6265SDimitry Andric           return nullptr;
75481ad6265SDimitry Andric   }
75581ad6265SDimitry Andric 
7560b57cec5SDimitry Andric   if (Exit) {
7570b57cec5SDimitry Andric     // Try to find an if-then block (check if R is an if-then).
7580b57cec5SDimitry Andric     // if (cond) {
7590b57cec5SDimitry Andric     //  ...
7600b57cec5SDimitry Andric     // }
7610b57cec5SDimitry Andric     auto *BI = dyn_cast<BranchInst>(Entry->getTerminator());
7620b57cec5SDimitry Andric     if (BI)
7630b57cec5SDimitry Andric       CHR_DEBUG(dbgs() << "BI.isConditional " << BI->isConditional() << "\n");
7640b57cec5SDimitry Andric     else
7650b57cec5SDimitry Andric       CHR_DEBUG(dbgs() << "BI null\n");
7660b57cec5SDimitry Andric     if (BI && BI->isConditional()) {
7670b57cec5SDimitry Andric       BasicBlock *S0 = BI->getSuccessor(0);
7680b57cec5SDimitry Andric       BasicBlock *S1 = BI->getSuccessor(1);
7690b57cec5SDimitry Andric       CHR_DEBUG(dbgs() << "S0 " << S0->getName() << "\n");
7700b57cec5SDimitry Andric       CHR_DEBUG(dbgs() << "S1 " << S1->getName() << "\n");
7710b57cec5SDimitry Andric       if (S0 != S1 && (S0 == Exit || S1 == Exit)) {
7720b57cec5SDimitry Andric         RegInfo RI(R);
7730b57cec5SDimitry Andric         RI.HasBranch = checkBiasedBranch(
7740b57cec5SDimitry Andric             BI, R, TrueBiasedRegionsGlobal, FalseBiasedRegionsGlobal,
7750b57cec5SDimitry Andric             BranchBiasMap);
7760b57cec5SDimitry Andric         Result = new CHRScope(RI);
7770b57cec5SDimitry Andric         Scopes.insert(Result);
7780b57cec5SDimitry Andric         CHR_DEBUG(dbgs() << "Found a region with a branch\n");
7790b57cec5SDimitry Andric         ++Stats.NumBranches;
7800b57cec5SDimitry Andric         if (!RI.HasBranch) {
7810b57cec5SDimitry Andric           ORE.emit([&]() {
7820b57cec5SDimitry Andric             return OptimizationRemarkMissed(DEBUG_TYPE, "BranchNotBiased", BI)
7830b57cec5SDimitry Andric                 << "Branch not biased";
7840b57cec5SDimitry Andric           });
7850b57cec5SDimitry Andric         }
7860b57cec5SDimitry Andric       }
7870b57cec5SDimitry Andric     }
7880b57cec5SDimitry Andric   }
7890b57cec5SDimitry Andric   {
7900b57cec5SDimitry Andric     // Try to look for selects in the direct child blocks (as opposed to in
7910b57cec5SDimitry Andric     // subregions) of R.
7920b57cec5SDimitry Andric     // ...
7930b57cec5SDimitry Andric     // if (..) { // Some subregion
7940b57cec5SDimitry Andric     //   ...
7950b57cec5SDimitry Andric     // }
7960b57cec5SDimitry Andric     // if (..) { // Some subregion
7970b57cec5SDimitry Andric     //   ...
7980b57cec5SDimitry Andric     // }
7990b57cec5SDimitry Andric     // ...
8000b57cec5SDimitry Andric     // a = cond ? b : c;
8010b57cec5SDimitry Andric     // ...
8020b57cec5SDimitry Andric     SmallVector<SelectInst *, 8> Selects;
8030b57cec5SDimitry Andric     for (RegionNode *E : R->elements()) {
8040b57cec5SDimitry Andric       if (E->isSubRegion())
8050b57cec5SDimitry Andric         continue;
8060b57cec5SDimitry Andric       // This returns the basic block of E if E is a direct child of R (not a
8070b57cec5SDimitry Andric       // subregion.)
8080b57cec5SDimitry Andric       BasicBlock *BB = E->getEntry();
8090b57cec5SDimitry Andric       // Need to push in the order to make it easier to find the first Select
8100b57cec5SDimitry Andric       // later.
8110b57cec5SDimitry Andric       for (Instruction &I : *BB) {
8120b57cec5SDimitry Andric         if (auto *SI = dyn_cast<SelectInst>(&I)) {
8130b57cec5SDimitry Andric           Selects.push_back(SI);
8140b57cec5SDimitry Andric           ++Stats.NumBranches;
8150b57cec5SDimitry Andric         }
8160b57cec5SDimitry Andric       }
8170b57cec5SDimitry Andric     }
8180b57cec5SDimitry Andric     if (Selects.size() > 0) {
8190b57cec5SDimitry Andric       auto AddSelects = [&](RegInfo &RI) {
8200b57cec5SDimitry Andric         for (auto *SI : Selects)
8210b57cec5SDimitry Andric           if (checkBiasedSelect(SI, RI.R,
8220b57cec5SDimitry Andric                                 TrueBiasedSelectsGlobal,
8230b57cec5SDimitry Andric                                 FalseBiasedSelectsGlobal,
8240b57cec5SDimitry Andric                                 SelectBiasMap))
8250b57cec5SDimitry Andric             RI.Selects.push_back(SI);
8260b57cec5SDimitry Andric           else
8270b57cec5SDimitry Andric             ORE.emit([&]() {
8280b57cec5SDimitry Andric               return OptimizationRemarkMissed(DEBUG_TYPE, "SelectNotBiased", SI)
8290b57cec5SDimitry Andric                   << "Select not biased";
8300b57cec5SDimitry Andric             });
8310b57cec5SDimitry Andric       };
8320b57cec5SDimitry Andric       if (!Result) {
8330b57cec5SDimitry Andric         CHR_DEBUG(dbgs() << "Found a select-only region\n");
8340b57cec5SDimitry Andric         RegInfo RI(R);
8350b57cec5SDimitry Andric         AddSelects(RI);
8360b57cec5SDimitry Andric         Result = new CHRScope(RI);
8370b57cec5SDimitry Andric         Scopes.insert(Result);
8380b57cec5SDimitry Andric       } else {
8390b57cec5SDimitry Andric         CHR_DEBUG(dbgs() << "Found select(s) in a region with a branch\n");
8400b57cec5SDimitry Andric         AddSelects(Result->RegInfos[0]);
8410b57cec5SDimitry Andric       }
8420b57cec5SDimitry Andric     }
8430b57cec5SDimitry Andric   }
8440b57cec5SDimitry Andric 
8450b57cec5SDimitry Andric   if (Result) {
8460b57cec5SDimitry Andric     checkScopeHoistable(Result);
8470b57cec5SDimitry Andric   }
8480b57cec5SDimitry Andric   return Result;
8490b57cec5SDimitry Andric }
8500b57cec5SDimitry Andric 
8510b57cec5SDimitry Andric // Check that any of the branch and the selects in the region could be
8520b57cec5SDimitry Andric // hoisted above the the CHR branch insert point (the most dominating of
8530b57cec5SDimitry Andric // them, either the branch (at the end of the first block) or the first
8540b57cec5SDimitry Andric // select in the first block). If the branch can't be hoisted, drop the
8550b57cec5SDimitry Andric // selects in the first blocks.
8560b57cec5SDimitry Andric //
8570b57cec5SDimitry Andric // For example, for the following scope/region with selects, we want to insert
8580b57cec5SDimitry Andric // the merged branch right before the first select in the first/entry block by
8590b57cec5SDimitry Andric // hoisting c1, c2, c3, and c4.
8600b57cec5SDimitry Andric //
8610b57cec5SDimitry Andric // // Branch insert point here.
8620b57cec5SDimitry Andric // a = c1 ? b : c; // Select 1
8630b57cec5SDimitry Andric // d = c2 ? e : f; // Select 2
8640b57cec5SDimitry Andric // if (c3) { // Branch
8650b57cec5SDimitry Andric //   ...
8660b57cec5SDimitry Andric //   c4 = foo() // A call.
8670b57cec5SDimitry Andric //   g = c4 ? h : i; // Select 3
8680b57cec5SDimitry Andric // }
8690b57cec5SDimitry Andric //
8700b57cec5SDimitry Andric // But suppose we can't hoist c4 because it's dependent on the preceding
8710b57cec5SDimitry Andric // call. Then, we drop Select 3. Furthermore, if we can't hoist c2, we also drop
8720b57cec5SDimitry Andric // Select 2. If we can't hoist c3, we drop Selects 1 & 2.
8730b57cec5SDimitry Andric void CHR::checkScopeHoistable(CHRScope *Scope) {
8740b57cec5SDimitry Andric   RegInfo &RI = Scope->RegInfos[0];
8750b57cec5SDimitry Andric   Region *R = RI.R;
8760b57cec5SDimitry Andric   BasicBlock *EntryBB = R->getEntry();
8770b57cec5SDimitry Andric   auto *Branch = RI.HasBranch ?
8780b57cec5SDimitry Andric                  cast<BranchInst>(EntryBB->getTerminator()) : nullptr;
8790b57cec5SDimitry Andric   SmallVector<SelectInst *, 8> &Selects = RI.Selects;
8800b57cec5SDimitry Andric   if (RI.HasBranch || !Selects.empty()) {
8810b57cec5SDimitry Andric     Instruction *InsertPoint = getBranchInsertPoint(RI);
8820b57cec5SDimitry Andric     CHR_DEBUG(dbgs() << "InsertPoint " << *InsertPoint << "\n");
8830b57cec5SDimitry Andric     // Avoid a data dependence from a select or a branch to a(nother)
8840b57cec5SDimitry Andric     // select. Note no instruction can't data-depend on a branch (a branch
8850b57cec5SDimitry Andric     // instruction doesn't produce a value).
8860b57cec5SDimitry Andric     DenseSet<Instruction *> Unhoistables;
8870b57cec5SDimitry Andric     // Initialize Unhoistables with the selects.
8880b57cec5SDimitry Andric     for (SelectInst *SI : Selects) {
8890b57cec5SDimitry Andric       Unhoistables.insert(SI);
8900b57cec5SDimitry Andric     }
8910b57cec5SDimitry Andric     // Remove Selects that can't be hoisted.
8920b57cec5SDimitry Andric     for (auto it = Selects.begin(); it != Selects.end(); ) {
8930b57cec5SDimitry Andric       SelectInst *SI = *it;
8940b57cec5SDimitry Andric       if (SI == InsertPoint) {
8950b57cec5SDimitry Andric         ++it;
8960b57cec5SDimitry Andric         continue;
8970b57cec5SDimitry Andric       }
8980b57cec5SDimitry Andric       DenseMap<Instruction *, bool> Visited;
8990b57cec5SDimitry Andric       bool IsHoistable = checkHoistValue(SI->getCondition(), InsertPoint,
9000b57cec5SDimitry Andric                                          DT, Unhoistables, nullptr, Visited);
9010b57cec5SDimitry Andric       if (!IsHoistable) {
9020b57cec5SDimitry Andric         CHR_DEBUG(dbgs() << "Dropping select " << *SI << "\n");
9030b57cec5SDimitry Andric         ORE.emit([&]() {
9040b57cec5SDimitry Andric           return OptimizationRemarkMissed(DEBUG_TYPE,
9050b57cec5SDimitry Andric                                           "DropUnhoistableSelect", SI)
9060b57cec5SDimitry Andric               << "Dropped unhoistable select";
9070b57cec5SDimitry Andric         });
9080b57cec5SDimitry Andric         it = Selects.erase(it);
9090b57cec5SDimitry Andric         // Since we are dropping the select here, we also drop it from
9100b57cec5SDimitry Andric         // Unhoistables.
9110b57cec5SDimitry Andric         Unhoistables.erase(SI);
9120b57cec5SDimitry Andric       } else
9130b57cec5SDimitry Andric         ++it;
9140b57cec5SDimitry Andric     }
9150b57cec5SDimitry Andric     // Update InsertPoint after potentially removing selects.
9160b57cec5SDimitry Andric     InsertPoint = getBranchInsertPoint(RI);
9170b57cec5SDimitry Andric     CHR_DEBUG(dbgs() << "InsertPoint " << *InsertPoint << "\n");
9180b57cec5SDimitry Andric     if (RI.HasBranch && InsertPoint != Branch) {
9190b57cec5SDimitry Andric       DenseMap<Instruction *, bool> Visited;
9200b57cec5SDimitry Andric       bool IsHoistable = checkHoistValue(Branch->getCondition(), InsertPoint,
9210b57cec5SDimitry Andric                                          DT, Unhoistables, nullptr, Visited);
9220b57cec5SDimitry Andric       if (!IsHoistable) {
9230b57cec5SDimitry Andric         // If the branch isn't hoistable, drop the selects in the entry
9240b57cec5SDimitry Andric         // block, preferring the branch, which makes the branch the hoist
9250b57cec5SDimitry Andric         // point.
9260b57cec5SDimitry Andric         assert(InsertPoint != Branch && "Branch must not be the hoist point");
9270b57cec5SDimitry Andric         CHR_DEBUG(dbgs() << "Dropping selects in entry block \n");
9280b57cec5SDimitry Andric         CHR_DEBUG(
9290b57cec5SDimitry Andric             for (SelectInst *SI : Selects) {
9300b57cec5SDimitry Andric               dbgs() << "SI " << *SI << "\n";
9310b57cec5SDimitry Andric             });
9320b57cec5SDimitry Andric         for (SelectInst *SI : Selects) {
9330b57cec5SDimitry Andric           ORE.emit([&]() {
9340b57cec5SDimitry Andric             return OptimizationRemarkMissed(DEBUG_TYPE,
9350b57cec5SDimitry Andric                                             "DropSelectUnhoistableBranch", SI)
9360b57cec5SDimitry Andric                 << "Dropped select due to unhoistable branch";
9370b57cec5SDimitry Andric           });
9380b57cec5SDimitry Andric         }
939e8d8bef9SDimitry Andric         llvm::erase_if(Selects, [EntryBB](SelectInst *SI) {
9400b57cec5SDimitry Andric           return SI->getParent() == EntryBB;
941e8d8bef9SDimitry Andric         });
9420b57cec5SDimitry Andric         Unhoistables.clear();
9430b57cec5SDimitry Andric         InsertPoint = Branch;
9440b57cec5SDimitry Andric       }
9450b57cec5SDimitry Andric     }
9460b57cec5SDimitry Andric     CHR_DEBUG(dbgs() << "InsertPoint " << *InsertPoint << "\n");
9470b57cec5SDimitry Andric #ifndef NDEBUG
9480b57cec5SDimitry Andric     if (RI.HasBranch) {
9490b57cec5SDimitry Andric       assert(!DT.dominates(Branch, InsertPoint) &&
9500b57cec5SDimitry Andric              "Branch can't be already above the hoist point");
9510b57cec5SDimitry Andric       DenseMap<Instruction *, bool> Visited;
9520b57cec5SDimitry Andric       assert(checkHoistValue(Branch->getCondition(), InsertPoint,
9530b57cec5SDimitry Andric                              DT, Unhoistables, nullptr, Visited) &&
9540b57cec5SDimitry Andric              "checkHoistValue for branch");
9550b57cec5SDimitry Andric     }
9560b57cec5SDimitry Andric     for (auto *SI : Selects) {
9570b57cec5SDimitry Andric       assert(!DT.dominates(SI, InsertPoint) &&
9580b57cec5SDimitry Andric              "SI can't be already above the hoist point");
9590b57cec5SDimitry Andric       DenseMap<Instruction *, bool> Visited;
9600b57cec5SDimitry Andric       assert(checkHoistValue(SI->getCondition(), InsertPoint, DT,
9610b57cec5SDimitry Andric                              Unhoistables, nullptr, Visited) &&
9620b57cec5SDimitry Andric              "checkHoistValue for selects");
9630b57cec5SDimitry Andric     }
9640b57cec5SDimitry Andric     CHR_DEBUG(dbgs() << "Result\n");
9650b57cec5SDimitry Andric     if (RI.HasBranch) {
9660b57cec5SDimitry Andric       CHR_DEBUG(dbgs() << "BI " << *Branch << "\n");
9670b57cec5SDimitry Andric     }
9680b57cec5SDimitry Andric     for (auto *SI : Selects) {
9690b57cec5SDimitry Andric       CHR_DEBUG(dbgs() << "SI " << *SI << "\n");
9700b57cec5SDimitry Andric     }
9710b57cec5SDimitry Andric #endif
9720b57cec5SDimitry Andric   }
9730b57cec5SDimitry Andric }
9740b57cec5SDimitry Andric 
9750b57cec5SDimitry Andric // Traverse the region tree, find all nested scopes and merge them if possible.
9760b57cec5SDimitry Andric CHRScope * CHR::findScopes(Region *R, Region *NextRegion, Region *ParentRegion,
9770b57cec5SDimitry Andric                            SmallVectorImpl<CHRScope *> &Scopes) {
9780b57cec5SDimitry Andric   CHR_DEBUG(dbgs() << "findScopes " << R->getNameStr() << "\n");
9790b57cec5SDimitry Andric   CHRScope *Result = findScope(R);
9800b57cec5SDimitry Andric   // Visit subscopes.
9810b57cec5SDimitry Andric   CHRScope *ConsecutiveSubscope = nullptr;
9820b57cec5SDimitry Andric   SmallVector<CHRScope *, 8> Subscopes;
9830b57cec5SDimitry Andric   for (auto It = R->begin(); It != R->end(); ++It) {
9840b57cec5SDimitry Andric     const std::unique_ptr<Region> &SubR = *It;
9850b57cec5SDimitry Andric     auto NextIt = std::next(It);
9860b57cec5SDimitry Andric     Region *NextSubR = NextIt != R->end() ? NextIt->get() : nullptr;
9870b57cec5SDimitry Andric     CHR_DEBUG(dbgs() << "Looking at subregion " << SubR.get()->getNameStr()
9880b57cec5SDimitry Andric               << "\n");
9890b57cec5SDimitry Andric     CHRScope *SubCHRScope = findScopes(SubR.get(), NextSubR, R, Scopes);
9900b57cec5SDimitry Andric     if (SubCHRScope) {
9910b57cec5SDimitry Andric       CHR_DEBUG(dbgs() << "Subregion Scope " << *SubCHRScope << "\n");
9920b57cec5SDimitry Andric     } else {
9930b57cec5SDimitry Andric       CHR_DEBUG(dbgs() << "Subregion Scope null\n");
9940b57cec5SDimitry Andric     }
9950b57cec5SDimitry Andric     if (SubCHRScope) {
9960b57cec5SDimitry Andric       if (!ConsecutiveSubscope)
9970b57cec5SDimitry Andric         ConsecutiveSubscope = SubCHRScope;
9980b57cec5SDimitry Andric       else if (!ConsecutiveSubscope->appendable(SubCHRScope)) {
9990b57cec5SDimitry Andric         Subscopes.push_back(ConsecutiveSubscope);
10000b57cec5SDimitry Andric         ConsecutiveSubscope = SubCHRScope;
10010b57cec5SDimitry Andric       } else
10020b57cec5SDimitry Andric         ConsecutiveSubscope->append(SubCHRScope);
10030b57cec5SDimitry Andric     } else {
10040b57cec5SDimitry Andric       if (ConsecutiveSubscope) {
10050b57cec5SDimitry Andric         Subscopes.push_back(ConsecutiveSubscope);
10060b57cec5SDimitry Andric       }
10070b57cec5SDimitry Andric       ConsecutiveSubscope = nullptr;
10080b57cec5SDimitry Andric     }
10090b57cec5SDimitry Andric   }
10100b57cec5SDimitry Andric   if (ConsecutiveSubscope) {
10110b57cec5SDimitry Andric     Subscopes.push_back(ConsecutiveSubscope);
10120b57cec5SDimitry Andric   }
10130b57cec5SDimitry Andric   for (CHRScope *Sub : Subscopes) {
10140b57cec5SDimitry Andric     if (Result) {
10150b57cec5SDimitry Andric       // Combine it with the parent.
10160b57cec5SDimitry Andric       Result->addSub(Sub);
10170b57cec5SDimitry Andric     } else {
10180b57cec5SDimitry Andric       // Push Subscopes as they won't be combined with the parent.
10190b57cec5SDimitry Andric       Scopes.push_back(Sub);
10200b57cec5SDimitry Andric     }
10210b57cec5SDimitry Andric   }
10220b57cec5SDimitry Andric   return Result;
10230b57cec5SDimitry Andric }
10240b57cec5SDimitry Andric 
10250b57cec5SDimitry Andric static DenseSet<Value *> getCHRConditionValuesForRegion(RegInfo &RI) {
10260b57cec5SDimitry Andric   DenseSet<Value *> ConditionValues;
10270b57cec5SDimitry Andric   if (RI.HasBranch) {
10280b57cec5SDimitry Andric     auto *BI = cast<BranchInst>(RI.R->getEntry()->getTerminator());
10290b57cec5SDimitry Andric     ConditionValues.insert(BI->getCondition());
10300b57cec5SDimitry Andric   }
10310b57cec5SDimitry Andric   for (SelectInst *SI : RI.Selects) {
10320b57cec5SDimitry Andric     ConditionValues.insert(SI->getCondition());
10330b57cec5SDimitry Andric   }
10340b57cec5SDimitry Andric   return ConditionValues;
10350b57cec5SDimitry Andric }
10360b57cec5SDimitry Andric 
10370b57cec5SDimitry Andric 
10380b57cec5SDimitry Andric // Determine whether to split a scope depending on the sets of the branch
10390b57cec5SDimitry Andric // condition values of the previous region and the current region. We split
10400b57cec5SDimitry Andric // (return true) it if 1) the condition values of the inner/lower scope can't be
10410b57cec5SDimitry Andric // hoisted up to the outer/upper scope, or 2) the two sets of the condition
10420b57cec5SDimitry Andric // values have an empty intersection (because the combined branch conditions
10430b57cec5SDimitry Andric // won't probably lead to a simpler combined condition).
10440b57cec5SDimitry Andric static bool shouldSplit(Instruction *InsertPoint,
10450b57cec5SDimitry Andric                         DenseSet<Value *> &PrevConditionValues,
10460b57cec5SDimitry Andric                         DenseSet<Value *> &ConditionValues,
10470b57cec5SDimitry Andric                         DominatorTree &DT,
10480b57cec5SDimitry Andric                         DenseSet<Instruction *> &Unhoistables) {
1049480093f4SDimitry Andric   assert(InsertPoint && "Null InsertPoint");
10500b57cec5SDimitry Andric   CHR_DEBUG(
10510b57cec5SDimitry Andric       dbgs() << "shouldSplit " << *InsertPoint << " PrevConditionValues ";
10520b57cec5SDimitry Andric       for (Value *V : PrevConditionValues) {
10530b57cec5SDimitry Andric         dbgs() << *V << ", ";
10540b57cec5SDimitry Andric       }
10550b57cec5SDimitry Andric       dbgs() << " ConditionValues ";
10560b57cec5SDimitry Andric       for (Value *V : ConditionValues) {
10570b57cec5SDimitry Andric         dbgs() << *V << ", ";
10580b57cec5SDimitry Andric       }
10590b57cec5SDimitry Andric       dbgs() << "\n");
10600b57cec5SDimitry Andric   // If any of Bases isn't hoistable to the hoist point, split.
10610b57cec5SDimitry Andric   for (Value *V : ConditionValues) {
10620b57cec5SDimitry Andric     DenseMap<Instruction *, bool> Visited;
10630b57cec5SDimitry Andric     if (!checkHoistValue(V, InsertPoint, DT, Unhoistables, nullptr, Visited)) {
10640b57cec5SDimitry Andric       CHR_DEBUG(dbgs() << "Split. checkHoistValue false " << *V << "\n");
10650b57cec5SDimitry Andric       return true; // Not hoistable, split.
10660b57cec5SDimitry Andric     }
10670b57cec5SDimitry Andric   }
10680b57cec5SDimitry Andric   // If PrevConditionValues or ConditionValues is empty, don't split to avoid
10690b57cec5SDimitry Andric   // unnecessary splits at scopes with no branch/selects.  If
10700b57cec5SDimitry Andric   // PrevConditionValues and ConditionValues don't intersect at all, split.
10710b57cec5SDimitry Andric   if (!PrevConditionValues.empty() && !ConditionValues.empty()) {
10720b57cec5SDimitry Andric     // Use std::set as DenseSet doesn't work with set_intersection.
10730b57cec5SDimitry Andric     std::set<Value *> PrevBases, Bases;
10748bcb0991SDimitry Andric     DenseMap<Value *, std::set<Value *>> Visited;
10750b57cec5SDimitry Andric     for (Value *V : PrevConditionValues) {
10765ffd83dbSDimitry Andric       const std::set<Value *> &BaseValues = getBaseValues(V, DT, Visited);
10770b57cec5SDimitry Andric       PrevBases.insert(BaseValues.begin(), BaseValues.end());
10780b57cec5SDimitry Andric     }
10790b57cec5SDimitry Andric     for (Value *V : ConditionValues) {
10805ffd83dbSDimitry Andric       const std::set<Value *> &BaseValues = getBaseValues(V, DT, Visited);
10810b57cec5SDimitry Andric       Bases.insert(BaseValues.begin(), BaseValues.end());
10820b57cec5SDimitry Andric     }
10830b57cec5SDimitry Andric     CHR_DEBUG(
10840b57cec5SDimitry Andric         dbgs() << "PrevBases ";
10850b57cec5SDimitry Andric         for (Value *V : PrevBases) {
10860b57cec5SDimitry Andric           dbgs() << *V << ", ";
10870b57cec5SDimitry Andric         }
10880b57cec5SDimitry Andric         dbgs() << " Bases ";
10890b57cec5SDimitry Andric         for (Value *V : Bases) {
10900b57cec5SDimitry Andric           dbgs() << *V << ", ";
10910b57cec5SDimitry Andric         }
10920b57cec5SDimitry Andric         dbgs() << "\n");
10935ffd83dbSDimitry Andric     std::vector<Value *> Intersection;
10945ffd83dbSDimitry Andric     std::set_intersection(PrevBases.begin(), PrevBases.end(), Bases.begin(),
10955ffd83dbSDimitry Andric                           Bases.end(), std::back_inserter(Intersection));
10960b57cec5SDimitry Andric     if (Intersection.empty()) {
10970b57cec5SDimitry Andric       // Empty intersection, split.
10980b57cec5SDimitry Andric       CHR_DEBUG(dbgs() << "Split. Intersection empty\n");
10990b57cec5SDimitry Andric       return true;
11000b57cec5SDimitry Andric     }
11010b57cec5SDimitry Andric   }
11020b57cec5SDimitry Andric   CHR_DEBUG(dbgs() << "No split\n");
11030b57cec5SDimitry Andric   return false;  // Don't split.
11040b57cec5SDimitry Andric }
11050b57cec5SDimitry Andric 
11060b57cec5SDimitry Andric static void getSelectsInScope(CHRScope *Scope,
11070b57cec5SDimitry Andric                               DenseSet<Instruction *> &Output) {
11080b57cec5SDimitry Andric   for (RegInfo &RI : Scope->RegInfos)
11090b57cec5SDimitry Andric     for (SelectInst *SI : RI.Selects)
11100b57cec5SDimitry Andric       Output.insert(SI);
11110b57cec5SDimitry Andric   for (CHRScope *Sub : Scope->Subs)
11120b57cec5SDimitry Andric     getSelectsInScope(Sub, Output);
11130b57cec5SDimitry Andric }
11140b57cec5SDimitry Andric 
11150b57cec5SDimitry Andric void CHR::splitScopes(SmallVectorImpl<CHRScope *> &Input,
11160b57cec5SDimitry Andric                       SmallVectorImpl<CHRScope *> &Output) {
11170b57cec5SDimitry Andric   for (CHRScope *Scope : Input) {
11180b57cec5SDimitry Andric     assert(!Scope->BranchInsertPoint &&
11190b57cec5SDimitry Andric            "BranchInsertPoint must not be set");
11200b57cec5SDimitry Andric     DenseSet<Instruction *> Unhoistables;
11210b57cec5SDimitry Andric     getSelectsInScope(Scope, Unhoistables);
11220b57cec5SDimitry Andric     splitScope(Scope, nullptr, nullptr, nullptr, Output, Unhoistables);
11230b57cec5SDimitry Andric   }
11240b57cec5SDimitry Andric #ifndef NDEBUG
11250b57cec5SDimitry Andric   for (CHRScope *Scope : Output) {
11260b57cec5SDimitry Andric     assert(Scope->BranchInsertPoint && "BranchInsertPoint must be set");
11270b57cec5SDimitry Andric   }
11280b57cec5SDimitry Andric #endif
11290b57cec5SDimitry Andric }
11300b57cec5SDimitry Andric 
11310b57cec5SDimitry Andric SmallVector<CHRScope *, 8> CHR::splitScope(
11320b57cec5SDimitry Andric     CHRScope *Scope,
11330b57cec5SDimitry Andric     CHRScope *Outer,
11340b57cec5SDimitry Andric     DenseSet<Value *> *OuterConditionValues,
11350b57cec5SDimitry Andric     Instruction *OuterInsertPoint,
11360b57cec5SDimitry Andric     SmallVectorImpl<CHRScope *> &Output,
11370b57cec5SDimitry Andric     DenseSet<Instruction *> &Unhoistables) {
11380b57cec5SDimitry Andric   if (Outer) {
11390b57cec5SDimitry Andric     assert(OuterConditionValues && "Null OuterConditionValues");
11400b57cec5SDimitry Andric     assert(OuterInsertPoint && "Null OuterInsertPoint");
11410b57cec5SDimitry Andric   }
11420b57cec5SDimitry Andric   bool PrevSplitFromOuter = true;
11430b57cec5SDimitry Andric   DenseSet<Value *> PrevConditionValues;
11440b57cec5SDimitry Andric   Instruction *PrevInsertPoint = nullptr;
11450b57cec5SDimitry Andric   SmallVector<CHRScope *, 8> Splits;
11460b57cec5SDimitry Andric   SmallVector<bool, 8> SplitsSplitFromOuter;
11470b57cec5SDimitry Andric   SmallVector<DenseSet<Value *>, 8> SplitsConditionValues;
11480b57cec5SDimitry Andric   SmallVector<Instruction *, 8> SplitsInsertPoints;
11490b57cec5SDimitry Andric   SmallVector<RegInfo, 8> RegInfos(Scope->RegInfos);  // Copy
11500b57cec5SDimitry Andric   for (RegInfo &RI : RegInfos) {
11510b57cec5SDimitry Andric     Instruction *InsertPoint = getBranchInsertPoint(RI);
11520b57cec5SDimitry Andric     DenseSet<Value *> ConditionValues = getCHRConditionValuesForRegion(RI);
11530b57cec5SDimitry Andric     CHR_DEBUG(
11540b57cec5SDimitry Andric         dbgs() << "ConditionValues ";
11550b57cec5SDimitry Andric         for (Value *V : ConditionValues) {
11560b57cec5SDimitry Andric           dbgs() << *V << ", ";
11570b57cec5SDimitry Andric         }
11580b57cec5SDimitry Andric         dbgs() << "\n");
11590b57cec5SDimitry Andric     if (RI.R == RegInfos[0].R) {
11600b57cec5SDimitry Andric       // First iteration. Check to see if we should split from the outer.
11610b57cec5SDimitry Andric       if (Outer) {
11620b57cec5SDimitry Andric         CHR_DEBUG(dbgs() << "Outer " << *Outer << "\n");
11630b57cec5SDimitry Andric         CHR_DEBUG(dbgs() << "Should split from outer at "
11640b57cec5SDimitry Andric                   << RI.R->getNameStr() << "\n");
11650b57cec5SDimitry Andric         if (shouldSplit(OuterInsertPoint, *OuterConditionValues,
11660b57cec5SDimitry Andric                         ConditionValues, DT, Unhoistables)) {
11670b57cec5SDimitry Andric           PrevConditionValues = ConditionValues;
11680b57cec5SDimitry Andric           PrevInsertPoint = InsertPoint;
11690b57cec5SDimitry Andric           ORE.emit([&]() {
11700b57cec5SDimitry Andric             return OptimizationRemarkMissed(DEBUG_TYPE,
11710b57cec5SDimitry Andric                                             "SplitScopeFromOuter",
11720b57cec5SDimitry Andric                                             RI.R->getEntry()->getTerminator())
11730b57cec5SDimitry Andric                 << "Split scope from outer due to unhoistable branch/select "
11740b57cec5SDimitry Andric                 << "and/or lack of common condition values";
11750b57cec5SDimitry Andric           });
11760b57cec5SDimitry Andric         } else {
11770b57cec5SDimitry Andric           // Not splitting from the outer. Use the outer bases and insert
11780b57cec5SDimitry Andric           // point. Union the bases.
11790b57cec5SDimitry Andric           PrevSplitFromOuter = false;
11800b57cec5SDimitry Andric           PrevConditionValues = *OuterConditionValues;
11810b57cec5SDimitry Andric           PrevConditionValues.insert(ConditionValues.begin(),
11820b57cec5SDimitry Andric                                      ConditionValues.end());
11830b57cec5SDimitry Andric           PrevInsertPoint = OuterInsertPoint;
11840b57cec5SDimitry Andric         }
11850b57cec5SDimitry Andric       } else {
11860b57cec5SDimitry Andric         CHR_DEBUG(dbgs() << "Outer null\n");
11870b57cec5SDimitry Andric         PrevConditionValues = ConditionValues;
11880b57cec5SDimitry Andric         PrevInsertPoint = InsertPoint;
11890b57cec5SDimitry Andric       }
11900b57cec5SDimitry Andric     } else {
11910b57cec5SDimitry Andric       CHR_DEBUG(dbgs() << "Should split from prev at "
11920b57cec5SDimitry Andric                 << RI.R->getNameStr() << "\n");
11930b57cec5SDimitry Andric       if (shouldSplit(PrevInsertPoint, PrevConditionValues, ConditionValues,
11940b57cec5SDimitry Andric                       DT, Unhoistables)) {
11950b57cec5SDimitry Andric         CHRScope *Tail = Scope->split(RI.R);
11960b57cec5SDimitry Andric         Scopes.insert(Tail);
11970b57cec5SDimitry Andric         Splits.push_back(Scope);
11980b57cec5SDimitry Andric         SplitsSplitFromOuter.push_back(PrevSplitFromOuter);
11990b57cec5SDimitry Andric         SplitsConditionValues.push_back(PrevConditionValues);
12000b57cec5SDimitry Andric         SplitsInsertPoints.push_back(PrevInsertPoint);
12010b57cec5SDimitry Andric         Scope = Tail;
12020b57cec5SDimitry Andric         PrevConditionValues = ConditionValues;
12030b57cec5SDimitry Andric         PrevInsertPoint = InsertPoint;
12040b57cec5SDimitry Andric         PrevSplitFromOuter = true;
12050b57cec5SDimitry Andric         ORE.emit([&]() {
12060b57cec5SDimitry Andric           return OptimizationRemarkMissed(DEBUG_TYPE,
12070b57cec5SDimitry Andric                                           "SplitScopeFromPrev",
12080b57cec5SDimitry Andric                                           RI.R->getEntry()->getTerminator())
12090b57cec5SDimitry Andric               << "Split scope from previous due to unhoistable branch/select "
12100b57cec5SDimitry Andric               << "and/or lack of common condition values";
12110b57cec5SDimitry Andric         });
12120b57cec5SDimitry Andric       } else {
12130b57cec5SDimitry Andric         // Not splitting. Union the bases. Keep the hoist point.
12140b57cec5SDimitry Andric         PrevConditionValues.insert(ConditionValues.begin(), ConditionValues.end());
12150b57cec5SDimitry Andric       }
12160b57cec5SDimitry Andric     }
12170b57cec5SDimitry Andric   }
12180b57cec5SDimitry Andric   Splits.push_back(Scope);
12190b57cec5SDimitry Andric   SplitsSplitFromOuter.push_back(PrevSplitFromOuter);
12200b57cec5SDimitry Andric   SplitsConditionValues.push_back(PrevConditionValues);
12210b57cec5SDimitry Andric   assert(PrevInsertPoint && "Null PrevInsertPoint");
12220b57cec5SDimitry Andric   SplitsInsertPoints.push_back(PrevInsertPoint);
12230b57cec5SDimitry Andric   assert(Splits.size() == SplitsConditionValues.size() &&
12240b57cec5SDimitry Andric          Splits.size() == SplitsSplitFromOuter.size() &&
12250b57cec5SDimitry Andric          Splits.size() == SplitsInsertPoints.size() && "Mismatching sizes");
12260b57cec5SDimitry Andric   for (size_t I = 0; I < Splits.size(); ++I) {
12270b57cec5SDimitry Andric     CHRScope *Split = Splits[I];
12280b57cec5SDimitry Andric     DenseSet<Value *> &SplitConditionValues = SplitsConditionValues[I];
12290b57cec5SDimitry Andric     Instruction *SplitInsertPoint = SplitsInsertPoints[I];
12300b57cec5SDimitry Andric     SmallVector<CHRScope *, 8> NewSubs;
12310b57cec5SDimitry Andric     DenseSet<Instruction *> SplitUnhoistables;
12320b57cec5SDimitry Andric     getSelectsInScope(Split, SplitUnhoistables);
12330b57cec5SDimitry Andric     for (CHRScope *Sub : Split->Subs) {
12340b57cec5SDimitry Andric       SmallVector<CHRScope *, 8> SubSplits = splitScope(
12350b57cec5SDimitry Andric           Sub, Split, &SplitConditionValues, SplitInsertPoint, Output,
12360b57cec5SDimitry Andric           SplitUnhoistables);
1237e8d8bef9SDimitry Andric       llvm::append_range(NewSubs, SubSplits);
12380b57cec5SDimitry Andric     }
12390b57cec5SDimitry Andric     Split->Subs = NewSubs;
12400b57cec5SDimitry Andric   }
12410b57cec5SDimitry Andric   SmallVector<CHRScope *, 8> Result;
12420b57cec5SDimitry Andric   for (size_t I = 0; I < Splits.size(); ++I) {
12430b57cec5SDimitry Andric     CHRScope *Split = Splits[I];
12440b57cec5SDimitry Andric     if (SplitsSplitFromOuter[I]) {
12450b57cec5SDimitry Andric       // Split from the outer.
12460b57cec5SDimitry Andric       Output.push_back(Split);
12470b57cec5SDimitry Andric       Split->BranchInsertPoint = SplitsInsertPoints[I];
12480b57cec5SDimitry Andric       CHR_DEBUG(dbgs() << "BranchInsertPoint " << *SplitsInsertPoints[I]
12490b57cec5SDimitry Andric                 << "\n");
12500b57cec5SDimitry Andric     } else {
12510b57cec5SDimitry Andric       // Connected to the outer.
12520b57cec5SDimitry Andric       Result.push_back(Split);
12530b57cec5SDimitry Andric     }
12540b57cec5SDimitry Andric   }
12550b57cec5SDimitry Andric   if (!Outer)
12560b57cec5SDimitry Andric     assert(Result.empty() &&
12570b57cec5SDimitry Andric            "If no outer (top-level), must return no nested ones");
12580b57cec5SDimitry Andric   return Result;
12590b57cec5SDimitry Andric }
12600b57cec5SDimitry Andric 
12610b57cec5SDimitry Andric void CHR::classifyBiasedScopes(SmallVectorImpl<CHRScope *> &Scopes) {
12620b57cec5SDimitry Andric   for (CHRScope *Scope : Scopes) {
12630b57cec5SDimitry Andric     assert(Scope->TrueBiasedRegions.empty() && Scope->FalseBiasedRegions.empty() && "Empty");
12640b57cec5SDimitry Andric     classifyBiasedScopes(Scope, Scope);
12650b57cec5SDimitry Andric     CHR_DEBUG(
12660b57cec5SDimitry Andric         dbgs() << "classifyBiasedScopes " << *Scope << "\n";
12670b57cec5SDimitry Andric         dbgs() << "TrueBiasedRegions ";
12680b57cec5SDimitry Andric         for (Region *R : Scope->TrueBiasedRegions) {
12690b57cec5SDimitry Andric           dbgs() << R->getNameStr() << ", ";
12700b57cec5SDimitry Andric         }
12710b57cec5SDimitry Andric         dbgs() << "\n";
12720b57cec5SDimitry Andric         dbgs() << "FalseBiasedRegions ";
12730b57cec5SDimitry Andric         for (Region *R : Scope->FalseBiasedRegions) {
12740b57cec5SDimitry Andric           dbgs() << R->getNameStr() << ", ";
12750b57cec5SDimitry Andric         }
12760b57cec5SDimitry Andric         dbgs() << "\n";
12770b57cec5SDimitry Andric         dbgs() << "TrueBiasedSelects ";
12780b57cec5SDimitry Andric         for (SelectInst *SI : Scope->TrueBiasedSelects) {
12790b57cec5SDimitry Andric           dbgs() << *SI << ", ";
12800b57cec5SDimitry Andric         }
12810b57cec5SDimitry Andric         dbgs() << "\n";
12820b57cec5SDimitry Andric         dbgs() << "FalseBiasedSelects ";
12830b57cec5SDimitry Andric         for (SelectInst *SI : Scope->FalseBiasedSelects) {
12840b57cec5SDimitry Andric           dbgs() << *SI << ", ";
12850b57cec5SDimitry Andric         }
12860b57cec5SDimitry Andric         dbgs() << "\n";);
12870b57cec5SDimitry Andric   }
12880b57cec5SDimitry Andric }
12890b57cec5SDimitry Andric 
12900b57cec5SDimitry Andric void CHR::classifyBiasedScopes(CHRScope *Scope, CHRScope *OutermostScope) {
12910b57cec5SDimitry Andric   for (RegInfo &RI : Scope->RegInfos) {
12920b57cec5SDimitry Andric     if (RI.HasBranch) {
12930b57cec5SDimitry Andric       Region *R = RI.R;
1294e8d8bef9SDimitry Andric       if (TrueBiasedRegionsGlobal.contains(R))
12950b57cec5SDimitry Andric         OutermostScope->TrueBiasedRegions.insert(R);
1296e8d8bef9SDimitry Andric       else if (FalseBiasedRegionsGlobal.contains(R))
12970b57cec5SDimitry Andric         OutermostScope->FalseBiasedRegions.insert(R);
12980b57cec5SDimitry Andric       else
12990b57cec5SDimitry Andric         llvm_unreachable("Must be biased");
13000b57cec5SDimitry Andric     }
13010b57cec5SDimitry Andric     for (SelectInst *SI : RI.Selects) {
1302e8d8bef9SDimitry Andric       if (TrueBiasedSelectsGlobal.contains(SI))
13030b57cec5SDimitry Andric         OutermostScope->TrueBiasedSelects.insert(SI);
1304e8d8bef9SDimitry Andric       else if (FalseBiasedSelectsGlobal.contains(SI))
13050b57cec5SDimitry Andric         OutermostScope->FalseBiasedSelects.insert(SI);
13060b57cec5SDimitry Andric       else
13070b57cec5SDimitry Andric         llvm_unreachable("Must be biased");
13080b57cec5SDimitry Andric     }
13090b57cec5SDimitry Andric   }
13100b57cec5SDimitry Andric   for (CHRScope *Sub : Scope->Subs) {
13110b57cec5SDimitry Andric     classifyBiasedScopes(Sub, OutermostScope);
13120b57cec5SDimitry Andric   }
13130b57cec5SDimitry Andric }
13140b57cec5SDimitry Andric 
13150b57cec5SDimitry Andric static bool hasAtLeastTwoBiasedBranches(CHRScope *Scope) {
13160b57cec5SDimitry Andric   unsigned NumBiased = Scope->TrueBiasedRegions.size() +
13170b57cec5SDimitry Andric                        Scope->FalseBiasedRegions.size() +
13180b57cec5SDimitry Andric                        Scope->TrueBiasedSelects.size() +
13190b57cec5SDimitry Andric                        Scope->FalseBiasedSelects.size();
13200b57cec5SDimitry Andric   return NumBiased >= CHRMergeThreshold;
13210b57cec5SDimitry Andric }
13220b57cec5SDimitry Andric 
13230b57cec5SDimitry Andric void CHR::filterScopes(SmallVectorImpl<CHRScope *> &Input,
13240b57cec5SDimitry Andric                        SmallVectorImpl<CHRScope *> &Output) {
13250b57cec5SDimitry Andric   for (CHRScope *Scope : Input) {
13260b57cec5SDimitry Andric     // Filter out the ones with only one region and no subs.
13270b57cec5SDimitry Andric     if (!hasAtLeastTwoBiasedBranches(Scope)) {
13280b57cec5SDimitry Andric       CHR_DEBUG(dbgs() << "Filtered out by biased branches truthy-regions "
13290b57cec5SDimitry Andric                 << Scope->TrueBiasedRegions.size()
13300b57cec5SDimitry Andric                 << " falsy-regions " << Scope->FalseBiasedRegions.size()
13310b57cec5SDimitry Andric                 << " true-selects " << Scope->TrueBiasedSelects.size()
13320b57cec5SDimitry Andric                 << " false-selects " << Scope->FalseBiasedSelects.size() << "\n");
13330b57cec5SDimitry Andric       ORE.emit([&]() {
13340b57cec5SDimitry Andric         return OptimizationRemarkMissed(
13350b57cec5SDimitry Andric             DEBUG_TYPE,
13360b57cec5SDimitry Andric             "DropScopeWithOneBranchOrSelect",
13370b57cec5SDimitry Andric             Scope->RegInfos[0].R->getEntry()->getTerminator())
13380b57cec5SDimitry Andric             << "Drop scope with < "
13390b57cec5SDimitry Andric             << ore::NV("CHRMergeThreshold", CHRMergeThreshold)
13400b57cec5SDimitry Andric             << " biased branch(es) or select(s)";
13410b57cec5SDimitry Andric       });
13420b57cec5SDimitry Andric       continue;
13430b57cec5SDimitry Andric     }
13440b57cec5SDimitry Andric     Output.push_back(Scope);
13450b57cec5SDimitry Andric   }
13460b57cec5SDimitry Andric }
13470b57cec5SDimitry Andric 
13480b57cec5SDimitry Andric void CHR::setCHRRegions(SmallVectorImpl<CHRScope *> &Input,
13490b57cec5SDimitry Andric                         SmallVectorImpl<CHRScope *> &Output) {
13500b57cec5SDimitry Andric   for (CHRScope *Scope : Input) {
13510b57cec5SDimitry Andric     assert(Scope->HoistStopMap.empty() && Scope->CHRRegions.empty() &&
13520b57cec5SDimitry Andric            "Empty");
13530b57cec5SDimitry Andric     setCHRRegions(Scope, Scope);
13540b57cec5SDimitry Andric     Output.push_back(Scope);
13550b57cec5SDimitry Andric     CHR_DEBUG(
13560b57cec5SDimitry Andric         dbgs() << "setCHRRegions HoistStopMap " << *Scope << "\n";
13570b57cec5SDimitry Andric         for (auto pair : Scope->HoistStopMap) {
13580b57cec5SDimitry Andric           Region *R = pair.first;
13590b57cec5SDimitry Andric           dbgs() << "Region " << R->getNameStr() << "\n";
13600b57cec5SDimitry Andric           for (Instruction *I : pair.second) {
13610b57cec5SDimitry Andric             dbgs() << "HoistStop " << *I << "\n";
13620b57cec5SDimitry Andric           }
13630b57cec5SDimitry Andric         }
13640b57cec5SDimitry Andric         dbgs() << "CHRRegions" << "\n";
13650b57cec5SDimitry Andric         for (RegInfo &RI : Scope->CHRRegions) {
13660b57cec5SDimitry Andric           dbgs() << RI.R->getNameStr() << "\n";
13670b57cec5SDimitry Andric         });
13680b57cec5SDimitry Andric   }
13690b57cec5SDimitry Andric }
13700b57cec5SDimitry Andric 
13710b57cec5SDimitry Andric void CHR::setCHRRegions(CHRScope *Scope, CHRScope *OutermostScope) {
13720b57cec5SDimitry Andric   DenseSet<Instruction *> Unhoistables;
13730b57cec5SDimitry Andric   // Put the biased selects in Unhoistables because they should stay where they
13740b57cec5SDimitry Andric   // are and constant-folded after CHR (in case one biased select or a branch
13750b57cec5SDimitry Andric   // can depend on another biased select.)
13760b57cec5SDimitry Andric   for (RegInfo &RI : Scope->RegInfos) {
13770b57cec5SDimitry Andric     for (SelectInst *SI : RI.Selects) {
13780b57cec5SDimitry Andric       Unhoistables.insert(SI);
13790b57cec5SDimitry Andric     }
13800b57cec5SDimitry Andric   }
13810b57cec5SDimitry Andric   Instruction *InsertPoint = OutermostScope->BranchInsertPoint;
13820b57cec5SDimitry Andric   for (RegInfo &RI : Scope->RegInfos) {
13830b57cec5SDimitry Andric     Region *R = RI.R;
13840b57cec5SDimitry Andric     DenseSet<Instruction *> HoistStops;
13850b57cec5SDimitry Andric     bool IsHoisted = false;
13860b57cec5SDimitry Andric     if (RI.HasBranch) {
1387e8d8bef9SDimitry Andric       assert((OutermostScope->TrueBiasedRegions.contains(R) ||
1388e8d8bef9SDimitry Andric               OutermostScope->FalseBiasedRegions.contains(R)) &&
13890b57cec5SDimitry Andric              "Must be truthy or falsy");
13900b57cec5SDimitry Andric       auto *BI = cast<BranchInst>(R->getEntry()->getTerminator());
13910b57cec5SDimitry Andric       // Note checkHoistValue fills in HoistStops.
13920b57cec5SDimitry Andric       DenseMap<Instruction *, bool> Visited;
13930b57cec5SDimitry Andric       bool IsHoistable = checkHoistValue(BI->getCondition(), InsertPoint, DT,
13940b57cec5SDimitry Andric                                          Unhoistables, &HoistStops, Visited);
13950b57cec5SDimitry Andric       assert(IsHoistable && "Must be hoistable");
13960b57cec5SDimitry Andric       (void)(IsHoistable);  // Unused in release build
13970b57cec5SDimitry Andric       IsHoisted = true;
13980b57cec5SDimitry Andric     }
13990b57cec5SDimitry Andric     for (SelectInst *SI : RI.Selects) {
1400e8d8bef9SDimitry Andric       assert((OutermostScope->TrueBiasedSelects.contains(SI) ||
1401e8d8bef9SDimitry Andric               OutermostScope->FalseBiasedSelects.contains(SI)) &&
14020b57cec5SDimitry Andric              "Must be true or false biased");
14030b57cec5SDimitry Andric       // Note checkHoistValue fills in HoistStops.
14040b57cec5SDimitry Andric       DenseMap<Instruction *, bool> Visited;
14050b57cec5SDimitry Andric       bool IsHoistable = checkHoistValue(SI->getCondition(), InsertPoint, DT,
14060b57cec5SDimitry Andric                                          Unhoistables, &HoistStops, Visited);
14070b57cec5SDimitry Andric       assert(IsHoistable && "Must be hoistable");
14080b57cec5SDimitry Andric       (void)(IsHoistable);  // Unused in release build
14090b57cec5SDimitry Andric       IsHoisted = true;
14100b57cec5SDimitry Andric     }
14110b57cec5SDimitry Andric     if (IsHoisted) {
14120b57cec5SDimitry Andric       OutermostScope->CHRRegions.push_back(RI);
14130b57cec5SDimitry Andric       OutermostScope->HoistStopMap[R] = HoistStops;
14140b57cec5SDimitry Andric     }
14150b57cec5SDimitry Andric   }
14160b57cec5SDimitry Andric   for (CHRScope *Sub : Scope->Subs)
14170b57cec5SDimitry Andric     setCHRRegions(Sub, OutermostScope);
14180b57cec5SDimitry Andric }
14190b57cec5SDimitry Andric 
14205ffd83dbSDimitry Andric static bool CHRScopeSorter(CHRScope *Scope1, CHRScope *Scope2) {
14210b57cec5SDimitry Andric   return Scope1->RegInfos[0].R->getDepth() < Scope2->RegInfos[0].R->getDepth();
14220b57cec5SDimitry Andric }
14230b57cec5SDimitry Andric 
14240b57cec5SDimitry Andric void CHR::sortScopes(SmallVectorImpl<CHRScope *> &Input,
14250b57cec5SDimitry Andric                      SmallVectorImpl<CHRScope *> &Output) {
14260b57cec5SDimitry Andric   Output.resize(Input.size());
14270b57cec5SDimitry Andric   llvm::copy(Input, Output.begin());
14280b57cec5SDimitry Andric   llvm::stable_sort(Output, CHRScopeSorter);
14290b57cec5SDimitry Andric }
14300b57cec5SDimitry Andric 
14310b57cec5SDimitry Andric // Return true if V is already hoisted or was hoisted (along with its operands)
14320b57cec5SDimitry Andric // to the insert point.
14330b57cec5SDimitry Andric static void hoistValue(Value *V, Instruction *HoistPoint, Region *R,
14340b57cec5SDimitry Andric                        HoistStopMapTy &HoistStopMap,
14350b57cec5SDimitry Andric                        DenseSet<Instruction *> &HoistedSet,
14360b57cec5SDimitry Andric                        DenseSet<PHINode *> &TrivialPHIs,
14370b57cec5SDimitry Andric                        DominatorTree &DT) {
14380b57cec5SDimitry Andric   auto IT = HoistStopMap.find(R);
14390b57cec5SDimitry Andric   assert(IT != HoistStopMap.end() && "Region must be in hoist stop map");
14400b57cec5SDimitry Andric   DenseSet<Instruction *> &HoistStops = IT->second;
14410b57cec5SDimitry Andric   if (auto *I = dyn_cast<Instruction>(V)) {
14420b57cec5SDimitry Andric     if (I == HoistPoint)
14430b57cec5SDimitry Andric       return;
14440b57cec5SDimitry Andric     if (HoistStops.count(I))
14450b57cec5SDimitry Andric       return;
14460b57cec5SDimitry Andric     if (auto *PN = dyn_cast<PHINode>(I))
14470b57cec5SDimitry Andric       if (TrivialPHIs.count(PN))
14480b57cec5SDimitry Andric         // The trivial phi inserted by the previous CHR scope could replace a
14490b57cec5SDimitry Andric         // non-phi in HoistStops. Note that since this phi is at the exit of a
14500b57cec5SDimitry Andric         // previous CHR scope, which dominates this scope, it's safe to stop
14510b57cec5SDimitry Andric         // hoisting there.
14520b57cec5SDimitry Andric         return;
14530b57cec5SDimitry Andric     if (HoistedSet.count(I))
14540b57cec5SDimitry Andric       // Already hoisted, return.
14550b57cec5SDimitry Andric       return;
14560b57cec5SDimitry Andric     assert(isHoistableInstructionType(I) && "Unhoistable instruction type");
14570b57cec5SDimitry Andric     assert(DT.getNode(I->getParent()) && "DT must contain I's block");
14580b57cec5SDimitry Andric     assert(DT.getNode(HoistPoint->getParent()) &&
14590b57cec5SDimitry Andric            "DT must contain HoistPoint block");
14600b57cec5SDimitry Andric     if (DT.dominates(I, HoistPoint))
14610b57cec5SDimitry Andric       // We are already above the hoist point. Stop here. This may be necessary
14620b57cec5SDimitry Andric       // when multiple scopes would independently hoist the same
14630b57cec5SDimitry Andric       // instruction. Since an outer (dominating) scope would hoist it to its
14640b57cec5SDimitry Andric       // entry before an inner (dominated) scope would to its entry, the inner
14650b57cec5SDimitry Andric       // scope may see the instruction already hoisted, in which case it
14660b57cec5SDimitry Andric       // potentially wrong for the inner scope to hoist it and could cause bad
14670b57cec5SDimitry Andric       // IR (non-dominating def), but safe to skip hoisting it instead because
14680b57cec5SDimitry Andric       // it's already in a block that dominates the inner scope.
14690b57cec5SDimitry Andric       return;
14700b57cec5SDimitry Andric     for (Value *Op : I->operands()) {
14710b57cec5SDimitry Andric       hoistValue(Op, HoistPoint, R, HoistStopMap, HoistedSet, TrivialPHIs, DT);
14720b57cec5SDimitry Andric     }
14730b57cec5SDimitry Andric     I->moveBefore(HoistPoint);
14740b57cec5SDimitry Andric     HoistedSet.insert(I);
14750b57cec5SDimitry Andric     CHR_DEBUG(dbgs() << "hoistValue " << *I << "\n");
14760b57cec5SDimitry Andric   }
14770b57cec5SDimitry Andric }
14780b57cec5SDimitry Andric 
14790b57cec5SDimitry Andric // Hoist the dependent condition values of the branches and the selects in the
14800b57cec5SDimitry Andric // scope to the insert point.
14810b57cec5SDimitry Andric static void hoistScopeConditions(CHRScope *Scope, Instruction *HoistPoint,
14820b57cec5SDimitry Andric                                  DenseSet<PHINode *> &TrivialPHIs,
14830b57cec5SDimitry Andric                                  DominatorTree &DT) {
14840b57cec5SDimitry Andric   DenseSet<Instruction *> HoistedSet;
14850b57cec5SDimitry Andric   for (const RegInfo &RI : Scope->CHRRegions) {
14860b57cec5SDimitry Andric     Region *R = RI.R;
14870b57cec5SDimitry Andric     bool IsTrueBiased = Scope->TrueBiasedRegions.count(R);
14880b57cec5SDimitry Andric     bool IsFalseBiased = Scope->FalseBiasedRegions.count(R);
14890b57cec5SDimitry Andric     if (RI.HasBranch && (IsTrueBiased || IsFalseBiased)) {
14900b57cec5SDimitry Andric       auto *BI = cast<BranchInst>(R->getEntry()->getTerminator());
14910b57cec5SDimitry Andric       hoistValue(BI->getCondition(), HoistPoint, R, Scope->HoistStopMap,
14920b57cec5SDimitry Andric                  HoistedSet, TrivialPHIs, DT);
14930b57cec5SDimitry Andric     }
14940b57cec5SDimitry Andric     for (SelectInst *SI : RI.Selects) {
14950b57cec5SDimitry Andric       bool IsTrueBiased = Scope->TrueBiasedSelects.count(SI);
14960b57cec5SDimitry Andric       bool IsFalseBiased = Scope->FalseBiasedSelects.count(SI);
14970b57cec5SDimitry Andric       if (!(IsTrueBiased || IsFalseBiased))
14980b57cec5SDimitry Andric         continue;
14990b57cec5SDimitry Andric       hoistValue(SI->getCondition(), HoistPoint, R, Scope->HoistStopMap,
15000b57cec5SDimitry Andric                  HoistedSet, TrivialPHIs, DT);
15010b57cec5SDimitry Andric     }
15020b57cec5SDimitry Andric   }
15030b57cec5SDimitry Andric }
15040b57cec5SDimitry Andric 
15050b57cec5SDimitry Andric // Negate the predicate if an ICmp if it's used only by branches or selects by
15060b57cec5SDimitry Andric // swapping the operands of the branches or the selects. Returns true if success.
15070b57cec5SDimitry Andric static bool negateICmpIfUsedByBranchOrSelectOnly(ICmpInst *ICmp,
15080b57cec5SDimitry Andric                                                  Instruction *ExcludedUser,
15090b57cec5SDimitry Andric                                                  CHRScope *Scope) {
15100b57cec5SDimitry Andric   for (User *U : ICmp->users()) {
15110b57cec5SDimitry Andric     if (U == ExcludedUser)
15120b57cec5SDimitry Andric       continue;
15130b57cec5SDimitry Andric     if (isa<BranchInst>(U) && cast<BranchInst>(U)->isConditional())
15140b57cec5SDimitry Andric       continue;
15150b57cec5SDimitry Andric     if (isa<SelectInst>(U) && cast<SelectInst>(U)->getCondition() == ICmp)
15160b57cec5SDimitry Andric       continue;
15170b57cec5SDimitry Andric     return false;
15180b57cec5SDimitry Andric   }
15190b57cec5SDimitry Andric   for (User *U : ICmp->users()) {
15200b57cec5SDimitry Andric     if (U == ExcludedUser)
15210b57cec5SDimitry Andric       continue;
15220b57cec5SDimitry Andric     if (auto *BI = dyn_cast<BranchInst>(U)) {
15230b57cec5SDimitry Andric       assert(BI->isConditional() && "Must be conditional");
15240b57cec5SDimitry Andric       BI->swapSuccessors();
15250b57cec5SDimitry Andric       // Don't need to swap this in terms of
15260b57cec5SDimitry Andric       // TrueBiasedRegions/FalseBiasedRegions because true-based/false-based
15270b57cec5SDimitry Andric       // mean whehter the branch is likely go into the if-then rather than
15280b57cec5SDimitry Andric       // successor0/successor1 and because we can tell which edge is the then or
15290b57cec5SDimitry Andric       // the else one by comparing the destination to the region exit block.
15300b57cec5SDimitry Andric       continue;
15310b57cec5SDimitry Andric     }
15320b57cec5SDimitry Andric     if (auto *SI = dyn_cast<SelectInst>(U)) {
15330b57cec5SDimitry Andric       // Swap operands
15348bcb0991SDimitry Andric       SI->swapValues();
15350b57cec5SDimitry Andric       SI->swapProfMetadata();
15360b57cec5SDimitry Andric       if (Scope->TrueBiasedSelects.count(SI)) {
1537349cc55cSDimitry Andric         assert(!Scope->FalseBiasedSelects.contains(SI) &&
15380b57cec5SDimitry Andric                "Must not be already in");
15390b57cec5SDimitry Andric         Scope->FalseBiasedSelects.insert(SI);
15400b57cec5SDimitry Andric       } else if (Scope->FalseBiasedSelects.count(SI)) {
1541349cc55cSDimitry Andric         assert(!Scope->TrueBiasedSelects.contains(SI) &&
15420b57cec5SDimitry Andric                "Must not be already in");
15430b57cec5SDimitry Andric         Scope->TrueBiasedSelects.insert(SI);
15440b57cec5SDimitry Andric       }
15450b57cec5SDimitry Andric       continue;
15460b57cec5SDimitry Andric     }
15470b57cec5SDimitry Andric     llvm_unreachable("Must be a branch or a select");
15480b57cec5SDimitry Andric   }
15490b57cec5SDimitry Andric   ICmp->setPredicate(CmpInst::getInversePredicate(ICmp->getPredicate()));
15500b57cec5SDimitry Andric   return true;
15510b57cec5SDimitry Andric }
15520b57cec5SDimitry Andric 
15530b57cec5SDimitry Andric // A helper for transformScopes. Insert a trivial phi at the scope exit block
15540b57cec5SDimitry Andric // for a value that's defined in the scope but used outside it (meaning it's
15550b57cec5SDimitry Andric // alive at the exit block).
15560b57cec5SDimitry Andric static void insertTrivialPHIs(CHRScope *Scope,
15570b57cec5SDimitry Andric                               BasicBlock *EntryBlock, BasicBlock *ExitBlock,
15580b57cec5SDimitry Andric                               DenseSet<PHINode *> &TrivialPHIs) {
15595ffd83dbSDimitry Andric   SmallSetVector<BasicBlock *, 8> BlocksInScope;
15600b57cec5SDimitry Andric   for (RegInfo &RI : Scope->RegInfos) {
15610b57cec5SDimitry Andric     for (BasicBlock *BB : RI.R->blocks()) { // This includes the blocks in the
15620b57cec5SDimitry Andric                                             // sub-Scopes.
15635ffd83dbSDimitry Andric       BlocksInScope.insert(BB);
15640b57cec5SDimitry Andric     }
15650b57cec5SDimitry Andric   }
15665ffd83dbSDimitry Andric   CHR_DEBUG({
15675ffd83dbSDimitry Andric     dbgs() << "Inserting redundant phis\n";
15685ffd83dbSDimitry Andric     for (BasicBlock *BB : BlocksInScope)
15690b57cec5SDimitry Andric       dbgs() << "BlockInScope " << BB->getName() << "\n";
15700b57cec5SDimitry Andric   });
15715ffd83dbSDimitry Andric   for (BasicBlock *BB : BlocksInScope) {
15720b57cec5SDimitry Andric     for (Instruction &I : *BB) {
15730b57cec5SDimitry Andric       SmallVector<Instruction *, 8> Users;
15740b57cec5SDimitry Andric       for (User *U : I.users()) {
15750b57cec5SDimitry Andric         if (auto *UI = dyn_cast<Instruction>(U)) {
1576349cc55cSDimitry Andric           if (!BlocksInScope.contains(UI->getParent()) &&
15770b57cec5SDimitry Andric               // Unless there's already a phi for I at the exit block.
15780b57cec5SDimitry Andric               !(isa<PHINode>(UI) && UI->getParent() == ExitBlock)) {
15790b57cec5SDimitry Andric             CHR_DEBUG(dbgs() << "V " << I << "\n");
15800b57cec5SDimitry Andric             CHR_DEBUG(dbgs() << "Used outside scope by user " << *UI << "\n");
15810b57cec5SDimitry Andric             Users.push_back(UI);
15820b57cec5SDimitry Andric           } else if (UI->getParent() == EntryBlock && isa<PHINode>(UI)) {
15830b57cec5SDimitry Andric             // There's a loop backedge from a block that's dominated by this
15840b57cec5SDimitry Andric             // scope to the entry block.
15850b57cec5SDimitry Andric             CHR_DEBUG(dbgs() << "V " << I << "\n");
15860b57cec5SDimitry Andric             CHR_DEBUG(dbgs()
15870b57cec5SDimitry Andric                       << "Used at entry block (for a back edge) by a phi user "
15880b57cec5SDimitry Andric                       << *UI << "\n");
15890b57cec5SDimitry Andric             Users.push_back(UI);
15900b57cec5SDimitry Andric           }
15910b57cec5SDimitry Andric         }
15920b57cec5SDimitry Andric       }
15930b57cec5SDimitry Andric       if (Users.size() > 0) {
15940b57cec5SDimitry Andric         // Insert a trivial phi for I (phi [&I, P0], [&I, P1], ...) at
15950b57cec5SDimitry Andric         // ExitBlock. Replace I with the new phi in UI unless UI is another
15960b57cec5SDimitry Andric         // phi at ExitBlock.
15975f757f3fSDimitry Andric         PHINode *PN = PHINode::Create(I.getType(), pred_size(ExitBlock), "");
15985f757f3fSDimitry Andric         PN->insertBefore(ExitBlock->begin());
15990b57cec5SDimitry Andric         for (BasicBlock *Pred : predecessors(ExitBlock)) {
16000b57cec5SDimitry Andric           PN->addIncoming(&I, Pred);
16010b57cec5SDimitry Andric         }
16020b57cec5SDimitry Andric         TrivialPHIs.insert(PN);
16030b57cec5SDimitry Andric         CHR_DEBUG(dbgs() << "Insert phi " << *PN << "\n");
16040b57cec5SDimitry Andric         for (Instruction *UI : Users) {
16050b57cec5SDimitry Andric           for (unsigned J = 0, NumOps = UI->getNumOperands(); J < NumOps; ++J) {
16060b57cec5SDimitry Andric             if (UI->getOperand(J) == &I) {
16070b57cec5SDimitry Andric               UI->setOperand(J, PN);
16080b57cec5SDimitry Andric             }
16090b57cec5SDimitry Andric           }
16100b57cec5SDimitry Andric           CHR_DEBUG(dbgs() << "Updated user " << *UI << "\n");
16110b57cec5SDimitry Andric         }
16120b57cec5SDimitry Andric       }
16130b57cec5SDimitry Andric     }
16140b57cec5SDimitry Andric   }
16150b57cec5SDimitry Andric }
16160b57cec5SDimitry Andric 
16170b57cec5SDimitry Andric // Assert that all the CHR regions of the scope have a biased branch or select.
16180b57cec5SDimitry Andric static void LLVM_ATTRIBUTE_UNUSED
16190b57cec5SDimitry Andric assertCHRRegionsHaveBiasedBranchOrSelect(CHRScope *Scope) {
16200b57cec5SDimitry Andric #ifndef NDEBUG
16210b57cec5SDimitry Andric   auto HasBiasedBranchOrSelect = [](RegInfo &RI, CHRScope *Scope) {
16220b57cec5SDimitry Andric     if (Scope->TrueBiasedRegions.count(RI.R) ||
16230b57cec5SDimitry Andric         Scope->FalseBiasedRegions.count(RI.R))
16240b57cec5SDimitry Andric       return true;
16250b57cec5SDimitry Andric     for (SelectInst *SI : RI.Selects)
16260b57cec5SDimitry Andric       if (Scope->TrueBiasedSelects.count(SI) ||
16270b57cec5SDimitry Andric           Scope->FalseBiasedSelects.count(SI))
16280b57cec5SDimitry Andric         return true;
16290b57cec5SDimitry Andric     return false;
16300b57cec5SDimitry Andric   };
16310b57cec5SDimitry Andric   for (RegInfo &RI : Scope->CHRRegions) {
16320b57cec5SDimitry Andric     assert(HasBiasedBranchOrSelect(RI, Scope) &&
16330b57cec5SDimitry Andric            "Must have biased branch or select");
16340b57cec5SDimitry Andric   }
16350b57cec5SDimitry Andric #endif
16360b57cec5SDimitry Andric }
16370b57cec5SDimitry Andric 
16380b57cec5SDimitry Andric // Assert that all the condition values of the biased branches and selects have
16390b57cec5SDimitry Andric // been hoisted to the pre-entry block or outside of the scope.
16400b57cec5SDimitry Andric static void LLVM_ATTRIBUTE_UNUSED assertBranchOrSelectConditionHoisted(
16410b57cec5SDimitry Andric     CHRScope *Scope, BasicBlock *PreEntryBlock) {
16420b57cec5SDimitry Andric   CHR_DEBUG(dbgs() << "Biased regions condition values \n");
16430b57cec5SDimitry Andric   for (RegInfo &RI : Scope->CHRRegions) {
16440b57cec5SDimitry Andric     Region *R = RI.R;
16450b57cec5SDimitry Andric     bool IsTrueBiased = Scope->TrueBiasedRegions.count(R);
16460b57cec5SDimitry Andric     bool IsFalseBiased = Scope->FalseBiasedRegions.count(R);
16470b57cec5SDimitry Andric     if (RI.HasBranch && (IsTrueBiased || IsFalseBiased)) {
16480b57cec5SDimitry Andric       auto *BI = cast<BranchInst>(R->getEntry()->getTerminator());
16490b57cec5SDimitry Andric       Value *V = BI->getCondition();
16500b57cec5SDimitry Andric       CHR_DEBUG(dbgs() << *V << "\n");
16510b57cec5SDimitry Andric       if (auto *I = dyn_cast<Instruction>(V)) {
16520b57cec5SDimitry Andric         (void)(I); // Unused in release build.
16530b57cec5SDimitry Andric         assert((I->getParent() == PreEntryBlock ||
16540b57cec5SDimitry Andric                 !Scope->contains(I)) &&
16550b57cec5SDimitry Andric                "Must have been hoisted to PreEntryBlock or outside the scope");
16560b57cec5SDimitry Andric       }
16570b57cec5SDimitry Andric     }
16580b57cec5SDimitry Andric     for (SelectInst *SI : RI.Selects) {
16590b57cec5SDimitry Andric       bool IsTrueBiased = Scope->TrueBiasedSelects.count(SI);
16600b57cec5SDimitry Andric       bool IsFalseBiased = Scope->FalseBiasedSelects.count(SI);
16610b57cec5SDimitry Andric       if (!(IsTrueBiased || IsFalseBiased))
16620b57cec5SDimitry Andric         continue;
16630b57cec5SDimitry Andric       Value *V = SI->getCondition();
16640b57cec5SDimitry Andric       CHR_DEBUG(dbgs() << *V << "\n");
16650b57cec5SDimitry Andric       if (auto *I = dyn_cast<Instruction>(V)) {
16660b57cec5SDimitry Andric         (void)(I); // Unused in release build.
16670b57cec5SDimitry Andric         assert((I->getParent() == PreEntryBlock ||
16680b57cec5SDimitry Andric                 !Scope->contains(I)) &&
16690b57cec5SDimitry Andric                "Must have been hoisted to PreEntryBlock or outside the scope");
16700b57cec5SDimitry Andric       }
16710b57cec5SDimitry Andric     }
16720b57cec5SDimitry Andric   }
16730b57cec5SDimitry Andric }
16740b57cec5SDimitry Andric 
16750b57cec5SDimitry Andric void CHR::transformScopes(CHRScope *Scope, DenseSet<PHINode *> &TrivialPHIs) {
16760b57cec5SDimitry Andric   CHR_DEBUG(dbgs() << "transformScopes " << *Scope << "\n");
16770b57cec5SDimitry Andric 
16780b57cec5SDimitry Andric   assert(Scope->RegInfos.size() >= 1 && "Should have at least one Region");
1679bdd1243dSDimitry Andric 
1680bdd1243dSDimitry Andric   for (RegInfo &RI : Scope->RegInfos) {
1681bdd1243dSDimitry Andric     const Region *R = RI.R;
1682bdd1243dSDimitry Andric     unsigned Duplication = getRegionDuplicationCount(R);
1683bdd1243dSDimitry Andric     CHR_DEBUG(dbgs() << "Dup count for R=" << R << "  is " << Duplication
1684bdd1243dSDimitry Andric                      << "\n");
1685bdd1243dSDimitry Andric     if (Duplication >= CHRDupThreshsold) {
1686bdd1243dSDimitry Andric       CHR_DEBUG(dbgs() << "Reached the dup threshold of " << Duplication
1687bdd1243dSDimitry Andric                        << " for this region");
1688bdd1243dSDimitry Andric       ORE.emit([&]() {
1689bdd1243dSDimitry Andric         return OptimizationRemarkMissed(DEBUG_TYPE, "DupThresholdReached",
1690bdd1243dSDimitry Andric                                         R->getEntry()->getTerminator())
1691bdd1243dSDimitry Andric                << "Reached the duplication threshold for the region";
1692bdd1243dSDimitry Andric       });
1693bdd1243dSDimitry Andric       return;
1694bdd1243dSDimitry Andric     }
1695bdd1243dSDimitry Andric   }
1696bdd1243dSDimitry Andric   for (RegInfo &RI : Scope->RegInfos) {
1697bdd1243dSDimitry Andric     DuplicationCount[RI.R]++;
1698bdd1243dSDimitry Andric   }
1699bdd1243dSDimitry Andric 
17000b57cec5SDimitry Andric   Region *FirstRegion = Scope->RegInfos[0].R;
17010b57cec5SDimitry Andric   BasicBlock *EntryBlock = FirstRegion->getEntry();
17020b57cec5SDimitry Andric   Region *LastRegion = Scope->RegInfos[Scope->RegInfos.size() - 1].R;
17030b57cec5SDimitry Andric   BasicBlock *ExitBlock = LastRegion->getExit();
1704bdd1243dSDimitry Andric   std::optional<uint64_t> ProfileCount = BFI.getBlockProfileCount(EntryBlock);
17050b57cec5SDimitry Andric 
17060b57cec5SDimitry Andric   if (ExitBlock) {
17070b57cec5SDimitry Andric     // Insert a trivial phi at the exit block (where the CHR hot path and the
17080b57cec5SDimitry Andric     // cold path merges) for a value that's defined in the scope but used
17090b57cec5SDimitry Andric     // outside it (meaning it's alive at the exit block). We will add the
17100b57cec5SDimitry Andric     // incoming values for the CHR cold paths to it below. Without this, we'd
17110b57cec5SDimitry Andric     // miss updating phi's for such values unless there happens to already be a
17120b57cec5SDimitry Andric     // phi for that value there.
17130b57cec5SDimitry Andric     insertTrivialPHIs(Scope, EntryBlock, ExitBlock, TrivialPHIs);
17140b57cec5SDimitry Andric   }
17150b57cec5SDimitry Andric 
17160b57cec5SDimitry Andric   // Split the entry block of the first region. The new block becomes the new
17170b57cec5SDimitry Andric   // entry block of the first region. The old entry block becomes the block to
17180b57cec5SDimitry Andric   // insert the CHR branch into. Note DT gets updated. Since DT gets updated
17190b57cec5SDimitry Andric   // through the split, we update the entry of the first region after the split,
17200b57cec5SDimitry Andric   // and Region only points to the entry and the exit blocks, rather than
17210b57cec5SDimitry Andric   // keeping everything in a list or set, the blocks membership and the
17220b57cec5SDimitry Andric   // entry/exit blocks of the region are still valid after the split.
17230b57cec5SDimitry Andric   CHR_DEBUG(dbgs() << "Splitting entry block " << EntryBlock->getName()
17240b57cec5SDimitry Andric             << " at " << *Scope->BranchInsertPoint << "\n");
17250b57cec5SDimitry Andric   BasicBlock *NewEntryBlock =
17260b57cec5SDimitry Andric       SplitBlock(EntryBlock, Scope->BranchInsertPoint, &DT);
17270b57cec5SDimitry Andric   assert(NewEntryBlock->getSinglePredecessor() == EntryBlock &&
17280b57cec5SDimitry Andric          "NewEntryBlock's only pred must be EntryBlock");
17290b57cec5SDimitry Andric   FirstRegion->replaceEntryRecursive(NewEntryBlock);
17300b57cec5SDimitry Andric   BasicBlock *PreEntryBlock = EntryBlock;
17310b57cec5SDimitry Andric 
17320b57cec5SDimitry Andric   ValueToValueMapTy VMap;
17330b57cec5SDimitry Andric   // Clone the blocks in the scope (excluding the PreEntryBlock) to split into a
17340b57cec5SDimitry Andric   // hot path (originals) and a cold path (clones) and update the PHIs at the
17350b57cec5SDimitry Andric   // exit block.
17360b57cec5SDimitry Andric   cloneScopeBlocks(Scope, PreEntryBlock, ExitBlock, LastRegion, VMap);
17370b57cec5SDimitry Andric 
17380b57cec5SDimitry Andric   // Replace the old (placeholder) branch with the new (merged) conditional
17390b57cec5SDimitry Andric   // branch.
17400b57cec5SDimitry Andric   BranchInst *MergedBr = createMergedBranch(PreEntryBlock, EntryBlock,
17410b57cec5SDimitry Andric                                             NewEntryBlock, VMap);
17420b57cec5SDimitry Andric 
17430b57cec5SDimitry Andric #ifndef NDEBUG
17440b57cec5SDimitry Andric   assertCHRRegionsHaveBiasedBranchOrSelect(Scope);
17450b57cec5SDimitry Andric #endif
17460b57cec5SDimitry Andric 
17470b57cec5SDimitry Andric   // Hoist the conditional values of the branches/selects.
17480b57cec5SDimitry Andric   hoistScopeConditions(Scope, PreEntryBlock->getTerminator(), TrivialPHIs, DT);
17490b57cec5SDimitry Andric 
17500b57cec5SDimitry Andric #ifndef NDEBUG
17510b57cec5SDimitry Andric   assertBranchOrSelectConditionHoisted(Scope, PreEntryBlock);
17520b57cec5SDimitry Andric #endif
17530b57cec5SDimitry Andric 
17540b57cec5SDimitry Andric   // Create the combined branch condition and constant-fold the branches/selects
17550b57cec5SDimitry Andric   // in the hot path.
17560b57cec5SDimitry Andric   fixupBranchesAndSelects(Scope, PreEntryBlock, MergedBr,
175781ad6265SDimitry Andric                           ProfileCount.value_or(0));
17580b57cec5SDimitry Andric }
17590b57cec5SDimitry Andric 
17600b57cec5SDimitry Andric // A helper for transformScopes. Clone the blocks in the scope (excluding the
17610b57cec5SDimitry Andric // PreEntryBlock) to split into a hot path and a cold path and update the PHIs
17620b57cec5SDimitry Andric // at the exit block.
17630b57cec5SDimitry Andric void CHR::cloneScopeBlocks(CHRScope *Scope,
17640b57cec5SDimitry Andric                            BasicBlock *PreEntryBlock,
17650b57cec5SDimitry Andric                            BasicBlock *ExitBlock,
17660b57cec5SDimitry Andric                            Region *LastRegion,
17670b57cec5SDimitry Andric                            ValueToValueMapTy &VMap) {
17680b57cec5SDimitry Andric   // Clone all the blocks. The original blocks will be the hot-path
17690b57cec5SDimitry Andric   // CHR-optimized code and the cloned blocks will be the original unoptimized
17700b57cec5SDimitry Andric   // code. This is so that the block pointers from the
17710b57cec5SDimitry Andric   // CHRScope/Region/RegionInfo can stay valid in pointing to the hot-path code
17720b57cec5SDimitry Andric   // which CHR should apply to.
17730b57cec5SDimitry Andric   SmallVector<BasicBlock*, 8> NewBlocks;
17740b57cec5SDimitry Andric   for (RegInfo &RI : Scope->RegInfos)
17750b57cec5SDimitry Andric     for (BasicBlock *BB : RI.R->blocks()) { // This includes the blocks in the
17760b57cec5SDimitry Andric                                             // sub-Scopes.
17770b57cec5SDimitry Andric       assert(BB != PreEntryBlock && "Don't copy the preetntry block");
17780b57cec5SDimitry Andric       BasicBlock *NewBB = CloneBasicBlock(BB, VMap, ".nonchr", &F);
17790b57cec5SDimitry Andric       NewBlocks.push_back(NewBB);
17800b57cec5SDimitry Andric       VMap[BB] = NewBB;
17818a4dda33SDimitry Andric 
17828a4dda33SDimitry Andric       // Unreachable predecessors will not be cloned and will not have an edge
17838a4dda33SDimitry Andric       // to the cloned block. As such, also remove them from any phi nodes.
17848a4dda33SDimitry Andric       for (PHINode &PN : make_early_inc_range(NewBB->phis()))
17855f757f3fSDimitry Andric         PN.removeIncomingValueIf([&](unsigned Idx) {
17865f757f3fSDimitry Andric           return !DT.isReachableFromEntry(PN.getIncomingBlock(Idx));
17875f757f3fSDimitry Andric         });
17880b57cec5SDimitry Andric     }
17890b57cec5SDimitry Andric 
17900b57cec5SDimitry Andric   // Place the cloned blocks right after the original blocks (right before the
17910b57cec5SDimitry Andric   // exit block of.)
17920b57cec5SDimitry Andric   if (ExitBlock)
1793bdd1243dSDimitry Andric     F.splice(ExitBlock->getIterator(), &F, NewBlocks[0]->getIterator(),
1794bdd1243dSDimitry Andric              F.end());
17950b57cec5SDimitry Andric 
17960b57cec5SDimitry Andric   // Update the cloned blocks/instructions to refer to themselves.
1797bdd1243dSDimitry Andric   for (BasicBlock *NewBB : NewBlocks)
1798bdd1243dSDimitry Andric     for (Instruction &I : *NewBB)
17990b57cec5SDimitry Andric       RemapInstruction(&I, VMap,
18000b57cec5SDimitry Andric                        RF_NoModuleLevelChanges | RF_IgnoreMissingLocals);
18010b57cec5SDimitry Andric 
18020b57cec5SDimitry Andric   // Add the cloned blocks to the PHIs of the exit blocks. ExitBlock is null for
18030b57cec5SDimitry Andric   // the top-level region but we don't need to add PHIs. The trivial PHIs
18040b57cec5SDimitry Andric   // inserted above will be updated here.
18050b57cec5SDimitry Andric   if (ExitBlock)
18060b57cec5SDimitry Andric     for (PHINode &PN : ExitBlock->phis())
18070b57cec5SDimitry Andric       for (unsigned I = 0, NumOps = PN.getNumIncomingValues(); I < NumOps;
18080b57cec5SDimitry Andric            ++I) {
18090b57cec5SDimitry Andric         BasicBlock *Pred = PN.getIncomingBlock(I);
18100b57cec5SDimitry Andric         if (LastRegion->contains(Pred)) {
18110b57cec5SDimitry Andric           Value *V = PN.getIncomingValue(I);
18120b57cec5SDimitry Andric           auto It = VMap.find(V);
18130b57cec5SDimitry Andric           if (It != VMap.end()) V = It->second;
18140b57cec5SDimitry Andric           assert(VMap.find(Pred) != VMap.end() && "Pred must have been cloned");
18150b57cec5SDimitry Andric           PN.addIncoming(V, cast<BasicBlock>(VMap[Pred]));
18160b57cec5SDimitry Andric         }
18170b57cec5SDimitry Andric       }
18180b57cec5SDimitry Andric }
18190b57cec5SDimitry Andric 
18200b57cec5SDimitry Andric // A helper for transformScope. Replace the old (placeholder) branch with the
18210b57cec5SDimitry Andric // new (merged) conditional branch.
18220b57cec5SDimitry Andric BranchInst *CHR::createMergedBranch(BasicBlock *PreEntryBlock,
18230b57cec5SDimitry Andric                                     BasicBlock *EntryBlock,
18240b57cec5SDimitry Andric                                     BasicBlock *NewEntryBlock,
18250b57cec5SDimitry Andric                                     ValueToValueMapTy &VMap) {
18260b57cec5SDimitry Andric   BranchInst *OldBR = cast<BranchInst>(PreEntryBlock->getTerminator());
18270b57cec5SDimitry Andric   assert(OldBR->isUnconditional() && OldBR->getSuccessor(0) == NewEntryBlock &&
18280b57cec5SDimitry Andric          "SplitBlock did not work correctly!");
18290b57cec5SDimitry Andric   assert(NewEntryBlock->getSinglePredecessor() == EntryBlock &&
18300b57cec5SDimitry Andric          "NewEntryBlock's only pred must be EntryBlock");
18310b57cec5SDimitry Andric   assert(VMap.find(NewEntryBlock) != VMap.end() &&
18320b57cec5SDimitry Andric          "NewEntryBlock must have been copied");
18330b57cec5SDimitry Andric   OldBR->dropAllReferences();
18340b57cec5SDimitry Andric   OldBR->eraseFromParent();
18350b57cec5SDimitry Andric   // The true predicate is a placeholder. It will be replaced later in
18360b57cec5SDimitry Andric   // fixupBranchesAndSelects().
18370b57cec5SDimitry Andric   BranchInst *NewBR = BranchInst::Create(NewEntryBlock,
18380b57cec5SDimitry Andric                                          cast<BasicBlock>(VMap[NewEntryBlock]),
18390b57cec5SDimitry Andric                                          ConstantInt::getTrue(F.getContext()));
1840bdd1243dSDimitry Andric   NewBR->insertInto(PreEntryBlock, PreEntryBlock->end());
18410b57cec5SDimitry Andric   assert(NewEntryBlock->getSinglePredecessor() == EntryBlock &&
18420b57cec5SDimitry Andric          "NewEntryBlock's only pred must be EntryBlock");
18430b57cec5SDimitry Andric   return NewBR;
18440b57cec5SDimitry Andric }
18450b57cec5SDimitry Andric 
18460b57cec5SDimitry Andric // A helper for transformScopes. Create the combined branch condition and
18470b57cec5SDimitry Andric // constant-fold the branches/selects in the hot path.
18480b57cec5SDimitry Andric void CHR::fixupBranchesAndSelects(CHRScope *Scope,
18490b57cec5SDimitry Andric                                   BasicBlock *PreEntryBlock,
18500b57cec5SDimitry Andric                                   BranchInst *MergedBR,
18510b57cec5SDimitry Andric                                   uint64_t ProfileCount) {
18520b57cec5SDimitry Andric   Value *MergedCondition = ConstantInt::getTrue(F.getContext());
18530b57cec5SDimitry Andric   BranchProbability CHRBranchBias(1, 1);
18540b57cec5SDimitry Andric   uint64_t NumCHRedBranches = 0;
18550b57cec5SDimitry Andric   IRBuilder<> IRB(PreEntryBlock->getTerminator());
18560b57cec5SDimitry Andric   for (RegInfo &RI : Scope->CHRRegions) {
18570b57cec5SDimitry Andric     Region *R = RI.R;
18580b57cec5SDimitry Andric     if (RI.HasBranch) {
18590b57cec5SDimitry Andric       fixupBranch(R, Scope, IRB, MergedCondition, CHRBranchBias);
18600b57cec5SDimitry Andric       ++NumCHRedBranches;
18610b57cec5SDimitry Andric     }
18620b57cec5SDimitry Andric     for (SelectInst *SI : RI.Selects) {
18630b57cec5SDimitry Andric       fixupSelect(SI, Scope, IRB, MergedCondition, CHRBranchBias);
18640b57cec5SDimitry Andric       ++NumCHRedBranches;
18650b57cec5SDimitry Andric     }
18660b57cec5SDimitry Andric   }
18670b57cec5SDimitry Andric   Stats.NumBranchesDelta += NumCHRedBranches - 1;
18680b57cec5SDimitry Andric   Stats.WeightedNumBranchesDelta += (NumCHRedBranches - 1) * ProfileCount;
18690b57cec5SDimitry Andric   ORE.emit([&]() {
18700b57cec5SDimitry Andric     return OptimizationRemark(DEBUG_TYPE,
18710b57cec5SDimitry Andric                               "CHR",
18720b57cec5SDimitry Andric                               // Refer to the hot (original) path
18730b57cec5SDimitry Andric                               MergedBR->getSuccessor(0)->getTerminator())
18740b57cec5SDimitry Andric         << "Merged " << ore::NV("NumCHRedBranches", NumCHRedBranches)
18750b57cec5SDimitry Andric         << " branches or selects";
18760b57cec5SDimitry Andric   });
18770b57cec5SDimitry Andric   MergedBR->setCondition(MergedCondition);
18785ffd83dbSDimitry Andric   uint32_t Weights[] = {
18795ffd83dbSDimitry Andric       static_cast<uint32_t>(CHRBranchBias.scale(1000)),
18805ffd83dbSDimitry Andric       static_cast<uint32_t>(CHRBranchBias.getCompl().scale(1000)),
18815ffd83dbSDimitry Andric   };
1882*0fca6ea1SDimitry Andric   setBranchWeights(*MergedBR, Weights, /*IsExpected=*/false);
18830b57cec5SDimitry Andric   CHR_DEBUG(dbgs() << "CHR branch bias " << Weights[0] << ":" << Weights[1]
18840b57cec5SDimitry Andric             << "\n");
18850b57cec5SDimitry Andric }
18860b57cec5SDimitry Andric 
18870b57cec5SDimitry Andric // A helper for fixupBranchesAndSelects. Add to the combined branch condition
18880b57cec5SDimitry Andric // and constant-fold a branch in the hot path.
18890b57cec5SDimitry Andric void CHR::fixupBranch(Region *R, CHRScope *Scope,
18900b57cec5SDimitry Andric                       IRBuilder<> &IRB,
18910b57cec5SDimitry Andric                       Value *&MergedCondition,
18920b57cec5SDimitry Andric                       BranchProbability &CHRBranchBias) {
18930b57cec5SDimitry Andric   bool IsTrueBiased = Scope->TrueBiasedRegions.count(R);
18940b57cec5SDimitry Andric   assert((IsTrueBiased || Scope->FalseBiasedRegions.count(R)) &&
18950b57cec5SDimitry Andric          "Must be truthy or falsy");
18960b57cec5SDimitry Andric   auto *BI = cast<BranchInst>(R->getEntry()->getTerminator());
189706c3fb27SDimitry Andric   assert(BranchBiasMap.contains(R) && "Must be in the bias map");
18980b57cec5SDimitry Andric   BranchProbability Bias = BranchBiasMap[R];
18990b57cec5SDimitry Andric   assert(Bias >= getCHRBiasThreshold() && "Must be highly biased");
19000b57cec5SDimitry Andric   // Take the min.
19010b57cec5SDimitry Andric   if (CHRBranchBias > Bias)
19020b57cec5SDimitry Andric     CHRBranchBias = Bias;
19030b57cec5SDimitry Andric   BasicBlock *IfThen = BI->getSuccessor(1);
19040b57cec5SDimitry Andric   BasicBlock *IfElse = BI->getSuccessor(0);
19050b57cec5SDimitry Andric   BasicBlock *RegionExitBlock = R->getExit();
19060b57cec5SDimitry Andric   assert(RegionExitBlock && "Null ExitBlock");
19070b57cec5SDimitry Andric   assert((IfThen == RegionExitBlock || IfElse == RegionExitBlock) &&
19080b57cec5SDimitry Andric          IfThen != IfElse && "Invariant from findScopes");
19090b57cec5SDimitry Andric   if (IfThen == RegionExitBlock) {
19100b57cec5SDimitry Andric     // Swap them so that IfThen means going into it and IfElse means skipping
19110b57cec5SDimitry Andric     // it.
19120b57cec5SDimitry Andric     std::swap(IfThen, IfElse);
19130b57cec5SDimitry Andric   }
19140b57cec5SDimitry Andric   CHR_DEBUG(dbgs() << "IfThen " << IfThen->getName()
19150b57cec5SDimitry Andric             << " IfElse " << IfElse->getName() << "\n");
19160b57cec5SDimitry Andric   Value *Cond = BI->getCondition();
19170b57cec5SDimitry Andric   BasicBlock *HotTarget = IsTrueBiased ? IfThen : IfElse;
19180b57cec5SDimitry Andric   bool ConditionTrue = HotTarget == BI->getSuccessor(0);
19190b57cec5SDimitry Andric   addToMergedCondition(ConditionTrue, Cond, BI, Scope, IRB,
19200b57cec5SDimitry Andric                        MergedCondition);
19210b57cec5SDimitry Andric   // Constant-fold the branch at ClonedEntryBlock.
19220b57cec5SDimitry Andric   assert(ConditionTrue == (HotTarget == BI->getSuccessor(0)) &&
19230b57cec5SDimitry Andric          "The successor shouldn't change");
19240b57cec5SDimitry Andric   Value *NewCondition = ConditionTrue ?
19250b57cec5SDimitry Andric                         ConstantInt::getTrue(F.getContext()) :
19260b57cec5SDimitry Andric                         ConstantInt::getFalse(F.getContext());
19270b57cec5SDimitry Andric   BI->setCondition(NewCondition);
19280b57cec5SDimitry Andric }
19290b57cec5SDimitry Andric 
19300b57cec5SDimitry Andric // A helper for fixupBranchesAndSelects. Add to the combined branch condition
19310b57cec5SDimitry Andric // and constant-fold a select in the hot path.
19320b57cec5SDimitry Andric void CHR::fixupSelect(SelectInst *SI, CHRScope *Scope,
19330b57cec5SDimitry Andric                       IRBuilder<> &IRB,
19340b57cec5SDimitry Andric                       Value *&MergedCondition,
19350b57cec5SDimitry Andric                       BranchProbability &CHRBranchBias) {
19360b57cec5SDimitry Andric   bool IsTrueBiased = Scope->TrueBiasedSelects.count(SI);
19370b57cec5SDimitry Andric   assert((IsTrueBiased ||
19380b57cec5SDimitry Andric           Scope->FalseBiasedSelects.count(SI)) && "Must be biased");
193906c3fb27SDimitry Andric   assert(SelectBiasMap.contains(SI) && "Must be in the bias map");
19400b57cec5SDimitry Andric   BranchProbability Bias = SelectBiasMap[SI];
19410b57cec5SDimitry Andric   assert(Bias >= getCHRBiasThreshold() && "Must be highly biased");
19420b57cec5SDimitry Andric   // Take the min.
19430b57cec5SDimitry Andric   if (CHRBranchBias > Bias)
19440b57cec5SDimitry Andric     CHRBranchBias = Bias;
19450b57cec5SDimitry Andric   Value *Cond = SI->getCondition();
19460b57cec5SDimitry Andric   addToMergedCondition(IsTrueBiased, Cond, SI, Scope, IRB,
19470b57cec5SDimitry Andric                        MergedCondition);
19480b57cec5SDimitry Andric   Value *NewCondition = IsTrueBiased ?
19490b57cec5SDimitry Andric                         ConstantInt::getTrue(F.getContext()) :
19500b57cec5SDimitry Andric                         ConstantInt::getFalse(F.getContext());
19510b57cec5SDimitry Andric   SI->setCondition(NewCondition);
19520b57cec5SDimitry Andric }
19530b57cec5SDimitry Andric 
19540b57cec5SDimitry Andric // A helper for fixupBranch/fixupSelect. Add a branch condition to the merged
19550b57cec5SDimitry Andric // condition.
19560b57cec5SDimitry Andric void CHR::addToMergedCondition(bool IsTrueBiased, Value *Cond,
195781ad6265SDimitry Andric                                Instruction *BranchOrSelect, CHRScope *Scope,
195881ad6265SDimitry Andric                                IRBuilder<> &IRB, Value *&MergedCondition) {
195981ad6265SDimitry Andric   if (!IsTrueBiased) {
19600b57cec5SDimitry Andric     // If Cond is an icmp and all users of V except for BranchOrSelect is a
19610b57cec5SDimitry Andric     // branch, negate the icmp predicate and swap the branch targets and avoid
19620b57cec5SDimitry Andric     // inserting an Xor to negate Cond.
196381ad6265SDimitry Andric     auto *ICmp = dyn_cast<ICmpInst>(Cond);
196481ad6265SDimitry Andric     if (!ICmp ||
196581ad6265SDimitry Andric         !negateICmpIfUsedByBranchOrSelectOnly(ICmp, BranchOrSelect, Scope))
196681ad6265SDimitry Andric       Cond = IRB.CreateXor(ConstantInt::getTrue(F.getContext()), Cond);
19670b57cec5SDimitry Andric   }
196881ad6265SDimitry Andric 
196906c3fb27SDimitry Andric   // Freeze potentially poisonous conditions.
197006c3fb27SDimitry Andric   if (!isGuaranteedNotToBeUndefOrPoison(Cond))
197181ad6265SDimitry Andric     Cond = IRB.CreateFreeze(Cond);
197281ad6265SDimitry Andric 
197381ad6265SDimitry Andric   // Use logical and to avoid propagating poison from later conditions.
197481ad6265SDimitry Andric   MergedCondition = IRB.CreateLogicalAnd(MergedCondition, Cond);
19750b57cec5SDimitry Andric }
19760b57cec5SDimitry Andric 
19770b57cec5SDimitry Andric void CHR::transformScopes(SmallVectorImpl<CHRScope *> &CHRScopes) {
19780b57cec5SDimitry Andric   unsigned I = 0;
19790b57cec5SDimitry Andric   DenseSet<PHINode *> TrivialPHIs;
19800b57cec5SDimitry Andric   for (CHRScope *Scope : CHRScopes) {
19810b57cec5SDimitry Andric     transformScopes(Scope, TrivialPHIs);
19820b57cec5SDimitry Andric     CHR_DEBUG(
19830b57cec5SDimitry Andric         std::ostringstream oss;
19840b57cec5SDimitry Andric         oss << " after transformScopes " << I++;
19850b57cec5SDimitry Andric         dumpIR(F, oss.str().c_str(), nullptr));
19860b57cec5SDimitry Andric     (void)I;
19870b57cec5SDimitry Andric   }
19880b57cec5SDimitry Andric }
19890b57cec5SDimitry Andric 
19900b57cec5SDimitry Andric static void LLVM_ATTRIBUTE_UNUSED
19910b57cec5SDimitry Andric dumpScopes(SmallVectorImpl<CHRScope *> &Scopes, const char *Label) {
19920b57cec5SDimitry Andric   dbgs() << Label << " " << Scopes.size() << "\n";
19930b57cec5SDimitry Andric   for (CHRScope *Scope : Scopes) {
19940b57cec5SDimitry Andric     dbgs() << *Scope << "\n";
19950b57cec5SDimitry Andric   }
19960b57cec5SDimitry Andric }
19970b57cec5SDimitry Andric 
19980b57cec5SDimitry Andric bool CHR::run() {
19990b57cec5SDimitry Andric   if (!shouldApply(F, PSI))
20000b57cec5SDimitry Andric     return false;
20010b57cec5SDimitry Andric 
20020b57cec5SDimitry Andric   CHR_DEBUG(dumpIR(F, "before", nullptr));
20030b57cec5SDimitry Andric 
20040b57cec5SDimitry Andric   bool Changed = false;
20050b57cec5SDimitry Andric   {
20060b57cec5SDimitry Andric     CHR_DEBUG(
20070b57cec5SDimitry Andric         dbgs() << "RegionInfo:\n";
20080b57cec5SDimitry Andric         RI.print(dbgs()));
20090b57cec5SDimitry Andric 
20100b57cec5SDimitry Andric     // Recursively traverse the region tree and find regions that have biased
20110b57cec5SDimitry Andric     // branches and/or selects and create scopes.
20120b57cec5SDimitry Andric     SmallVector<CHRScope *, 8> AllScopes;
20130b57cec5SDimitry Andric     findScopes(AllScopes);
20140b57cec5SDimitry Andric     CHR_DEBUG(dumpScopes(AllScopes, "All scopes"));
20150b57cec5SDimitry Andric 
2016bdd1243dSDimitry Andric     // Split the scopes if 1) the conditional values of the biased
20170b57cec5SDimitry Andric     // branches/selects of the inner/lower scope can't be hoisted up to the
20180b57cec5SDimitry Andric     // outermost/uppermost scope entry, or 2) the condition values of the biased
20190b57cec5SDimitry Andric     // branches/selects in a scope (including subscopes) don't share at least
20200b57cec5SDimitry Andric     // one common value.
20210b57cec5SDimitry Andric     SmallVector<CHRScope *, 8> SplitScopes;
20220b57cec5SDimitry Andric     splitScopes(AllScopes, SplitScopes);
20230b57cec5SDimitry Andric     CHR_DEBUG(dumpScopes(SplitScopes, "Split scopes"));
20240b57cec5SDimitry Andric 
20250b57cec5SDimitry Andric     // After splitting, set the biased regions and selects of a scope (a tree
20260b57cec5SDimitry Andric     // root) that include those of the subscopes.
20270b57cec5SDimitry Andric     classifyBiasedScopes(SplitScopes);
20280b57cec5SDimitry Andric     CHR_DEBUG(dbgs() << "Set per-scope bias " << SplitScopes.size() << "\n");
20290b57cec5SDimitry Andric 
20300b57cec5SDimitry Andric     // Filter out the scopes that has only one biased region or select (CHR
20310b57cec5SDimitry Andric     // isn't useful in such a case).
20320b57cec5SDimitry Andric     SmallVector<CHRScope *, 8> FilteredScopes;
20330b57cec5SDimitry Andric     filterScopes(SplitScopes, FilteredScopes);
20340b57cec5SDimitry Andric     CHR_DEBUG(dumpScopes(FilteredScopes, "Filtered scopes"));
20350b57cec5SDimitry Andric 
20360b57cec5SDimitry Andric     // Set the regions to be CHR'ed and their hoist stops for each scope.
20370b57cec5SDimitry Andric     SmallVector<CHRScope *, 8> SetScopes;
20380b57cec5SDimitry Andric     setCHRRegions(FilteredScopes, SetScopes);
20390b57cec5SDimitry Andric     CHR_DEBUG(dumpScopes(SetScopes, "Set CHR regions"));
20400b57cec5SDimitry Andric 
20410b57cec5SDimitry Andric     // Sort CHRScopes by the depth so that outer CHRScopes comes before inner
20420b57cec5SDimitry Andric     // ones. We need to apply CHR from outer to inner so that we apply CHR only
20430b57cec5SDimitry Andric     // to the hot path, rather than both hot and cold paths.
20440b57cec5SDimitry Andric     SmallVector<CHRScope *, 8> SortedScopes;
20450b57cec5SDimitry Andric     sortScopes(SetScopes, SortedScopes);
20460b57cec5SDimitry Andric     CHR_DEBUG(dumpScopes(SortedScopes, "Sorted scopes"));
20470b57cec5SDimitry Andric 
20480b57cec5SDimitry Andric     CHR_DEBUG(
20490b57cec5SDimitry Andric         dbgs() << "RegionInfo:\n";
20500b57cec5SDimitry Andric         RI.print(dbgs()));
20510b57cec5SDimitry Andric 
20520b57cec5SDimitry Andric     // Apply the CHR transformation.
20530b57cec5SDimitry Andric     if (!SortedScopes.empty()) {
20540b57cec5SDimitry Andric       transformScopes(SortedScopes);
20550b57cec5SDimitry Andric       Changed = true;
20560b57cec5SDimitry Andric     }
20570b57cec5SDimitry Andric   }
20580b57cec5SDimitry Andric 
20590b57cec5SDimitry Andric   if (Changed) {
20600b57cec5SDimitry Andric     CHR_DEBUG(dumpIR(F, "after", &Stats));
20610b57cec5SDimitry Andric     ORE.emit([&]() {
20620b57cec5SDimitry Andric       return OptimizationRemark(DEBUG_TYPE, "Stats", &F)
20630b57cec5SDimitry Andric           << ore::NV("Function", &F) << " "
20640b57cec5SDimitry Andric           << "Reduced the number of branches in hot paths by "
20650b57cec5SDimitry Andric           << ore::NV("NumBranchesDelta", Stats.NumBranchesDelta)
20660b57cec5SDimitry Andric           << " (static) and "
20670b57cec5SDimitry Andric           << ore::NV("WeightedNumBranchesDelta", Stats.WeightedNumBranchesDelta)
20680b57cec5SDimitry Andric           << " (weighted by PGO count)";
20690b57cec5SDimitry Andric     });
20700b57cec5SDimitry Andric   }
20710b57cec5SDimitry Andric 
20720b57cec5SDimitry Andric   return Changed;
20730b57cec5SDimitry Andric }
20740b57cec5SDimitry Andric 
20750b57cec5SDimitry Andric namespace llvm {
20760b57cec5SDimitry Andric 
20770b57cec5SDimitry Andric ControlHeightReductionPass::ControlHeightReductionPass() {
20780b57cec5SDimitry Andric   parseCHRFilterFiles();
20790b57cec5SDimitry Andric }
20800b57cec5SDimitry Andric 
20810b57cec5SDimitry Andric PreservedAnalyses ControlHeightReductionPass::run(
20820b57cec5SDimitry Andric     Function &F,
20830b57cec5SDimitry Andric     FunctionAnalysisManager &FAM) {
208406c3fb27SDimitry Andric   auto &MAMProxy = FAM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
208506c3fb27SDimitry Andric   auto PPSI = MAMProxy.getCachedResult<ProfileSummaryAnalysis>(*F.getParent());
208606c3fb27SDimitry Andric   // If there is no profile summary, we should not do CHR.
208706c3fb27SDimitry Andric   if (!PPSI || !PPSI->hasProfileSummary())
208806c3fb27SDimitry Andric     return PreservedAnalyses::all();
208906c3fb27SDimitry Andric   auto &PSI = *PPSI;
20900b57cec5SDimitry Andric   auto &BFI = FAM.getResult<BlockFrequencyAnalysis>(F);
20910b57cec5SDimitry Andric   auto &DT = FAM.getResult<DominatorTreeAnalysis>(F);
20920b57cec5SDimitry Andric   auto &RI = FAM.getResult<RegionInfoAnalysis>(F);
20930b57cec5SDimitry Andric   auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);
20940b57cec5SDimitry Andric   bool Changed = CHR(F, BFI, DT, PSI, RI, ORE).run();
20950b57cec5SDimitry Andric   if (!Changed)
20960b57cec5SDimitry Andric     return PreservedAnalyses::all();
2097fe6060f1SDimitry Andric   return PreservedAnalyses::none();
20980b57cec5SDimitry Andric }
20990b57cec5SDimitry Andric 
21000b57cec5SDimitry Andric } // namespace llvm
2101