//===- ControlFlowUtils.cpp - Control Flow Utilities -----------------------==// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Utilities to manipulate the CFG and restore SSA for the new control flow. // //===----------------------------------------------------------------------===// #include "llvm/Transforms/Utils/ControlFlowUtils.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallSet.h" #include "llvm/Analysis/DomTreeUpdater.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Transforms/Utils/Local.h" #define DEBUG_TYPE … usingnamespacellvm; BBPredicates; EdgeDescriptor; // Redirects the terminator of the incoming block to the first guard block in // the hub. Returns the branch condition from `BB` if it exits. // - If only one of Succ0 or Succ1 is not null, the corresponding branch // successor is redirected to the FirstGuardBlock. // - Else both are not null, and branch is replaced with an unconditional // branch to the FirstGuardBlock. static Value *redirectToHub(BasicBlock *BB, BasicBlock *Succ0, BasicBlock *Succ1, BasicBlock *FirstGuardBlock) { … } // Setup the branch instructions for guard blocks. // // Each guard block terminates in a conditional branch that transfers // control to the corresponding outgoing block or the next guard // block. The last guard block has two outgoing blocks as successors. static void setupBranchForGuard(ArrayRef<BasicBlock *> GuardBlocks, ArrayRef<BasicBlock *> Outgoing, BBPredicates &GuardPredicates) { … } // Assign an index to each outgoing block. At the corresponding guard // block, compute the branch condition by comparing this index. static void calcPredicateUsingInteger(ArrayRef<EdgeDescriptor> Branches, ArrayRef<BasicBlock *> Outgoing, ArrayRef<BasicBlock *> GuardBlocks, BBPredicates &GuardPredicates) { … } // Determine the branch condition to be used at each guard block from the // original boolean values. static void calcPredicateUsingBooleans( ArrayRef<EdgeDescriptor> Branches, ArrayRef<BasicBlock *> Outgoing, SmallVectorImpl<BasicBlock *> &GuardBlocks, BBPredicates &GuardPredicates, SmallVectorImpl<WeakVH> &DeletionCandidates) { … } // Capture the existing control flow as guard predicates, and redirect // control flow from \p Incoming block through the \p GuardBlocks to the // \p Outgoing blocks. // // There is one guard predicate for each outgoing block OutBB. The // predicate represents whether the hub should transfer control flow // to OutBB. These predicates are NOT ORTHOGONAL. The Hub evaluates // them in the same order as the Outgoing set-vector, and control // branches to the first outgoing block whose predicate evaluates to true. // // The last guard block has two outgoing blocks as successors since the // condition for the final outgoing block is trivially true. So we create one // less block (including the first guard block) than the number of outgoing // blocks. static void convertToGuardPredicates( ArrayRef<EdgeDescriptor> Branches, ArrayRef<BasicBlock *> Outgoing, SmallVectorImpl<BasicBlock *> &GuardBlocks, SmallVectorImpl<WeakVH> &DeletionCandidates, const StringRef Prefix, std::optional<unsigned> MaxControlFlowBooleans) { … } // After creating a control flow hub, the operands of PHINodes in an outgoing // block Out no longer match the predecessors of that block. Predecessors of Out // that are incoming blocks to the hub are now replaced by just one edge from // the hub. To match this new control flow, the corresponding values from each // PHINode must now be moved a new PHINode in the first guard block of the hub. // // This operation cannot be performed with SSAUpdater, because it involves one // new use: If the block Out is in the list of Incoming blocks, then the newly // created PHI in the Hub will use itself along that edge from Out to Hub. static void reconnectPhis(BasicBlock *Out, BasicBlock *GuardBlock, ArrayRef<EdgeDescriptor> Incoming, BasicBlock *FirstGuardBlock) { … } BasicBlock *ControlFlowHub::finalize( DomTreeUpdater *DTU, SmallVectorImpl<BasicBlock *> &GuardBlocks, const StringRef Prefix, std::optional<unsigned> MaxControlFlowBooleans) { … }