Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/Utils/ControlFlowUtils.cpp
213799 views
//===- ControlFlowUtils.cpp - Control Flow Utilities -----------------------==//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Utilities to manipulate the CFG and restore SSA for the new control flow.9//10//===----------------------------------------------------------------------===//1112#include "llvm/Transforms/Utils/ControlFlowUtils.h"13#include "llvm/ADT/SetVector.h"14#include "llvm/ADT/SmallSet.h"15#include "llvm/Analysis/DomTreeUpdater.h"16#include "llvm/IR/Constants.h"17#include "llvm/IR/Instructions.h"18#include "llvm/IR/ValueHandle.h"19#include "llvm/Transforms/Utils/Local.h"2021#define DEBUG_TYPE "control-flow-hub"2223using namespace llvm;2425using BBPredicates = DenseMap<BasicBlock *, Instruction *>;26using EdgeDescriptor = ControlFlowHub::BranchDescriptor;2728// Redirects the terminator of the incoming block to the first guard block in29// the hub. Returns the branch condition from `BB` if it exits.30// - If only one of Succ0 or Succ1 is not null, the corresponding branch31// successor is redirected to the FirstGuardBlock.32// - Else both are not null, and branch is replaced with an unconditional33// branch to the FirstGuardBlock.34static Value *redirectToHub(BasicBlock *BB, BasicBlock *Succ0,35BasicBlock *Succ1, BasicBlock *FirstGuardBlock) {36assert(isa<BranchInst>(BB->getTerminator()) &&37"Only support branch terminator.");38auto *Branch = cast<BranchInst>(BB->getTerminator());39auto *Condition = Branch->isConditional() ? Branch->getCondition() : nullptr;4041assert(Succ0 || Succ1);4243if (Branch->isUnconditional()) {44assert(Succ0 == Branch->getSuccessor(0));45assert(!Succ1);46Branch->setSuccessor(0, FirstGuardBlock);47} else {48assert(!Succ1 || Succ1 == Branch->getSuccessor(1));49if (Succ0 && !Succ1) {50Branch->setSuccessor(0, FirstGuardBlock);51} else if (Succ1 && !Succ0) {52Branch->setSuccessor(1, FirstGuardBlock);53} else {54Branch->eraseFromParent();55BranchInst::Create(FirstGuardBlock, BB);56}57}5859return Condition;60}6162// Setup the branch instructions for guard blocks.63//64// Each guard block terminates in a conditional branch that transfers65// control to the corresponding outgoing block or the next guard66// block. The last guard block has two outgoing blocks as successors.67static void setupBranchForGuard(ArrayRef<BasicBlock *> GuardBlocks,68ArrayRef<BasicBlock *> Outgoing,69BBPredicates &GuardPredicates) {70assert(Outgoing.size() > 1);71assert(GuardBlocks.size() == Outgoing.size() - 1);72int I = 0;73for (int E = GuardBlocks.size() - 1; I != E; ++I) {74BasicBlock *Out = Outgoing[I];75BranchInst::Create(Out, GuardBlocks[I + 1], GuardPredicates[Out],76GuardBlocks[I]);77}78BasicBlock *Out = Outgoing[I];79BranchInst::Create(Out, Outgoing[I + 1], GuardPredicates[Out],80GuardBlocks[I]);81}8283// Assign an index to each outgoing block. At the corresponding guard84// block, compute the branch condition by comparing this index.85static void calcPredicateUsingInteger(ArrayRef<EdgeDescriptor> Branches,86ArrayRef<BasicBlock *> Outgoing,87ArrayRef<BasicBlock *> GuardBlocks,88BBPredicates &GuardPredicates) {89LLVMContext &Context = GuardBlocks.front()->getContext();90BasicBlock *FirstGuardBlock = GuardBlocks.front();91Type *Int32Ty = Type::getInt32Ty(Context);9293auto *Phi = PHINode::Create(Int32Ty, Branches.size(), "merged.bb.idx",94FirstGuardBlock);9596for (auto [BB, Succ0, Succ1] : Branches) {97Value *Condition = redirectToHub(BB, Succ0, Succ1, FirstGuardBlock);98Value *IncomingId = nullptr;99if (Succ0 && Succ1) {100auto Succ0Iter = find(Outgoing, Succ0);101auto Succ1Iter = find(Outgoing, Succ1);102Value *Id0 =103ConstantInt::get(Int32Ty, std::distance(Outgoing.begin(), Succ0Iter));104Value *Id1 =105ConstantInt::get(Int32Ty, std::distance(Outgoing.begin(), Succ1Iter));106IncomingId = SelectInst::Create(Condition, Id0, Id1, "target.bb.idx",107BB->getTerminator()->getIterator());108} else {109// Get the index of the non-null successor.110auto SuccIter = Succ0 ? find(Outgoing, Succ0) : find(Outgoing, Succ1);111IncomingId =112ConstantInt::get(Int32Ty, std::distance(Outgoing.begin(), SuccIter));113}114Phi->addIncoming(IncomingId, BB);115}116117for (int I = 0, E = Outgoing.size() - 1; I != E; ++I) {118BasicBlock *Out = Outgoing[I];119LLVM_DEBUG(dbgs() << "Creating integer guard for " << Out->getName()120<< "\n");121auto *Cmp = ICmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, Phi,122ConstantInt::get(Int32Ty, I),123Out->getName() + ".predicate", GuardBlocks[I]);124GuardPredicates[Out] = Cmp;125}126}127128// Determine the branch condition to be used at each guard block from the129// original boolean values.130static void calcPredicateUsingBooleans(131ArrayRef<EdgeDescriptor> Branches, ArrayRef<BasicBlock *> Outgoing,132SmallVectorImpl<BasicBlock *> &GuardBlocks, BBPredicates &GuardPredicates,133SmallVectorImpl<WeakVH> &DeletionCandidates) {134LLVMContext &Context = GuardBlocks.front()->getContext();135auto *BoolTrue = ConstantInt::getTrue(Context);136auto *BoolFalse = ConstantInt::getFalse(Context);137BasicBlock *FirstGuardBlock = GuardBlocks.front();138139// The predicate for the last outgoing is trivially true, and so we140// process only the first N-1 successors.141for (int I = 0, E = Outgoing.size() - 1; I != E; ++I) {142BasicBlock *Out = Outgoing[I];143LLVM_DEBUG(dbgs() << "Creating boolean guard for " << Out->getName()144<< "\n");145146auto *Phi =147PHINode::Create(Type::getInt1Ty(Context), Branches.size(),148StringRef("Guard.") + Out->getName(), FirstGuardBlock);149GuardPredicates[Out] = Phi;150}151152for (auto [BB, Succ0, Succ1] : Branches) {153Value *Condition = redirectToHub(BB, Succ0, Succ1, FirstGuardBlock);154155// Optimization: Consider an incoming block A with both successors156// Succ0 and Succ1 in the set of outgoing blocks. The predicates157// for Succ0 and Succ1 complement each other. If Succ0 is visited158// first in the loop below, control will branch to Succ0 using the159// corresponding predicate. But if that branch is not taken, then160// control must reach Succ1, which means that the incoming value of161// the predicate from `BB` is true for Succ1.162bool OneSuccessorDone = false;163for (int I = 0, E = Outgoing.size() - 1; I != E; ++I) {164BasicBlock *Out = Outgoing[I];165PHINode *Phi = cast<PHINode>(GuardPredicates[Out]);166if (Out != Succ0 && Out != Succ1) {167Phi->addIncoming(BoolFalse, BB);168} else if (!Succ0 || !Succ1 || OneSuccessorDone) {169// Optimization: When only one successor is an outgoing block,170// the incoming predicate from `BB` is always true.171Phi->addIncoming(BoolTrue, BB);172} else {173assert(Succ0 && Succ1);174if (Out == Succ0) {175Phi->addIncoming(Condition, BB);176} else {177Value *Inverted = invertCondition(Condition);178DeletionCandidates.push_back(Condition);179Phi->addIncoming(Inverted, BB);180}181OneSuccessorDone = true;182}183}184}185}186187// Capture the existing control flow as guard predicates, and redirect188// control flow from \p Incoming block through the \p GuardBlocks to the189// \p Outgoing blocks.190//191// There is one guard predicate for each outgoing block OutBB. The192// predicate represents whether the hub should transfer control flow193// to OutBB. These predicates are NOT ORTHOGONAL. The Hub evaluates194// them in the same order as the Outgoing set-vector, and control195// branches to the first outgoing block whose predicate evaluates to true.196//197// The last guard block has two outgoing blocks as successors since the198// condition for the final outgoing block is trivially true. So we create one199// less block (including the first guard block) than the number of outgoing200// blocks.201static void convertToGuardPredicates(202ArrayRef<EdgeDescriptor> Branches, ArrayRef<BasicBlock *> Outgoing,203SmallVectorImpl<BasicBlock *> &GuardBlocks,204SmallVectorImpl<WeakVH> &DeletionCandidates, const StringRef Prefix,205std::optional<unsigned> MaxControlFlowBooleans) {206BBPredicates GuardPredicates;207Function *F = Outgoing.front()->getParent();208209for (int I = 0, E = Outgoing.size() - 1; I != E; ++I)210GuardBlocks.push_back(211BasicBlock::Create(F->getContext(), Prefix + ".guard", F));212213// When we are using an integer to record which target block to jump to, we214// are creating less live values, actually we are using one single integer to215// store the index of the target block. When we are using booleans to store216// the branching information, we need (N-1) boolean values, where N is the217// number of outgoing block.218if (!MaxControlFlowBooleans || Outgoing.size() <= *MaxControlFlowBooleans)219calcPredicateUsingBooleans(Branches, Outgoing, GuardBlocks, GuardPredicates,220DeletionCandidates);221else222calcPredicateUsingInteger(Branches, Outgoing, GuardBlocks, GuardPredicates);223224setupBranchForGuard(GuardBlocks, Outgoing, GuardPredicates);225}226227// After creating a control flow hub, the operands of PHINodes in an outgoing228// block Out no longer match the predecessors of that block. Predecessors of Out229// that are incoming blocks to the hub are now replaced by just one edge from230// the hub. To match this new control flow, the corresponding values from each231// PHINode must now be moved a new PHINode in the first guard block of the hub.232//233// This operation cannot be performed with SSAUpdater, because it involves one234// new use: If the block Out is in the list of Incoming blocks, then the newly235// created PHI in the Hub will use itself along that edge from Out to Hub.236static void reconnectPhis(BasicBlock *Out, BasicBlock *GuardBlock,237ArrayRef<EdgeDescriptor> Incoming,238BasicBlock *FirstGuardBlock) {239auto I = Out->begin();240while (I != Out->end() && isa<PHINode>(I)) {241auto *Phi = cast<PHINode>(I);242auto *NewPhi =243PHINode::Create(Phi->getType(), Incoming.size(),244Phi->getName() + ".moved", FirstGuardBlock->begin());245bool AllUndef = true;246for (auto [BB, Succ0, Succ1] : Incoming) {247Value *V = PoisonValue::get(Phi->getType());248if (Phi->getBasicBlockIndex(BB) != -1) {249V = Phi->removeIncomingValue(BB, false);250if (BB == Out) {251V = NewPhi;252}253AllUndef &= isa<UndefValue>(V);254}255256NewPhi->addIncoming(V, BB);257}258assert(NewPhi->getNumIncomingValues() == Incoming.size());259Value *NewV = NewPhi;260if (AllUndef) {261NewPhi->eraseFromParent();262NewV = PoisonValue::get(Phi->getType());263}264if (Phi->getNumOperands() == 0) {265Phi->replaceAllUsesWith(NewV);266I = Phi->eraseFromParent();267continue;268}269Phi->addIncoming(NewV, GuardBlock);270++I;271}272}273274std::pair<BasicBlock *, bool> ControlFlowHub::finalize(275DomTreeUpdater *DTU, SmallVectorImpl<BasicBlock *> &GuardBlocks,276const StringRef Prefix, std::optional<unsigned> MaxControlFlowBooleans) {277#ifndef NDEBUG278SmallSet<BasicBlock *, 8> Incoming;279#endif280SetVector<BasicBlock *> Outgoing;281282for (auto [BB, Succ0, Succ1] : Branches) {283#ifndef NDEBUG284assert(Incoming.insert(BB).second && "Duplicate entry for incoming block.");285#endif286if (Succ0)287Outgoing.insert(Succ0);288if (Succ1)289Outgoing.insert(Succ1);290}291292if (Outgoing.size() < 2)293return {Outgoing.front(), false};294295SmallVector<DominatorTree::UpdateType, 16> Updates;296if (DTU) {297for (auto [BB, Succ0, Succ1] : Branches) {298if (Succ0)299Updates.push_back({DominatorTree::Delete, BB, Succ0});300if (Succ1)301Updates.push_back({DominatorTree::Delete, BB, Succ1});302}303}304305SmallVector<WeakVH, 8> DeletionCandidates;306convertToGuardPredicates(Branches, Outgoing.getArrayRef(), GuardBlocks,307DeletionCandidates, Prefix, MaxControlFlowBooleans);308BasicBlock *FirstGuardBlock = GuardBlocks.front();309310// Update the PHINodes in each outgoing block to match the new control flow.311for (int I = 0, E = GuardBlocks.size(); I != E; ++I)312reconnectPhis(Outgoing[I], GuardBlocks[I], Branches, FirstGuardBlock);313// Process the Nth (last) outgoing block with the (N-1)th (last) guard block.314reconnectPhis(Outgoing.back(), GuardBlocks.back(), Branches, FirstGuardBlock);315316if (DTU) {317int NumGuards = GuardBlocks.size();318319for (auto [BB, Succ0, Succ1] : Branches)320Updates.push_back({DominatorTree::Insert, BB, FirstGuardBlock});321322for (int I = 0; I != NumGuards - 1; ++I) {323Updates.push_back({DominatorTree::Insert, GuardBlocks[I], Outgoing[I]});324Updates.push_back(325{DominatorTree::Insert, GuardBlocks[I], GuardBlocks[I + 1]});326}327// The second successor of the last guard block is an outgoing block instead328// of having a "next" guard block.329Updates.push_back({DominatorTree::Insert, GuardBlocks[NumGuards - 1],330Outgoing[NumGuards - 1]});331Updates.push_back({DominatorTree::Insert, GuardBlocks[NumGuards - 1],332Outgoing[NumGuards]});333DTU->applyUpdates(Updates);334}335336for (auto I : DeletionCandidates) {337if (I->use_empty())338if (auto *Inst = dyn_cast_or_null<Instruction>(I))339Inst->eraseFromParent();340}341342return {FirstGuardBlock, true};343}344345346