xref: /llvm-project/llvm/lib/Transforms/Utils/ControlFlowUtils.cpp (revision 5f6172f0684b6a224d207ff8d093fc9aad92e331)
1*5f6172f0SSameer Sahasrabuddhe //===- ControlFlowUtils.cpp - Control Flow Utilities -----------------------==//
2*5f6172f0SSameer Sahasrabuddhe //
3*5f6172f0SSameer Sahasrabuddhe // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*5f6172f0SSameer Sahasrabuddhe // See https://llvm.org/LICENSE.txt for license information.
5*5f6172f0SSameer Sahasrabuddhe // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*5f6172f0SSameer Sahasrabuddhe //
7*5f6172f0SSameer Sahasrabuddhe //===----------------------------------------------------------------------===//
8*5f6172f0SSameer Sahasrabuddhe //
9*5f6172f0SSameer Sahasrabuddhe // Utilities to manipulate the CFG and restore SSA for the new control flow.
10*5f6172f0SSameer Sahasrabuddhe //
11*5f6172f0SSameer Sahasrabuddhe //===----------------------------------------------------------------------===//
12*5f6172f0SSameer Sahasrabuddhe 
13*5f6172f0SSameer Sahasrabuddhe #include "llvm/Transforms/Utils/ControlFlowUtils.h"
14*5f6172f0SSameer Sahasrabuddhe #include "llvm/ADT/SetVector.h"
15*5f6172f0SSameer Sahasrabuddhe #include "llvm/ADT/SmallSet.h"
16*5f6172f0SSameer Sahasrabuddhe #include "llvm/Analysis/DomTreeUpdater.h"
17*5f6172f0SSameer Sahasrabuddhe #include "llvm/IR/Constants.h"
18*5f6172f0SSameer Sahasrabuddhe #include "llvm/IR/Instructions.h"
19*5f6172f0SSameer Sahasrabuddhe #include "llvm/IR/ValueHandle.h"
20*5f6172f0SSameer Sahasrabuddhe #include "llvm/Transforms/Utils/Local.h"
21*5f6172f0SSameer Sahasrabuddhe 
22*5f6172f0SSameer Sahasrabuddhe #define DEBUG_TYPE "control-flow-hub"
23*5f6172f0SSameer Sahasrabuddhe 
24*5f6172f0SSameer Sahasrabuddhe using namespace llvm;
25*5f6172f0SSameer Sahasrabuddhe 
26*5f6172f0SSameer Sahasrabuddhe using BBPredicates = DenseMap<BasicBlock *, Instruction *>;
27*5f6172f0SSameer Sahasrabuddhe using EdgeDescriptor = ControlFlowHub::BranchDescriptor;
28*5f6172f0SSameer Sahasrabuddhe 
29*5f6172f0SSameer Sahasrabuddhe // Redirects the terminator of the incoming block to the first guard block in
30*5f6172f0SSameer Sahasrabuddhe // the hub. Returns the branch condition from `BB` if it exits.
31*5f6172f0SSameer Sahasrabuddhe // - If only one of Succ0 or Succ1 is not null, the corresponding branch
32*5f6172f0SSameer Sahasrabuddhe //   successor is redirected to the FirstGuardBlock.
33*5f6172f0SSameer Sahasrabuddhe // - Else both are not null, and branch is replaced with an unconditional
34*5f6172f0SSameer Sahasrabuddhe //   branch to the FirstGuardBlock.
35*5f6172f0SSameer Sahasrabuddhe static Value *redirectToHub(BasicBlock *BB, BasicBlock *Succ0,
36*5f6172f0SSameer Sahasrabuddhe                             BasicBlock *Succ1, BasicBlock *FirstGuardBlock) {
37*5f6172f0SSameer Sahasrabuddhe   assert(isa<BranchInst>(BB->getTerminator()) &&
38*5f6172f0SSameer Sahasrabuddhe          "Only support branch terminator.");
39*5f6172f0SSameer Sahasrabuddhe   auto *Branch = cast<BranchInst>(BB->getTerminator());
40*5f6172f0SSameer Sahasrabuddhe   auto *Condition = Branch->isConditional() ? Branch->getCondition() : nullptr;
41*5f6172f0SSameer Sahasrabuddhe 
42*5f6172f0SSameer Sahasrabuddhe   assert(Succ0 || Succ1);
43*5f6172f0SSameer Sahasrabuddhe 
44*5f6172f0SSameer Sahasrabuddhe   if (Branch->isUnconditional()) {
45*5f6172f0SSameer Sahasrabuddhe     assert(Succ0 == Branch->getSuccessor(0));
46*5f6172f0SSameer Sahasrabuddhe     assert(!Succ1);
47*5f6172f0SSameer Sahasrabuddhe     Branch->setSuccessor(0, FirstGuardBlock);
48*5f6172f0SSameer Sahasrabuddhe   } else {
49*5f6172f0SSameer Sahasrabuddhe     assert(!Succ1 || Succ1 == Branch->getSuccessor(1));
50*5f6172f0SSameer Sahasrabuddhe     if (Succ0 && !Succ1) {
51*5f6172f0SSameer Sahasrabuddhe       Branch->setSuccessor(0, FirstGuardBlock);
52*5f6172f0SSameer Sahasrabuddhe     } else if (Succ1 && !Succ0) {
53*5f6172f0SSameer Sahasrabuddhe       Branch->setSuccessor(1, FirstGuardBlock);
54*5f6172f0SSameer Sahasrabuddhe     } else {
55*5f6172f0SSameer Sahasrabuddhe       Branch->eraseFromParent();
56*5f6172f0SSameer Sahasrabuddhe       BranchInst::Create(FirstGuardBlock, BB);
57*5f6172f0SSameer Sahasrabuddhe     }
58*5f6172f0SSameer Sahasrabuddhe   }
59*5f6172f0SSameer Sahasrabuddhe 
60*5f6172f0SSameer Sahasrabuddhe   return Condition;
61*5f6172f0SSameer Sahasrabuddhe }
62*5f6172f0SSameer Sahasrabuddhe 
63*5f6172f0SSameer Sahasrabuddhe // Setup the branch instructions for guard blocks.
64*5f6172f0SSameer Sahasrabuddhe //
65*5f6172f0SSameer Sahasrabuddhe // Each guard block terminates in a conditional branch that transfers
66*5f6172f0SSameer Sahasrabuddhe // control to the corresponding outgoing block or the next guard
67*5f6172f0SSameer Sahasrabuddhe // block. The last guard block has two outgoing blocks as successors.
68*5f6172f0SSameer Sahasrabuddhe static void setupBranchForGuard(ArrayRef<BasicBlock *> GuardBlocks,
69*5f6172f0SSameer Sahasrabuddhe                                 ArrayRef<BasicBlock *> Outgoing,
70*5f6172f0SSameer Sahasrabuddhe                                 BBPredicates &GuardPredicates) {
71*5f6172f0SSameer Sahasrabuddhe   assert(Outgoing.size() > 1);
72*5f6172f0SSameer Sahasrabuddhe   assert(GuardBlocks.size() == Outgoing.size() - 1);
73*5f6172f0SSameer Sahasrabuddhe   int I = 0;
74*5f6172f0SSameer Sahasrabuddhe   for (int E = GuardBlocks.size() - 1; I != E; ++I) {
75*5f6172f0SSameer Sahasrabuddhe     BasicBlock *Out = Outgoing[I];
76*5f6172f0SSameer Sahasrabuddhe     BranchInst::Create(Out, GuardBlocks[I + 1], GuardPredicates[Out],
77*5f6172f0SSameer Sahasrabuddhe                        GuardBlocks[I]);
78*5f6172f0SSameer Sahasrabuddhe   }
79*5f6172f0SSameer Sahasrabuddhe   BasicBlock *Out = Outgoing[I];
80*5f6172f0SSameer Sahasrabuddhe   BranchInst::Create(Out, Outgoing[I + 1], GuardPredicates[Out],
81*5f6172f0SSameer Sahasrabuddhe                      GuardBlocks[I]);
82*5f6172f0SSameer Sahasrabuddhe }
83*5f6172f0SSameer Sahasrabuddhe 
84*5f6172f0SSameer Sahasrabuddhe // Assign an index to each outgoing block. At the corresponding guard
85*5f6172f0SSameer Sahasrabuddhe // block, compute the branch condition by comparing this index.
86*5f6172f0SSameer Sahasrabuddhe static void calcPredicateUsingInteger(ArrayRef<EdgeDescriptor> Branches,
87*5f6172f0SSameer Sahasrabuddhe                                       ArrayRef<BasicBlock *> Outgoing,
88*5f6172f0SSameer Sahasrabuddhe                                       ArrayRef<BasicBlock *> GuardBlocks,
89*5f6172f0SSameer Sahasrabuddhe                                       BBPredicates &GuardPredicates) {
90*5f6172f0SSameer Sahasrabuddhe   LLVMContext &Context = GuardBlocks.front()->getContext();
91*5f6172f0SSameer Sahasrabuddhe   BasicBlock *FirstGuardBlock = GuardBlocks.front();
92*5f6172f0SSameer Sahasrabuddhe   Type *Int32Ty = Type::getInt32Ty(Context);
93*5f6172f0SSameer Sahasrabuddhe 
94*5f6172f0SSameer Sahasrabuddhe   auto *Phi = PHINode::Create(Int32Ty, Branches.size(), "merged.bb.idx",
95*5f6172f0SSameer Sahasrabuddhe                               FirstGuardBlock);
96*5f6172f0SSameer Sahasrabuddhe 
97*5f6172f0SSameer Sahasrabuddhe   for (auto [BB, Succ0, Succ1] : Branches) {
98*5f6172f0SSameer Sahasrabuddhe     Value *Condition = redirectToHub(BB, Succ0, Succ1, FirstGuardBlock);
99*5f6172f0SSameer Sahasrabuddhe     Value *IncomingId = nullptr;
100*5f6172f0SSameer Sahasrabuddhe     if (Succ0 && Succ1) {
101*5f6172f0SSameer Sahasrabuddhe       auto Succ0Iter = find(Outgoing, Succ0);
102*5f6172f0SSameer Sahasrabuddhe       auto Succ1Iter = find(Outgoing, Succ1);
103*5f6172f0SSameer Sahasrabuddhe       Value *Id0 =
104*5f6172f0SSameer Sahasrabuddhe           ConstantInt::get(Int32Ty, std::distance(Outgoing.begin(), Succ0Iter));
105*5f6172f0SSameer Sahasrabuddhe       Value *Id1 =
106*5f6172f0SSameer Sahasrabuddhe           ConstantInt::get(Int32Ty, std::distance(Outgoing.begin(), Succ1Iter));
107*5f6172f0SSameer Sahasrabuddhe       IncomingId = SelectInst::Create(Condition, Id0, Id1, "target.bb.idx",
108*5f6172f0SSameer Sahasrabuddhe                                       BB->getTerminator()->getIterator());
109*5f6172f0SSameer Sahasrabuddhe     } else {
110*5f6172f0SSameer Sahasrabuddhe       // Get the index of the non-null successor.
111*5f6172f0SSameer Sahasrabuddhe       auto SuccIter = Succ0 ? find(Outgoing, Succ0) : find(Outgoing, Succ1);
112*5f6172f0SSameer Sahasrabuddhe       IncomingId =
113*5f6172f0SSameer Sahasrabuddhe           ConstantInt::get(Int32Ty, std::distance(Outgoing.begin(), SuccIter));
114*5f6172f0SSameer Sahasrabuddhe     }
115*5f6172f0SSameer Sahasrabuddhe     Phi->addIncoming(IncomingId, BB);
116*5f6172f0SSameer Sahasrabuddhe   }
117*5f6172f0SSameer Sahasrabuddhe 
118*5f6172f0SSameer Sahasrabuddhe   for (int I = 0, E = Outgoing.size() - 1; I != E; ++I) {
119*5f6172f0SSameer Sahasrabuddhe     BasicBlock *Out = Outgoing[I];
120*5f6172f0SSameer Sahasrabuddhe     LLVM_DEBUG(dbgs() << "Creating integer guard for " << Out->getName()
121*5f6172f0SSameer Sahasrabuddhe                       << "\n");
122*5f6172f0SSameer Sahasrabuddhe     auto *Cmp = ICmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, Phi,
123*5f6172f0SSameer Sahasrabuddhe                                  ConstantInt::get(Int32Ty, I),
124*5f6172f0SSameer Sahasrabuddhe                                  Out->getName() + ".predicate", GuardBlocks[I]);
125*5f6172f0SSameer Sahasrabuddhe     GuardPredicates[Out] = Cmp;
126*5f6172f0SSameer Sahasrabuddhe   }
127*5f6172f0SSameer Sahasrabuddhe }
128*5f6172f0SSameer Sahasrabuddhe 
129*5f6172f0SSameer Sahasrabuddhe // Determine the branch condition to be used at each guard block from the
130*5f6172f0SSameer Sahasrabuddhe // original boolean values.
131*5f6172f0SSameer Sahasrabuddhe static void calcPredicateUsingBooleans(
132*5f6172f0SSameer Sahasrabuddhe     ArrayRef<EdgeDescriptor> Branches, ArrayRef<BasicBlock *> Outgoing,
133*5f6172f0SSameer Sahasrabuddhe     SmallVectorImpl<BasicBlock *> &GuardBlocks, BBPredicates &GuardPredicates,
134*5f6172f0SSameer Sahasrabuddhe     SmallVectorImpl<WeakVH> &DeletionCandidates) {
135*5f6172f0SSameer Sahasrabuddhe   LLVMContext &Context = GuardBlocks.front()->getContext();
136*5f6172f0SSameer Sahasrabuddhe   auto *BoolTrue = ConstantInt::getTrue(Context);
137*5f6172f0SSameer Sahasrabuddhe   auto *BoolFalse = ConstantInt::getFalse(Context);
138*5f6172f0SSameer Sahasrabuddhe   BasicBlock *FirstGuardBlock = GuardBlocks.front();
139*5f6172f0SSameer Sahasrabuddhe 
140*5f6172f0SSameer Sahasrabuddhe   // The predicate for the last outgoing is trivially true, and so we
141*5f6172f0SSameer Sahasrabuddhe   // process only the first N-1 successors.
142*5f6172f0SSameer Sahasrabuddhe   for (int I = 0, E = Outgoing.size() - 1; I != E; ++I) {
143*5f6172f0SSameer Sahasrabuddhe     BasicBlock *Out = Outgoing[I];
144*5f6172f0SSameer Sahasrabuddhe     LLVM_DEBUG(dbgs() << "Creating boolean guard for " << Out->getName()
145*5f6172f0SSameer Sahasrabuddhe                       << "\n");
146*5f6172f0SSameer Sahasrabuddhe 
147*5f6172f0SSameer Sahasrabuddhe     auto *Phi =
148*5f6172f0SSameer Sahasrabuddhe         PHINode::Create(Type::getInt1Ty(Context), Branches.size(),
149*5f6172f0SSameer Sahasrabuddhe                         StringRef("Guard.") + Out->getName(), FirstGuardBlock);
150*5f6172f0SSameer Sahasrabuddhe     GuardPredicates[Out] = Phi;
151*5f6172f0SSameer Sahasrabuddhe   }
152*5f6172f0SSameer Sahasrabuddhe 
153*5f6172f0SSameer Sahasrabuddhe   for (auto [BB, Succ0, Succ1] : Branches) {
154*5f6172f0SSameer Sahasrabuddhe     Value *Condition = redirectToHub(BB, Succ0, Succ1, FirstGuardBlock);
155*5f6172f0SSameer Sahasrabuddhe 
156*5f6172f0SSameer Sahasrabuddhe     // Optimization: Consider an incoming block A with both successors
157*5f6172f0SSameer Sahasrabuddhe     // Succ0 and Succ1 in the set of outgoing blocks. The predicates
158*5f6172f0SSameer Sahasrabuddhe     // for Succ0 and Succ1 complement each other. If Succ0 is visited
159*5f6172f0SSameer Sahasrabuddhe     // first in the loop below, control will branch to Succ0 using the
160*5f6172f0SSameer Sahasrabuddhe     // corresponding predicate. But if that branch is not taken, then
161*5f6172f0SSameer Sahasrabuddhe     // control must reach Succ1, which means that the incoming value of
162*5f6172f0SSameer Sahasrabuddhe     // the predicate from `BB` is true for Succ1.
163*5f6172f0SSameer Sahasrabuddhe     bool OneSuccessorDone = false;
164*5f6172f0SSameer Sahasrabuddhe     for (int I = 0, E = Outgoing.size() - 1; I != E; ++I) {
165*5f6172f0SSameer Sahasrabuddhe       BasicBlock *Out = Outgoing[I];
166*5f6172f0SSameer Sahasrabuddhe       PHINode *Phi = cast<PHINode>(GuardPredicates[Out]);
167*5f6172f0SSameer Sahasrabuddhe       if (Out != Succ0 && Out != Succ1) {
168*5f6172f0SSameer Sahasrabuddhe         Phi->addIncoming(BoolFalse, BB);
169*5f6172f0SSameer Sahasrabuddhe       } else if (!Succ0 || !Succ1 || OneSuccessorDone) {
170*5f6172f0SSameer Sahasrabuddhe         // Optimization: When only one successor is an outgoing block,
171*5f6172f0SSameer Sahasrabuddhe         // the incoming predicate from `BB` is always true.
172*5f6172f0SSameer Sahasrabuddhe         Phi->addIncoming(BoolTrue, BB);
173*5f6172f0SSameer Sahasrabuddhe       } else {
174*5f6172f0SSameer Sahasrabuddhe         assert(Succ0 && Succ1);
175*5f6172f0SSameer Sahasrabuddhe         if (Out == Succ0) {
176*5f6172f0SSameer Sahasrabuddhe           Phi->addIncoming(Condition, BB);
177*5f6172f0SSameer Sahasrabuddhe         } else {
178*5f6172f0SSameer Sahasrabuddhe           Value *Inverted = invertCondition(Condition);
179*5f6172f0SSameer Sahasrabuddhe           DeletionCandidates.push_back(Condition);
180*5f6172f0SSameer Sahasrabuddhe           Phi->addIncoming(Inverted, BB);
181*5f6172f0SSameer Sahasrabuddhe         }
182*5f6172f0SSameer Sahasrabuddhe         OneSuccessorDone = true;
183*5f6172f0SSameer Sahasrabuddhe       }
184*5f6172f0SSameer Sahasrabuddhe     }
185*5f6172f0SSameer Sahasrabuddhe   }
186*5f6172f0SSameer Sahasrabuddhe }
187*5f6172f0SSameer Sahasrabuddhe 
188*5f6172f0SSameer Sahasrabuddhe // Capture the existing control flow as guard predicates, and redirect
189*5f6172f0SSameer Sahasrabuddhe // control flow from \p Incoming block through the \p GuardBlocks to the
190*5f6172f0SSameer Sahasrabuddhe // \p Outgoing blocks.
191*5f6172f0SSameer Sahasrabuddhe //
192*5f6172f0SSameer Sahasrabuddhe // There is one guard predicate for each outgoing block OutBB. The
193*5f6172f0SSameer Sahasrabuddhe // predicate represents whether the hub should transfer control flow
194*5f6172f0SSameer Sahasrabuddhe // to OutBB. These predicates are NOT ORTHOGONAL. The Hub evaluates
195*5f6172f0SSameer Sahasrabuddhe // them in the same order as the Outgoing set-vector, and control
196*5f6172f0SSameer Sahasrabuddhe // branches to the first outgoing block whose predicate evaluates to true.
197*5f6172f0SSameer Sahasrabuddhe //
198*5f6172f0SSameer Sahasrabuddhe // The last guard block has two outgoing blocks as successors since the
199*5f6172f0SSameer Sahasrabuddhe // condition for the final outgoing block is trivially true. So we create one
200*5f6172f0SSameer Sahasrabuddhe // less block (including the first guard block) than the number of outgoing
201*5f6172f0SSameer Sahasrabuddhe // blocks.
202*5f6172f0SSameer Sahasrabuddhe static void convertToGuardPredicates(
203*5f6172f0SSameer Sahasrabuddhe     ArrayRef<EdgeDescriptor> Branches, ArrayRef<BasicBlock *> Outgoing,
204*5f6172f0SSameer Sahasrabuddhe     SmallVectorImpl<BasicBlock *> &GuardBlocks,
205*5f6172f0SSameer Sahasrabuddhe     SmallVectorImpl<WeakVH> &DeletionCandidates, const StringRef Prefix,
206*5f6172f0SSameer Sahasrabuddhe     std::optional<unsigned> MaxControlFlowBooleans) {
207*5f6172f0SSameer Sahasrabuddhe   BBPredicates GuardPredicates;
208*5f6172f0SSameer Sahasrabuddhe   Function *F = Outgoing.front()->getParent();
209*5f6172f0SSameer Sahasrabuddhe 
210*5f6172f0SSameer Sahasrabuddhe   for (int I = 0, E = Outgoing.size() - 1; I != E; ++I)
211*5f6172f0SSameer Sahasrabuddhe     GuardBlocks.push_back(
212*5f6172f0SSameer Sahasrabuddhe         BasicBlock::Create(F->getContext(), Prefix + ".guard", F));
213*5f6172f0SSameer Sahasrabuddhe 
214*5f6172f0SSameer Sahasrabuddhe   // When we are using an integer to record which target block to jump to, we
215*5f6172f0SSameer Sahasrabuddhe   // are creating less live values, actually we are using one single integer to
216*5f6172f0SSameer Sahasrabuddhe   // store the index of the target block. When we are using booleans to store
217*5f6172f0SSameer Sahasrabuddhe   // the branching information, we need (N-1) boolean values, where N is the
218*5f6172f0SSameer Sahasrabuddhe   // number of outgoing block.
219*5f6172f0SSameer Sahasrabuddhe   if (!MaxControlFlowBooleans || Outgoing.size() <= *MaxControlFlowBooleans)
220*5f6172f0SSameer Sahasrabuddhe     calcPredicateUsingBooleans(Branches, Outgoing, GuardBlocks, GuardPredicates,
221*5f6172f0SSameer Sahasrabuddhe                                DeletionCandidates);
222*5f6172f0SSameer Sahasrabuddhe   else
223*5f6172f0SSameer Sahasrabuddhe     calcPredicateUsingInteger(Branches, Outgoing, GuardBlocks, GuardPredicates);
224*5f6172f0SSameer Sahasrabuddhe 
225*5f6172f0SSameer Sahasrabuddhe   setupBranchForGuard(GuardBlocks, Outgoing, GuardPredicates);
226*5f6172f0SSameer Sahasrabuddhe }
227*5f6172f0SSameer Sahasrabuddhe 
228*5f6172f0SSameer Sahasrabuddhe // After creating a control flow hub, the operands of PHINodes in an outgoing
229*5f6172f0SSameer Sahasrabuddhe // block Out no longer match the predecessors of that block. Predecessors of Out
230*5f6172f0SSameer Sahasrabuddhe // that are incoming blocks to the hub are now replaced by just one edge from
231*5f6172f0SSameer Sahasrabuddhe // the hub. To match this new control flow, the corresponding values from each
232*5f6172f0SSameer Sahasrabuddhe // PHINode must now be moved a new PHINode in the first guard block of the hub.
233*5f6172f0SSameer Sahasrabuddhe //
234*5f6172f0SSameer Sahasrabuddhe // This operation cannot be performed with SSAUpdater, because it involves one
235*5f6172f0SSameer Sahasrabuddhe // new use: If the block Out is in the list of Incoming blocks, then the newly
236*5f6172f0SSameer Sahasrabuddhe // created PHI in the Hub will use itself along that edge from Out to Hub.
237*5f6172f0SSameer Sahasrabuddhe static void reconnectPhis(BasicBlock *Out, BasicBlock *GuardBlock,
238*5f6172f0SSameer Sahasrabuddhe                           ArrayRef<EdgeDescriptor> Incoming,
239*5f6172f0SSameer Sahasrabuddhe                           BasicBlock *FirstGuardBlock) {
240*5f6172f0SSameer Sahasrabuddhe   auto I = Out->begin();
241*5f6172f0SSameer Sahasrabuddhe   while (I != Out->end() && isa<PHINode>(I)) {
242*5f6172f0SSameer Sahasrabuddhe     auto *Phi = cast<PHINode>(I);
243*5f6172f0SSameer Sahasrabuddhe     auto *NewPhi =
244*5f6172f0SSameer Sahasrabuddhe         PHINode::Create(Phi->getType(), Incoming.size(),
245*5f6172f0SSameer Sahasrabuddhe                         Phi->getName() + ".moved", FirstGuardBlock->begin());
246*5f6172f0SSameer Sahasrabuddhe     bool AllUndef = true;
247*5f6172f0SSameer Sahasrabuddhe     for (auto [BB, Succ0, Succ1] : Incoming) {
248*5f6172f0SSameer Sahasrabuddhe       Value *V = PoisonValue::get(Phi->getType());
249*5f6172f0SSameer Sahasrabuddhe       if (BB == Out) {
250*5f6172f0SSameer Sahasrabuddhe         V = NewPhi;
251*5f6172f0SSameer Sahasrabuddhe       } else if (Phi->getBasicBlockIndex(BB) != -1) {
252*5f6172f0SSameer Sahasrabuddhe         V = Phi->removeIncomingValue(BB, false);
253*5f6172f0SSameer Sahasrabuddhe         AllUndef &= isa<UndefValue>(V);
254*5f6172f0SSameer Sahasrabuddhe       }
255*5f6172f0SSameer Sahasrabuddhe       NewPhi->addIncoming(V, BB);
256*5f6172f0SSameer Sahasrabuddhe     }
257*5f6172f0SSameer Sahasrabuddhe     assert(NewPhi->getNumIncomingValues() == Incoming.size());
258*5f6172f0SSameer Sahasrabuddhe     Value *NewV = NewPhi;
259*5f6172f0SSameer Sahasrabuddhe     if (AllUndef) {
260*5f6172f0SSameer Sahasrabuddhe       NewPhi->eraseFromParent();
261*5f6172f0SSameer Sahasrabuddhe       NewV = PoisonValue::get(Phi->getType());
262*5f6172f0SSameer Sahasrabuddhe     }
263*5f6172f0SSameer Sahasrabuddhe     if (Phi->getNumOperands() == 0) {
264*5f6172f0SSameer Sahasrabuddhe       Phi->replaceAllUsesWith(NewV);
265*5f6172f0SSameer Sahasrabuddhe       I = Phi->eraseFromParent();
266*5f6172f0SSameer Sahasrabuddhe       continue;
267*5f6172f0SSameer Sahasrabuddhe     }
268*5f6172f0SSameer Sahasrabuddhe     Phi->addIncoming(NewV, GuardBlock);
269*5f6172f0SSameer Sahasrabuddhe     ++I;
270*5f6172f0SSameer Sahasrabuddhe   }
271*5f6172f0SSameer Sahasrabuddhe }
272*5f6172f0SSameer Sahasrabuddhe 
273*5f6172f0SSameer Sahasrabuddhe BasicBlock *ControlFlowHub::finalize(
274*5f6172f0SSameer Sahasrabuddhe     DomTreeUpdater *DTU, SmallVectorImpl<BasicBlock *> &GuardBlocks,
275*5f6172f0SSameer Sahasrabuddhe     const StringRef Prefix, std::optional<unsigned> MaxControlFlowBooleans) {
276*5f6172f0SSameer Sahasrabuddhe #ifndef NDEBUG
277*5f6172f0SSameer Sahasrabuddhe   SmallSet<BasicBlock *, 8> Incoming;
278*5f6172f0SSameer Sahasrabuddhe #endif
279*5f6172f0SSameer Sahasrabuddhe   SetVector<BasicBlock *> Outgoing;
280*5f6172f0SSameer Sahasrabuddhe 
281*5f6172f0SSameer Sahasrabuddhe   for (auto [BB, Succ0, Succ1] : Branches) {
282*5f6172f0SSameer Sahasrabuddhe #ifndef NDEBUG
283*5f6172f0SSameer Sahasrabuddhe     assert(Incoming.insert(BB).second && "Duplicate entry for incoming block.");
284*5f6172f0SSameer Sahasrabuddhe #endif
285*5f6172f0SSameer Sahasrabuddhe     if (Succ0)
286*5f6172f0SSameer Sahasrabuddhe       Outgoing.insert(Succ0);
287*5f6172f0SSameer Sahasrabuddhe     if (Succ1)
288*5f6172f0SSameer Sahasrabuddhe       Outgoing.insert(Succ1);
289*5f6172f0SSameer Sahasrabuddhe   }
290*5f6172f0SSameer Sahasrabuddhe 
291*5f6172f0SSameer Sahasrabuddhe   if (Outgoing.size() < 2)
292*5f6172f0SSameer Sahasrabuddhe     return Outgoing.front();
293*5f6172f0SSameer Sahasrabuddhe 
294*5f6172f0SSameer Sahasrabuddhe   SmallVector<DominatorTree::UpdateType, 16> Updates;
295*5f6172f0SSameer Sahasrabuddhe   if (DTU) {
296*5f6172f0SSameer Sahasrabuddhe     for (auto [BB, Succ0, Succ1] : Branches) {
297*5f6172f0SSameer Sahasrabuddhe       if (Succ0)
298*5f6172f0SSameer Sahasrabuddhe         Updates.push_back({DominatorTree::Delete, BB, Succ0});
299*5f6172f0SSameer Sahasrabuddhe       if (Succ1)
300*5f6172f0SSameer Sahasrabuddhe         Updates.push_back({DominatorTree::Delete, BB, Succ1});
301*5f6172f0SSameer Sahasrabuddhe     }
302*5f6172f0SSameer Sahasrabuddhe   }
303*5f6172f0SSameer Sahasrabuddhe 
304*5f6172f0SSameer Sahasrabuddhe   SmallVector<WeakVH, 8> DeletionCandidates;
305*5f6172f0SSameer Sahasrabuddhe   convertToGuardPredicates(Branches, Outgoing.getArrayRef(), GuardBlocks,
306*5f6172f0SSameer Sahasrabuddhe                            DeletionCandidates, Prefix, MaxControlFlowBooleans);
307*5f6172f0SSameer Sahasrabuddhe   BasicBlock *FirstGuardBlock = GuardBlocks.front();
308*5f6172f0SSameer Sahasrabuddhe 
309*5f6172f0SSameer Sahasrabuddhe   // Update the PHINodes in each outgoing block to match the new control flow.
310*5f6172f0SSameer Sahasrabuddhe   for (int I = 0, E = GuardBlocks.size(); I != E; ++I)
311*5f6172f0SSameer Sahasrabuddhe     reconnectPhis(Outgoing[I], GuardBlocks[I], Branches, FirstGuardBlock);
312*5f6172f0SSameer Sahasrabuddhe   // Process the Nth (last) outgoing block with the (N-1)th (last) guard block.
313*5f6172f0SSameer Sahasrabuddhe   reconnectPhis(Outgoing.back(), GuardBlocks.back(), Branches, FirstGuardBlock);
314*5f6172f0SSameer Sahasrabuddhe 
315*5f6172f0SSameer Sahasrabuddhe   if (DTU) {
316*5f6172f0SSameer Sahasrabuddhe     int NumGuards = GuardBlocks.size();
317*5f6172f0SSameer Sahasrabuddhe 
318*5f6172f0SSameer Sahasrabuddhe     for (auto [BB, Succ0, Succ1] : Branches)
319*5f6172f0SSameer Sahasrabuddhe       Updates.push_back({DominatorTree::Insert, BB, FirstGuardBlock});
320*5f6172f0SSameer Sahasrabuddhe 
321*5f6172f0SSameer Sahasrabuddhe     for (int I = 0; I != NumGuards - 1; ++I) {
322*5f6172f0SSameer Sahasrabuddhe       Updates.push_back({DominatorTree::Insert, GuardBlocks[I], Outgoing[I]});
323*5f6172f0SSameer Sahasrabuddhe       Updates.push_back(
324*5f6172f0SSameer Sahasrabuddhe           {DominatorTree::Insert, GuardBlocks[I], GuardBlocks[I + 1]});
325*5f6172f0SSameer Sahasrabuddhe     }
326*5f6172f0SSameer Sahasrabuddhe     // The second successor of the last guard block is an outgoing block instead
327*5f6172f0SSameer Sahasrabuddhe     // of having a "next" guard block.
328*5f6172f0SSameer Sahasrabuddhe     Updates.push_back({DominatorTree::Insert, GuardBlocks[NumGuards - 1],
329*5f6172f0SSameer Sahasrabuddhe                        Outgoing[NumGuards - 1]});
330*5f6172f0SSameer Sahasrabuddhe     Updates.push_back({DominatorTree::Insert, GuardBlocks[NumGuards - 1],
331*5f6172f0SSameer Sahasrabuddhe                        Outgoing[NumGuards]});
332*5f6172f0SSameer Sahasrabuddhe     DTU->applyUpdates(Updates);
333*5f6172f0SSameer Sahasrabuddhe   }
334*5f6172f0SSameer Sahasrabuddhe 
335*5f6172f0SSameer Sahasrabuddhe   for (auto I : DeletionCandidates) {
336*5f6172f0SSameer Sahasrabuddhe     if (I->use_empty())
337*5f6172f0SSameer Sahasrabuddhe       if (auto *Inst = dyn_cast_or_null<Instruction>(I))
338*5f6172f0SSameer Sahasrabuddhe         Inst->eraseFromParent();
339*5f6172f0SSameer Sahasrabuddhe   }
340*5f6172f0SSameer Sahasrabuddhe 
341*5f6172f0SSameer Sahasrabuddhe   return FirstGuardBlock;
342*5f6172f0SSameer Sahasrabuddhe }
343