1cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar//===-- Relooper.cpp - Top-level interface for WebAssembly ----*- C++ -*-===// 2cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar// 3cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar// The LLVM Compiler Infrastructure 4cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar// 5cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar// This file is distributed under the University of Illinois Open Source 6cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar// License. See LICENSE.TXT for details. 7cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar// 8cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar//===---------------------------------------------------------------------===// 9cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar/// 10cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar/// \file 11cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar/// \brief This implements the Relooper algorithm. This implementation includes 12cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar/// optimizations added since the original academic paper [1] was published. 13cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar/// 14cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar/// [1] Alon Zakai. 2011. Emscripten: an LLVM-to-JavaScript compiler. In 15cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar/// Proceedings of the ACM international conference companion on Object 16cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar/// oriented programming systems languages and applications companion 17cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar/// (SPLASH '11). ACM, New York, NY, USA, 301-312. DOI=10.1145/2048147.2048224 18cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar/// http://doi.acm.org/10.1145/2048147.2048224 19cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar/// 20cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar//===-------------------------------------------------------------------===// 21cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 22cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar#include "Relooper.h" 23cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar#include "WebAssembly.h" 24cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 25cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar#include "llvm/ADT/STLExtras.h" 26cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar#include "llvm/IR/CFG.h" 27cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar#include "llvm/IR/Function.h" 28cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar#include "llvm/Pass.h" 29cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar#include "llvm/Support/CommandLine.h" 30cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar#include "llvm/Support/Debug.h" 31cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar#include "llvm/Support/raw_ostream.h" 32cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 33cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar#include <cstring> 34cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar#include <cstdlib> 35cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar#include <functional> 36cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar#include <list> 37cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar#include <stack> 38cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar#include <string> 39cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 40cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar#define DEBUG_TYPE "relooper" 41cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 42cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainarusing namespace llvm; 43cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainarusing namespace Relooper; 44cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 45cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainarstatic cl::opt<int> RelooperSplittingFactor( 46cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar "relooper-splitting-factor", 47cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar cl::desc( 48cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar "How much to discount code size when deciding whether to split a node"), 49cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar cl::init(5)); 50cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 51cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainarstatic cl::opt<unsigned> RelooperMultipleSwitchThreshold( 52cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar "relooper-multiple-switch-threshold", 53cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar cl::desc( 54cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar "How many entries to allow in a multiple before we use a switch"), 55cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar cl::init(10)); 56cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 57cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainarstatic cl::opt<unsigned> RelooperNestingLimit( 58cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar "relooper-nesting-limit", 59cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar cl::desc( 60cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar "How much nesting is acceptable"), 61cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar cl::init(20)); 62cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 63cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 64cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainarnamespace { 65cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar/// 66cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar/// Implements the relooper algorithm for a function's blocks. 67cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar/// 68cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar/// Implementation details: The Relooper instance has 69cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar/// ownership of the blocks and shapes, and frees them when done. 70cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar/// 71cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainarstruct RelooperAlgorithm { 72cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar std::deque<Block *> Blocks; 73cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar std::deque<Shape *> Shapes; 74cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Shape *Root; 75cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar bool MinSize; 76cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar int BlockIdCounter; 77cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar int ShapeIdCounter; 78cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 79cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar RelooperAlgorithm(); 80cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar ~RelooperAlgorithm(); 81cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 82cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar void AddBlock(Block *New, int Id = -1); 83cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 84cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Calculates the shapes 85cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar void Calculate(Block *Entry); 86cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 87cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Sets us to try to minimize size 88cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar void SetMinSize(bool MinSize_) { MinSize = MinSize_; } 89cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar}; 90cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 91cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainarstruct RelooperAnalysis final : public FunctionPass { 92cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar static char ID; 93cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar RelooperAnalysis() : FunctionPass(ID) {} 94cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar const char *getPassName() const override { return "relooper"; } 95cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar void getAnalysisUsage(AnalysisUsage &AU) const override { 96cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar AU.setPreservesAll(); 97cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 98cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar bool runOnFunction(Function &F) override; 99cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar}; 100cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar} 101cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 102cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar// RelooperAnalysis 103cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 104cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainarchar RelooperAnalysis::ID = 0; 105cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga NainarFunctionPass *llvm::createWebAssemblyRelooper() { 106cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar return new RelooperAnalysis(); 107cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar} 108cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 109cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainarbool RelooperAnalysis::runOnFunction(Function &F) { 110cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar DEBUG(dbgs() << "Relooping function '" << F.getName() << "'\n"); 111cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar RelooperAlgorithm R; 112cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // FIXME: remove duplication between relooper's and LLVM's BBs. 113cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar std::map<const BasicBlock *, Block *> BB2B; 114cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar std::map<const Block *, const BasicBlock *> B2BB; 115cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const BasicBlock &BB : F) { 116cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // FIXME: getName is wrong here, Code is meant to represent amount of code. 117cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // FIXME: use BranchVarInit for switch. 118cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *B = new Block(BB.getName().str().data(), /*BranchVarInit=*/nullptr); 119cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar R.AddBlock(B); 120cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar assert(BB2B.find(&BB) == BB2B.end() && "Inserting the same block twice"); 121cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar assert(B2BB.find(B) == B2BB.end() && "Inserting the same block twice"); 122cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BB2B[&BB] = B; 123cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar B2BB[B] = &BB; 124cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 125cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (Block *B : R.Blocks) { 126cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar const BasicBlock *BB = B2BB[B]; 127cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const BasicBlock *Successor : successors(BB)) 128cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // FIXME: add branch's Condition and Code below. 129cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar B->AddBranchTo(BB2B[Successor], /*Condition=*/nullptr, /*Code=*/nullptr); 130cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 131cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar R.Calculate(BB2B[&F.getEntryBlock()]); 132cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar return false; // Analysis passes don't modify anything. 133cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar} 134cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 135cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar// Helpers 136cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 137cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainartypedef MapVector<Block *, BlockSet> BlockBlockSetMap; 138cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainartypedef std::list<Block *> BlockList; 139cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 140cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainartemplate <class T, class U> 141cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainarstatic bool contains(const T &container, const U &contained) { 142cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar return container.count(contained); 143cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar} 144cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 145cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 146cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar// Branch 147cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 148cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga NainarBranch::Branch(const char *ConditionInit, const char *CodeInit) 149cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar : Ancestor(nullptr), Labeled(true) { 150cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // FIXME: move from char* to LLVM data structures 151cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Condition = ConditionInit ? strdup(ConditionInit) : nullptr; 152cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Code = CodeInit ? strdup(CodeInit) : nullptr; 153cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar} 154cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 155cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga NainarBranch::~Branch() { 156cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // FIXME: move from char* to LLVM data structures 157cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar free(static_cast<void *>(const_cast<char *>(Condition))); 158cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar free(static_cast<void *>(const_cast<char *>(Code))); 159cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar} 160cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 161cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar// Block 162cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 163cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga NainarBlock::Block(const char *CodeInit, const char *BranchVarInit) 164cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar : Parent(nullptr), Id(-1), IsCheckedMultipleEntry(false) { 165cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // FIXME: move from char* to LLVM data structures 166cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Code = strdup(CodeInit); 167cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BranchVar = BranchVarInit ? strdup(BranchVarInit) : nullptr; 168cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar} 169cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 170cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga NainarBlock::~Block() { 171cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // FIXME: move from char* to LLVM data structures 172cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar free(static_cast<void *>(const_cast<char *>(Code))); 173cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar free(static_cast<void *>(const_cast<char *>(BranchVar))); 174cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar} 175cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 176cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainarvoid Block::AddBranchTo(Block *Target, const char *Condition, 177cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar const char *Code) { 178cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar assert(!contains(BranchesOut, Target) && 179cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar "cannot add more than one branch to the same target"); 180cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BranchesOut[Target] = make_unique<Branch>(Condition, Code); 181cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar} 182cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 183cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar// Relooper 184cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 185cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga NainarRelooperAlgorithm::RelooperAlgorithm() 186cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar : Root(nullptr), MinSize(false), BlockIdCounter(1), 187cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar ShapeIdCounter(0) { // block ID 0 is reserved for clearings 188cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar} 189cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 190cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga NainarRelooperAlgorithm::~RelooperAlgorithm() { 191cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (auto Curr : Blocks) 192cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar delete Curr; 193cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (auto Curr : Shapes) 194cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar delete Curr; 195cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar} 196cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 197cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainarvoid RelooperAlgorithm::AddBlock(Block *New, int Id) { 198cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar New->Id = Id == -1 ? BlockIdCounter++ : Id; 199cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Blocks.push_back(New); 200cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar} 201cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 202cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainarstruct RelooperRecursor { 203cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar RelooperAlgorithm *Parent; 204cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar RelooperRecursor(RelooperAlgorithm *ParentInit) : Parent(ParentInit) {} 205cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar}; 206cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 207cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainarvoid RelooperAlgorithm::Calculate(Block *Entry) { 208cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Scan and optimize the input 209cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar struct PreOptimizer : public RelooperRecursor { 210cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar PreOptimizer(RelooperAlgorithm *Parent) : RelooperRecursor(Parent) {} 211cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockSet Live; 212cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 213cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar void FindLive(Block *Root) { 214cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockList ToInvestigate; 215cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar ToInvestigate.push_back(Root); 216cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar while (!ToInvestigate.empty()) { 217cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *Curr = ToInvestigate.front(); 218cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar ToInvestigate.pop_front(); 219cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (contains(Live, Curr)) 220cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar continue; 221cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Live.insert(Curr); 222cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : Curr->BranchesOut) 223cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar ToInvestigate.push_back(iter.first); 224cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 225cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 226cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 227cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // If a block has multiple entries but no exits, and it is small enough, it 228cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // is useful to split it. A common example is a C++ function where 229cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // everything ends up at a final exit block and does some RAII cleanup. 230cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Without splitting, we will be forced to introduce labelled loops to 231cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // allow reaching the final block 232cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar void SplitDeadEnds() { 233cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar unsigned TotalCodeSize = 0; 234cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &Curr : Live) { 235cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar TotalCodeSize += strlen(Curr->Code); 236cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 237cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockSet Splits; 238cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockSet Removed; 239cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &Original : Live) { 240cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Original->BranchesIn.size() <= 1 || 241cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar !Original->BranchesOut.empty()) 242cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar continue; // only dead ends, for now 243cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (contains(Original->BranchesOut, Original)) 244cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar continue; // cannot split a looping node 245cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (strlen(Original->Code) * (Original->BranchesIn.size() - 1) > 246cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar TotalCodeSize / RelooperSplittingFactor) 247cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar continue; // if splitting increases raw code size by a significant 248cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // amount, abort 249cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Split the node (for simplicity, we replace all the blocks, even 250cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // though we could have reused the original) 251cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar DEBUG(dbgs() << " Splitting '" << Original->Code << "'\n"); 252cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &Prior : Original->BranchesIn) { 253cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *Split = new Block(Original->Code, Original->BranchVar); 254cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Parent->AddBlock(Split, Original->Id); 255cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Split->BranchesIn.insert(Prior); 256cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar std::unique_ptr<Branch> Details; 257cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Details.swap(Prior->BranchesOut[Original]); 258cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Prior->BranchesOut[Split] = make_unique<Branch>(Details->Condition, 259cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Details->Code); 260cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : Original->BranchesOut) { 261cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *Post = iter.first; 262cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Branch *Details = iter.second.get(); 263cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Split->BranchesOut[Post] = make_unique<Branch>(Details->Condition, 264cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Details->Code); 265cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Post->BranchesIn.insert(Split); 266cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 267cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Splits.insert(Split); 268cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Removed.insert(Original); 269cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 270cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : Original->BranchesOut) { 271cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *Post = iter.first; 272cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Post->BranchesIn.remove(Original); 273cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 274cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 275cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : Splits) 276cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Live.insert(iter); 277cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : Removed) 278cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Live.remove(iter); 279cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 280cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar }; 281cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar PreOptimizer Pre(this); 282cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Pre.FindLive(Entry); 283cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 284cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Add incoming branches from live blocks, ignoring dead code 285cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (unsigned i = 0; i < Blocks.size(); i++) { 286cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *Curr = Blocks[i]; 287cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (!contains(Pre.Live, Curr)) 288cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar continue; 289cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : Curr->BranchesOut) 290cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar iter.first->BranchesIn.insert(Curr); 291cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 292cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 293cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (!MinSize) 294cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Pre.SplitDeadEnds(); 295cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 296cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Recursively process the graph 297cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 298cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar struct Analyzer : public RelooperRecursor { 299cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Analyzer(RelooperAlgorithm *Parent) : RelooperRecursor(Parent) {} 300cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 301cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Add a shape to the list of shapes in this Relooper calculation 302cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar void Notice(Shape *New) { 303cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar New->Id = Parent->ShapeIdCounter++; 304cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Parent->Shapes.push_back(New); 305cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 306cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 307cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Create a list of entries from a block. If LimitTo is provided, only 308cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // results in that set will appear 309cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar void GetBlocksOut(Block *Source, BlockSet &Entries, 310cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockSet *LimitTo = nullptr) { 311cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : Source->BranchesOut) 312cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (!LimitTo || contains(*LimitTo, iter.first)) 313cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Entries.insert(iter.first); 314cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 315cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 316cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Converts/processes all branchings to a specific target 317cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar void Solipsize(Block *Target, Branch::FlowType Type, Shape *Ancestor, 318cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockSet &From) { 319cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar DEBUG(dbgs() << " Solipsize '" << Target->Code << "' type " << Type 320cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar << "\n"); 321cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (auto iter = Target->BranchesIn.begin(); 322cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar iter != Target->BranchesIn.end();) { 323cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *Prior = *iter; 324cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (!contains(From, Prior)) { 325cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar iter++; 326cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar continue; 327cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 328cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar std::unique_ptr<Branch> PriorOut; 329cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar PriorOut.swap(Prior->BranchesOut[Target]); 330cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar PriorOut->Ancestor = Ancestor; 331cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar PriorOut->Type = Type; 332cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (MultipleShape *Multiple = dyn_cast<MultipleShape>(Ancestor)) 333cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Multiple->Breaks++; // We are breaking out of this Multiple, so need a 334cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // loop 335cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar iter++; // carefully increment iter before erasing 336cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Target->BranchesIn.remove(Prior); 337cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Target->ProcessedBranchesIn.insert(Prior); 338cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Prior->ProcessedBranchesOut[Target].swap(PriorOut); 339cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 340cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 341cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 342cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Shape *MakeSimple(BlockSet &Blocks, Block *Inner, BlockSet &NextEntries) { 343cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar DEBUG(dbgs() << " MakeSimple inner block '" << Inner->Code << "'\n"); 344cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar SimpleShape *Simple = new SimpleShape; 345cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Notice(Simple); 346cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Simple->Inner = Inner; 347cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Inner->Parent = Simple; 348cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Blocks.size() > 1) { 349cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Blocks.remove(Inner); 350cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar GetBlocksOut(Inner, NextEntries, &Blocks); 351cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockSet JustInner; 352cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar JustInner.insert(Inner); 353cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : NextEntries) 354cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Solipsize(iter, Branch::Direct, Simple, JustInner); 355cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 356cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar return Simple; 357cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 358cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 359cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Shape *MakeLoop(BlockSet &Blocks, BlockSet &Entries, 360cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockSet &NextEntries) { 361cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Find the inner blocks in this loop. Proceed backwards from the entries 362cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // until 363cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // you reach a seen block, collecting as you go. 364cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockSet InnerBlocks; 365cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockSet Queue = Entries; 366cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar while (!Queue.empty()) { 367cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *Curr = *(Queue.begin()); 368cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Queue.remove(*Queue.begin()); 369cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (!contains(InnerBlocks, Curr)) { 370cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // This element is new, mark it as inner and remove from outer 371cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar InnerBlocks.insert(Curr); 372cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Blocks.remove(Curr); 373cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Add the elements prior to it 374cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : Curr->BranchesIn) 375cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Queue.insert(iter); 376cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 377cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 378cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar assert(!InnerBlocks.empty()); 379cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 380cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &Curr : InnerBlocks) { 381cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : Curr->BranchesOut) { 382cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *Possible = iter.first; 383cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (!contains(InnerBlocks, Possible)) 384cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar NextEntries.insert(Possible); 385cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 386cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 387cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 388cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar LoopShape *Loop = new LoopShape(); 389cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Notice(Loop); 390cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 391cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Solipsize the loop, replacing with break/continue and marking branches 392cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // as Processed (will not affect later calculations) 393cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // A. Branches to the loop entries become a continue to this shape 394cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : Entries) 395cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Solipsize(iter, Branch::Continue, Loop, InnerBlocks); 396cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // B. Branches to outside the loop (a next entry) become breaks on this 397cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // shape 398cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : NextEntries) 399cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Solipsize(iter, Branch::Break, Loop, InnerBlocks); 400cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Finish up 401cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Shape *Inner = Process(InnerBlocks, Entries, nullptr); 402cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Loop->Inner = Inner; 403cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar return Loop; 404cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 405cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 406cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // For each entry, find the independent group reachable by it. The 407cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // independent group is the entry itself, plus all the blocks it can 408cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // reach that cannot be directly reached by another entry. Note that we 409cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // ignore directly reaching the entry itself by another entry. 410cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // @param Ignore - previous blocks that are irrelevant 411cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar void FindIndependentGroups(BlockSet &Entries, 412cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockBlockSetMap &IndependentGroups, 413cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockSet *Ignore = nullptr) { 414cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar typedef std::map<Block *, Block *> BlockBlockMap; 415cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 416cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar struct HelperClass { 417cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockBlockSetMap &IndependentGroups; 418cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockBlockMap Ownership; // For each block, which entry it belongs to. 419cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // We have reached it from there. 420cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 421cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar HelperClass(BlockBlockSetMap &IndependentGroupsInit) 422cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar : IndependentGroups(IndependentGroupsInit) {} 423cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar void InvalidateWithChildren(Block *New) { 424cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Being in the list means you need to be invalidated 425cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockList ToInvalidate; 426cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar ToInvalidate.push_back(New); 427cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar while (!ToInvalidate.empty()) { 428cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *Invalidatee = ToInvalidate.front(); 429cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar ToInvalidate.pop_front(); 430cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *Owner = Ownership[Invalidatee]; 431cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Owner may have been invalidated, do not add to 432cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // IndependentGroups! 433cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (contains(IndependentGroups, Owner)) 434cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar IndependentGroups[Owner].remove(Invalidatee); 435cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Ownership[Invalidatee]) { // may have been seen before and 436cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // invalidated already 437cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Ownership[Invalidatee] = nullptr; 438cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : Invalidatee->BranchesOut) { 439cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *Target = iter.first; 440cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockBlockMap::iterator Known = Ownership.find(Target); 441cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Known != Ownership.end()) { 442cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *TargetOwner = Known->second; 443cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (TargetOwner) 444cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar ToInvalidate.push_back(Target); 445cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 446cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 447cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 448cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 449cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 450cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar }; 451cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar HelperClass Helper(IndependentGroups); 452cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 453cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // We flow out from each of the entries, simultaneously. 454cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // When we reach a new block, we add it as belonging to the one we got to 455cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // it from. 456cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // If we reach a new block that is already marked as belonging to someone, 457cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // it is reachable by two entries and is not valid for any of them. 458cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Remove it and all it can reach that have been visited. 459cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 460cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Being in the queue means we just added this item, and 461cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // we need to add its children 462cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockList Queue; 463cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &Entry : Entries) { 464cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Helper.Ownership[Entry] = Entry; 465cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar IndependentGroups[Entry].insert(Entry); 466cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Queue.push_back(Entry); 467cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 468cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar while (!Queue.empty()) { 469cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *Curr = Queue.front(); 470cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Queue.pop_front(); 471cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *Owner = Helper.Ownership[Curr]; // Curr must be in the ownership 472cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // map if we are in the queue 473cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (!Owner) 474cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar continue; // we have been invalidated meanwhile after being reached 475cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // from two entries 476cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Add all children 477cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : Curr->BranchesOut) { 478cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *New = iter.first; 479cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockBlockMap::iterator Known = Helper.Ownership.find(New); 480cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Known == Helper.Ownership.end()) { 481cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // New node. Add it, and put it in the queue 482cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Helper.Ownership[New] = Owner; 483cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar IndependentGroups[Owner].insert(New); 484cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Queue.push_back(New); 485cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar continue; 486cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 487cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *NewOwner = Known->second; 488cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (!NewOwner) 489cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar continue; // We reached an invalidated node 490cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (NewOwner != Owner) 491cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Invalidate this and all reachable that we have seen - we reached 492cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // this from two locations 493cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Helper.InvalidateWithChildren(New); 494cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // otherwise, we have the same owner, so do nothing 495cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 496cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 497cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 498cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Having processed all the interesting blocks, we remain with just one 499cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // potential issue: 500cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // If a->b, and a was invalidated, but then b was later reached by 501cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // someone else, we must invalidate b. To check for this, we go over all 502cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // elements in the independent groups, if an element has a parent which 503cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // does *not* have the same owner, we/ must remove it and all its 504cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // children. 505cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 506cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : Entries) { 507cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockSet &CurrGroup = IndependentGroups[iter]; 508cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockList ToInvalidate; 509cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : CurrGroup) { 510cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *Child = iter; 511cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : Child->BranchesIn) { 512cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *Parent = iter; 513cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Ignore && contains(*Ignore, Parent)) 514cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar continue; 515cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Helper.Ownership[Parent] != Helper.Ownership[Child]) 516cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar ToInvalidate.push_back(Child); 517cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 518cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 519cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar while (!ToInvalidate.empty()) { 520cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *Invalidatee = ToInvalidate.front(); 521cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar ToInvalidate.pop_front(); 522cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Helper.InvalidateWithChildren(Invalidatee); 523cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 524cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 525cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 526cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Remove empty groups 527cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : Entries) 528cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (IndependentGroups[iter].empty()) 529cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar IndependentGroups.erase(iter); 530cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 531cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 532cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Shape *MakeMultiple(BlockSet &Blocks, BlockSet &Entries, 533cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockBlockSetMap &IndependentGroups, Shape *Prev, 534cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockSet &NextEntries) { 535cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar bool Fused = isa<SimpleShape>(Prev); 536cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar MultipleShape *Multiple = new MultipleShape(); 537cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Notice(Multiple); 538cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockSet CurrEntries; 539cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (auto &iter : IndependentGroups) { 540cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *CurrEntry = iter.first; 541cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockSet &CurrBlocks = iter.second; 542cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Create inner block 543cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar CurrEntries.clear(); 544cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar CurrEntries.insert(CurrEntry); 545cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &CurrInner : CurrBlocks) { 546cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Remove the block from the remaining blocks 547cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Blocks.remove(CurrInner); 548cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Find new next entries and fix branches to them 549cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (auto iter = CurrInner->BranchesOut.begin(); 550cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar iter != CurrInner->BranchesOut.end();) { 551cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *CurrTarget = iter->first; 552cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar auto Next = iter; 553cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Next++; 554cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (!contains(CurrBlocks, CurrTarget)) { 555cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar NextEntries.insert(CurrTarget); 556cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Solipsize(CurrTarget, Branch::Break, Multiple, CurrBlocks); 557cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 558cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar iter = Next; // increment carefully because Solipsize can remove us 559cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 560cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 561cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Multiple->InnerMap[CurrEntry->Id] = 562cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Process(CurrBlocks, CurrEntries, nullptr); 563cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // If we are not fused, then our entries will actually be checked 564cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (!Fused) 565cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar CurrEntry->IsCheckedMultipleEntry = true; 566cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 567cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Add entries not handled as next entries, they are deferred 568cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &Entry : Entries) 569cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (!contains(IndependentGroups, Entry)) 570cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar NextEntries.insert(Entry); 571cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // The multiple has been created, we can decide how to implement it 572cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Multiple->InnerMap.size() >= RelooperMultipleSwitchThreshold) { 573cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Multiple->UseSwitch = true; 574cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Multiple->Breaks++; // switch captures breaks 575cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 576cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar return Multiple; 577cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 578cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 579cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Main function. 580cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Process a set of blocks with specified entries, returns a shape 581cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // The Make* functions receive a NextEntries. If they fill it with data, 582cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // those are the entries for the ->Next block on them, and the blocks 583cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // are what remains in Blocks (which Make* modify). In this way 584cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // we avoid recursing on Next (imagine a long chain of Simples, if we 585cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // recursed we could blow the stack). 586cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Shape *Process(BlockSet &Blocks, BlockSet &InitialEntries, Shape *Prev) { 587cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockSet *Entries = &InitialEntries; 588cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockSet TempEntries[2]; 589cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar int CurrTempIndex = 0; 590cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockSet *NextEntries; 591cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Shape *Ret = nullptr; 592cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 593cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar auto Make = [&](Shape *Temp) { 594cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Prev) 595cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Prev->Next = Temp; 596cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (!Ret) 597cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Ret = Temp; 598cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Prev = Temp; 599cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Entries = NextEntries; 600cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar }; 601cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 602cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar while (1) { 603cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar CurrTempIndex = 1 - CurrTempIndex; 604cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar NextEntries = &TempEntries[CurrTempIndex]; 605cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar NextEntries->clear(); 606cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 607cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Entries->empty()) 608cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar return Ret; 609cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Entries->size() == 1) { 610cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *Curr = *(Entries->begin()); 611cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Curr->BranchesIn.empty()) { 612cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // One entry, no looping ==> Simple 613cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Make(MakeSimple(Blocks, Curr, *NextEntries)); 614cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (NextEntries->empty()) 615cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar return Ret; 616cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar continue; 617cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 618cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // One entry, looping ==> Loop 619cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Make(MakeLoop(Blocks, *Entries, *NextEntries)); 620cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (NextEntries->empty()) 621cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar return Ret; 622cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar continue; 623cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 624cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 625cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // More than one entry, try to eliminate through a Multiple groups of 626cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // independent blocks from an entry/ies. It is important to remove 627cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // through multiples as opposed to looping since the former is more 628cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // performant. 629cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockBlockSetMap IndependentGroups; 630cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar FindIndependentGroups(*Entries, IndependentGroups); 631cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 632cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (!IndependentGroups.empty()) { 633cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // We can handle a group in a multiple if its entry cannot be reached 634cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // by another group. 635cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Note that it might be reachable by itself - a loop. But that is 636cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // fine, we will create a loop inside the multiple block (which 637cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // is the performant order to do it). 638cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (auto iter = IndependentGroups.begin(); 639cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar iter != IndependentGroups.end();) { 640cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *Entry = iter->first; 641cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockSet &Group = iter->second; 642cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar auto curr = iter++; // iterate carefully, we may delete 643cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (BlockSet::iterator iterBranch = Entry->BranchesIn.begin(); 644cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar iterBranch != Entry->BranchesIn.end(); iterBranch++) { 645cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *Origin = *iterBranch; 646cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (!contains(Group, Origin)) { 647cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Reached from outside the group, so we cannot handle this 648cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar IndependentGroups.erase(curr); 649cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar break; 650cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 651cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 652cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 653cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 654cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // As an optimization, if we have 2 independent groups, and one is a 655cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // small dead end, we can handle only that dead end. 656cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // The other then becomes a Next - without nesting in the code and 657cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // recursion in the analysis. 658cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // TODO: if the larger is the only dead end, handle that too 659cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // TODO: handle >2 groups 660cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // TODO: handle not just dead ends, but also that do not branch to the 661cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // NextEntries. However, must be careful there since we create a 662cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Next, and that Next can prevent eliminating a break (since we no 663cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // longer naturally reach the same place), which may necessitate a 664cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // one-time loop, which makes the unnesting pointless. 665cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (IndependentGroups.size() == 2) { 666cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Find the smaller one 667cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar auto iter = IndependentGroups.begin(); 668cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *SmallEntry = iter->first; 669cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar auto SmallSize = iter->second.size(); 670cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar iter++; 671cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *LargeEntry = iter->first; 672cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar auto LargeSize = iter->second.size(); 673cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (SmallSize != LargeSize) { // ignore the case where they are 674cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // identical - keep things symmetrical 675cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // there 676cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (SmallSize > LargeSize) { 677cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *Temp = SmallEntry; 678cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar SmallEntry = LargeEntry; 679cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar LargeEntry = Temp; // Note: we did not flip the Sizes too, they 680cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // are now invalid. TODO: use the smaller 681cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // size as a limit? 682cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 683cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Check if dead end 684cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar bool DeadEnd = true; 685cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockSet &SmallGroup = IndependentGroups[SmallEntry]; 686cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &Curr : SmallGroup) { 687cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : Curr->BranchesOut) { 688cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *Target = iter.first; 689cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (!contains(SmallGroup, Target)) { 690cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar DeadEnd = false; 691cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar break; 692cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 693cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 694cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (!DeadEnd) 695cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar break; 696cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 697cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (DeadEnd) 698cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar IndependentGroups.erase(LargeEntry); 699cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 700cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 701cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 702cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (!IndependentGroups.empty()) 703cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Some groups removable ==> Multiple 704cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Make(MakeMultiple(Blocks, *Entries, IndependentGroups, Prev, 705cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar *NextEntries)); 706cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (NextEntries->empty()) 707cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar return Ret; 708cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar continue; 709cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 710cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // No independent groups, must be loopable ==> Loop 711cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Make(MakeLoop(Blocks, *Entries, *NextEntries)); 712cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (NextEntries->empty()) 713cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar return Ret; 714cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar continue; 715cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 716cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 717cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar }; 718cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 719cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Main 720cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 721cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockSet AllBlocks; 722cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &Curr : Pre.Live) { 723cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar AllBlocks.insert(Curr); 724cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 725cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 726cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockSet Entries; 727cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Entries.insert(Entry); 728cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Root = Analyzer(this).Process(AllBlocks, Entries, nullptr); 729cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar assert(Root); 730cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 731cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar /// 732cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar /// Relooper post-optimizer 733cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar /// 734cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar struct PostOptimizer { 735cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar RelooperAlgorithm *Parent; 736cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar std::stack<Shape *> LoopStack; 737cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 738cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar PostOptimizer(RelooperAlgorithm *ParentInit) : Parent(ParentInit) {} 739cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 740cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar void ShapeSwitch(Shape* var, 741cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar std::function<void (SimpleShape*)> simple, 742cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar std::function<void (MultipleShape*)> multiple, 743cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar std::function<void (LoopShape*)> loop) { 744cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar switch (var->getKind()) { 745cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar case Shape::SK_Simple: { 746cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar simple(cast<SimpleShape>(var)); 747cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar break; 748cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 749cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar case Shape::SK_Multiple: { 750cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar multiple(cast<MultipleShape>(var)); 751cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar break; 752cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 753cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar case Shape::SK_Loop: { 754cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar loop(cast<LoopShape>(var)); 755cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar break; 756cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 757cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 758cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 759cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 760cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Find the blocks that natural control flow can get us directly to, or 761cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // through a multiple that we ignore 762cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar void FollowNaturalFlow(Shape *S, BlockSet &Out) { 763cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar ShapeSwitch(S, [&](SimpleShape* Simple) { 764cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Out.insert(Simple->Inner); 765cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar }, [&](MultipleShape* Multiple) { 766cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : Multiple->InnerMap) { 767cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar FollowNaturalFlow(iter.second, Out); 768cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 769cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar FollowNaturalFlow(Multiple->Next, Out); 770cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar }, [&](LoopShape* Loop) { 771cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar FollowNaturalFlow(Loop->Inner, Out); 772cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar }); 773cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 774cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 775cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar void FindNaturals(Shape *Root, Shape *Otherwise = nullptr) { 776cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Root->Next) { 777cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Root->Natural = Root->Next; 778cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar FindNaturals(Root->Next, Otherwise); 779cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } else { 780cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Root->Natural = Otherwise; 781cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 782cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 783cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar ShapeSwitch(Root, [](SimpleShape* Simple) { 784cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar }, [&](MultipleShape* Multiple) { 785cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : Multiple->InnerMap) { 786cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar FindNaturals(iter.second, Root->Natural); 787cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 788cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar }, [&](LoopShape* Loop){ 789cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar FindNaturals(Loop->Inner, Loop->Inner); 790cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar }); 791cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 792cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 793cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Remove unneeded breaks and continues. 794cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // A flow operation is trivially unneeded if the shape we naturally get to 795cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // by normal code execution is the same as the flow forces us to. 796cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar void RemoveUnneededFlows(Shape *Root, Shape *Natural = nullptr, 797cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar LoopShape *LastLoop = nullptr, 798cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar unsigned Depth = 0) { 799cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar BlockSet NaturalBlocks; 800cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar FollowNaturalFlow(Natural, NaturalBlocks); 801cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Shape *Next = Root; 802cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar while (Next) { 803cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Root = Next; 804cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Next = nullptr; 805cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar ShapeSwitch( 806cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Root, 807cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar [&](SimpleShape* Simple) { 808cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Simple->Inner->BranchVar) 809cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar LastLoop = 810cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar nullptr; // a switch clears out the loop (TODO: only for 811cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // breaks, not continue) 812cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 813cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Simple->Next) { 814cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (!Simple->Inner->BranchVar && 815cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Simple->Inner->ProcessedBranchesOut.size() == 2 && 816cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Depth < RelooperNestingLimit) { 817cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // If there is a next block, we already know at Simple 818cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // creation time to make direct branches, and we can do 819cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // nothing more in general. But, we try to optimize the 820cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // case of a break and a direct: This would normally be 821cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // if (break?) { break; } .. 822cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // but if we make sure to nest the else, we can save the 823cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // break, 824cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // if (!break?) { .. } 825cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // This is also better because the more canonical nested 826cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // form is easier to further optimize later. The 827cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // downside is more nesting, which adds to size in builds with 828cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // whitespace. 829cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // Note that we avoid switches, as it complicates control flow 830cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // and is not relevant for the common case we optimize here. 831cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar bool Found = false; 832cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar bool Abort = false; 833cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : Simple->Inner->ProcessedBranchesOut) { 834cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *Target = iter.first; 835cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Branch *Details = iter.second.get(); 836cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Details->Type == Branch::Break) { 837cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Found = true; 838cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (!contains(NaturalBlocks, Target)) 839cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Abort = true; 840cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } else if (Details->Type != Branch::Direct) 841cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Abort = true; 842cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 843cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Found && !Abort) { 844cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : Simple->Inner->ProcessedBranchesOut) { 845cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Branch *Details = iter.second.get(); 846cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Details->Type == Branch::Break) { 847cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Details->Type = Branch::Direct; 848cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (MultipleShape *Multiple = 849cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar dyn_cast<MultipleShape>(Details->Ancestor)) 850cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Multiple->Breaks--; 851cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } else { 852cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar assert(Details->Type == Branch::Direct); 853cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Details->Type = Branch::Nested; 854cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 855cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 856cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 857cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Depth++; // this optimization increases depth, for us and all 858cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // our next chain (i.e., until this call returns) 859cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 860cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Next = Simple->Next; 861cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } else { 862cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // If there is no next then Natural is where we will 863cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // go to by doing nothing, so we can potentially optimize some 864cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // branches to direct. 865cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : Simple->Inner->ProcessedBranchesOut) { 866cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Block *Target = iter.first; 867cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Branch *Details = iter.second.get(); 868cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Details->Type != Branch::Direct && 869cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar contains(NaturalBlocks, 870cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Target)) { // note: cannot handle split blocks 871cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Details->Type = Branch::Direct; 872cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (MultipleShape *Multiple = 873cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar dyn_cast<MultipleShape>(Details->Ancestor)) 874cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Multiple->Breaks--; 875cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } else if (Details->Type == Branch::Break && LastLoop && 876cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar LastLoop->Natural == Details->Ancestor->Natural) { 877cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // it is important to simplify breaks, as simpler breaks 878cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // enable other optimizations 879cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Details->Labeled = false; 880cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (MultipleShape *Multiple = 881cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar dyn_cast<MultipleShape>(Details->Ancestor)) 882cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Multiple->Breaks--; 883cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 884cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 885cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 886cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar }, [&](MultipleShape* Multiple) 887cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar { 888cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : Multiple->InnerMap) { 889cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar RemoveUnneededFlows(iter.second, Multiple->Next, 890cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Multiple->Breaks ? nullptr : LastLoop, 891cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Depth + 1); 892cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 893cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Next = Multiple->Next; 894cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar }, [&](LoopShape* Loop) 895cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar { 896cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar RemoveUnneededFlows(Loop->Inner, Loop->Inner, Loop, Depth + 1); 897cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Next = Loop->Next; 898cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar }); 899cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 900cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 901cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 902cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // After we know which loops exist, we can calculate which need to be 903cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // labeled 904cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar void FindLabeledLoops(Shape *Root) { 905cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Shape *Next = Root; 906cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar while (Next) { 907cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Root = Next; 908cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Next = nullptr; 909cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 910cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar ShapeSwitch( 911cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Root, 912cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar [&](SimpleShape *Simple) { 913cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar MultipleShape *Fused = dyn_cast<MultipleShape>(Root->Next); 914cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // If we are fusing a Multiple with a loop into this Simple, then 915cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // visit it now 916cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Fused && Fused->Breaks) 917cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar LoopStack.push(Fused); 918cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Simple->Inner->BranchVar) 919cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar LoopStack.push(nullptr); // a switch means breaks are now useless, 920cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // push a dummy 921cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Fused) { 922cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Fused->UseSwitch) 923cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar LoopStack.push(nullptr); // a switch means breaks are now 924cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar // useless, push a dummy 925cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : Fused->InnerMap) { 926cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar FindLabeledLoops(iter.second); 927cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 928cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 929cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : Simple->Inner->ProcessedBranchesOut) { 930cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Branch *Details = iter.second.get(); 931cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Details->Type == Branch::Break || 932cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Details->Type == Branch::Continue) { 933cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar assert(!LoopStack.empty()); 934cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Details->Ancestor != LoopStack.top() && Details->Labeled) { 935cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (MultipleShape *Multiple = 936cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar dyn_cast<MultipleShape>(Details->Ancestor)) { 937cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Multiple->Labeled = true; 938cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } else { 939cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar LoopShape *Loop = cast<LoopShape>(Details->Ancestor); 940cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Loop->Labeled = true; 941cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 942cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } else { 943cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Details->Labeled = false; 944cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 945cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 946cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Fused && Fused->UseSwitch) 947cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar LoopStack.pop(); 948cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Simple->Inner->BranchVar) 949cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar LoopStack.pop(); 950cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Fused && Fused->Breaks) 951cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar LoopStack.pop(); 952cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Fused) 953cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Next = Fused->Next; 954cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar else 955cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Next = Root->Next; 956cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 957cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 958cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar , [&](MultipleShape* Multiple) { 959cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Multiple->Breaks) 960cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar LoopStack.push(Multiple); 961cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar for (const auto &iter : Multiple->InnerMap) 962cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar FindLabeledLoops(iter.second); 963cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar if (Multiple->Breaks) 964cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar LoopStack.pop(); 965cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Next = Root->Next; 966cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 967cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar , [&](LoopShape* Loop) { 968cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar LoopStack.push(Loop); 969cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar FindLabeledLoops(Loop->Inner); 970cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar LoopStack.pop(); 971cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar Next = Root->Next; 972cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar }); 973cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 974cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 975cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 976cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar void Process(Shape * Root) { 977cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar FindNaturals(Root); 978cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar RemoveUnneededFlows(Root); 979cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar FindLabeledLoops(Root); 980cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar } 981cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar }; 982cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar 983cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar PostOptimizer(this).Process(Root); 984cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar} 985