Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/Utils/FlattenCFG.cpp
35271 views
//===- FlatternCFG.cpp - Code to perform CFG flattening -------------------===//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// Reduce conditional branches in CFG.9//10//===----------------------------------------------------------------------===//1112#include "llvm/ADT/SmallPtrSet.h"13#include "llvm/Analysis/AliasAnalysis.h"14#include "llvm/Transforms/Utils/Local.h"15#include "llvm/Analysis/ValueTracking.h"16#include "llvm/IR/BasicBlock.h"17#include "llvm/IR/IRBuilder.h"18#include "llvm/IR/InstrTypes.h"19#include "llvm/IR/Instruction.h"20#include "llvm/IR/Instructions.h"21#include "llvm/IR/Value.h"22#include "llvm/Support/Casting.h"23#include "llvm/Support/Debug.h"24#include "llvm/Support/raw_ostream.h"25#include "llvm/Transforms/Utils/BasicBlockUtils.h"26#include <cassert>2728using namespace llvm;2930#define DEBUG_TYPE "flatten-cfg"3132namespace {3334class FlattenCFGOpt {35AliasAnalysis *AA;3637/// Use parallel-and or parallel-or to generate conditions for38/// conditional branches.39bool FlattenParallelAndOr(BasicBlock *BB, IRBuilder<> &Builder);4041/// If \param BB is the merge block of an if-region, attempt to merge42/// the if-region with an adjacent if-region upstream if two if-regions43/// contain identical instructions.44bool MergeIfRegion(BasicBlock *BB, IRBuilder<> &Builder);4546/// Compare a pair of blocks: \p Block1 and \p Block2, which47/// are from two if-regions, where \p Head2 is the entry block of the 2nd48/// if-region. \returns true if \p Block1 and \p Block2 contain identical49/// instructions, and have no memory reference alias with \p Head2.50/// This is used as a legality check for merging if-regions.51bool CompareIfRegionBlock(BasicBlock *Block1, BasicBlock *Block2,52BasicBlock *Head2);5354public:55FlattenCFGOpt(AliasAnalysis *AA) : AA(AA) {}5657bool run(BasicBlock *BB);58};5960} // end anonymous namespace6162/// If \param [in] BB has more than one predecessor that is a conditional63/// branch, attempt to use parallel and/or for the branch condition. \returns64/// true on success.65///66/// Before:67/// ......68/// %cmp10 = fcmp une float %tmp1, %tmp269/// br i1 %cmp10, label %if.then, label %lor.rhs70///71/// lor.rhs:72/// ......73/// %cmp11 = fcmp une float %tmp3, %tmp474/// br i1 %cmp11, label %if.then, label %ifend75///76/// if.end: // the merge block77/// ......78///79/// if.then: // has two predecessors, both of them contains conditional branch.80/// ......81/// br label %if.end;82///83/// After:84/// ......85/// %cmp10 = fcmp une float %tmp1, %tmp286/// ......87/// %cmp11 = fcmp une float %tmp3, %tmp488/// %cmp12 = or i1 %cmp10, %cmp11 // parallel-or mode.89/// br i1 %cmp12, label %if.then, label %ifend90///91/// if.end:92/// ......93///94/// if.then:95/// ......96/// br label %if.end;97///98/// Current implementation handles two cases.99/// Case 1: BB is on the else-path.100///101/// BB1102/// / |103/// BB2 |104/// / \ |105/// BB3 \ | where, BB1, BB2 contain conditional branches.106/// \ | / BB3 contains unconditional branch.107/// \ | / BB4 corresponds to BB which is also the merge.108/// BB => BB4109///110///111/// Corresponding source code:112///113/// if (a == b && c == d)114/// statement; // BB3115///116/// Case 2: BB is on the then-path.117///118/// BB1119/// / |120/// | BB2121/// \ / | where BB1, BB2 contain conditional branches.122/// BB => BB3 | BB3 contains unconditiona branch and corresponds123/// \ / to BB. BB4 is the merge.124/// BB4125///126/// Corresponding source code:127///128/// if (a == b || c == d)129/// statement; // BB3130///131/// In both cases, BB is the common successor of conditional branches.132/// In Case 1, BB (BB4) has an unconditional branch (BB3) as133/// its predecessor. In Case 2, BB (BB3) only has conditional branches134/// as its predecessors.135bool FlattenCFGOpt::FlattenParallelAndOr(BasicBlock *BB, IRBuilder<> &Builder) {136PHINode *PHI = dyn_cast<PHINode>(BB->begin());137if (PHI)138return false; // For simplicity, avoid cases containing PHI nodes.139140BasicBlock *LastCondBlock = nullptr;141BasicBlock *FirstCondBlock = nullptr;142BasicBlock *UnCondBlock = nullptr;143int Idx = -1;144145// Check predecessors of \param BB.146SmallPtrSet<BasicBlock *, 16> Preds(pred_begin(BB), pred_end(BB));147for (BasicBlock *Pred : Preds) {148BranchInst *PBI = dyn_cast<BranchInst>(Pred->getTerminator());149150// All predecessors should terminate with a branch.151if (!PBI)152return false;153154BasicBlock *PP = Pred->getSinglePredecessor();155156if (PBI->isUnconditional()) {157// Case 1: Pred (BB3) is an unconditional block, it should158// have a single predecessor (BB2) that is also a predecessor159// of \param BB (BB4) and should not have address-taken.160// There should exist only one such unconditional161// branch among the predecessors.162if (UnCondBlock || !PP || !Preds.contains(PP) ||163Pred->hasAddressTaken())164return false;165166UnCondBlock = Pred;167continue;168}169170// Only conditional branches are allowed beyond this point.171assert(PBI->isConditional());172173// Condition's unique use should be the branch instruction.174Value *PC = PBI->getCondition();175if (!PC || !PC->hasOneUse())176return false;177178if (PP && Preds.count(PP)) {179// These are internal condition blocks to be merged from, e.g.,180// BB2 in both cases.181// Should not be address-taken.182if (Pred->hasAddressTaken())183return false;184185// Instructions in the internal condition blocks should be safe186// to hoist up.187for (BasicBlock::iterator BI = Pred->begin(), BE = PBI->getIterator();188BI != BE;) {189Instruction *CI = &*BI++;190if (isa<PHINode>(CI) || !isSafeToSpeculativelyExecute(CI))191return false;192}193} else {194// This is the condition block to be merged into, e.g. BB1 in195// both cases.196if (FirstCondBlock)197return false;198FirstCondBlock = Pred;199}200201// Find whether BB is uniformly on the true (or false) path202// for all of its predecessors.203BasicBlock *PS1 = PBI->getSuccessor(0);204BasicBlock *PS2 = PBI->getSuccessor(1);205BasicBlock *PS = (PS1 == BB) ? PS2 : PS1;206int CIdx = (PS1 == BB) ? 0 : 1;207208if (Idx == -1)209Idx = CIdx;210else if (CIdx != Idx)211return false;212213// PS is the successor which is not BB. Check successors to identify214// the last conditional branch.215if (!Preds.contains(PS)) {216// Case 2.217LastCondBlock = Pred;218} else {219// Case 1220BranchInst *BPS = dyn_cast<BranchInst>(PS->getTerminator());221if (BPS && BPS->isUnconditional()) {222// Case 1: PS(BB3) should be an unconditional branch.223LastCondBlock = Pred;224}225}226}227228if (!FirstCondBlock || !LastCondBlock || (FirstCondBlock == LastCondBlock))229return false;230231Instruction *TBB = LastCondBlock->getTerminator();232BasicBlock *PS1 = TBB->getSuccessor(0);233BasicBlock *PS2 = TBB->getSuccessor(1);234BranchInst *PBI1 = dyn_cast<BranchInst>(PS1->getTerminator());235BranchInst *PBI2 = dyn_cast<BranchInst>(PS2->getTerminator());236237// If PS1 does not jump into PS2, but PS2 jumps into PS1,238// attempt branch inversion.239if (!PBI1 || !PBI1->isUnconditional() ||240(PS1->getTerminator()->getSuccessor(0) != PS2)) {241// Check whether PS2 jumps into PS1.242if (!PBI2 || !PBI2->isUnconditional() ||243(PS2->getTerminator()->getSuccessor(0) != PS1))244return false;245246// Do branch inversion.247BasicBlock *CurrBlock = LastCondBlock;248bool EverChanged = false;249for (; CurrBlock != FirstCondBlock;250CurrBlock = CurrBlock->getSinglePredecessor()) {251auto *BI = cast<BranchInst>(CurrBlock->getTerminator());252auto *CI = dyn_cast<CmpInst>(BI->getCondition());253if (!CI)254continue;255256CmpInst::Predicate Predicate = CI->getPredicate();257// Canonicalize icmp_ne -> icmp_eq, fcmp_one -> fcmp_oeq258if ((Predicate == CmpInst::ICMP_NE) || (Predicate == CmpInst::FCMP_ONE)) {259CI->setPredicate(ICmpInst::getInversePredicate(Predicate));260BI->swapSuccessors();261EverChanged = true;262}263}264return EverChanged;265}266267// PS1 must have a conditional branch.268if (!PBI1 || !PBI1->isUnconditional())269return false;270271// PS2 should not contain PHI node.272PHI = dyn_cast<PHINode>(PS2->begin());273if (PHI)274return false;275276// Do the transformation.277BasicBlock *CB;278BranchInst *PBI = cast<BranchInst>(FirstCondBlock->getTerminator());279bool Iteration = true;280IRBuilder<>::InsertPointGuard Guard(Builder);281Value *PC = PBI->getCondition();282283do {284CB = PBI->getSuccessor(1 - Idx);285// Delete the conditional branch.286FirstCondBlock->back().eraseFromParent();287FirstCondBlock->splice(FirstCondBlock->end(), CB);288PBI = cast<BranchInst>(FirstCondBlock->getTerminator());289Value *CC = PBI->getCondition();290// Merge conditions.291Builder.SetInsertPoint(PBI);292Value *NC;293if (Idx == 0)294// Case 2, use parallel or.295NC = Builder.CreateOr(PC, CC);296else297// Case 1, use parallel and.298NC = Builder.CreateAnd(PC, CC);299300PBI->replaceUsesOfWith(CC, NC);301PC = NC;302if (CB == LastCondBlock)303Iteration = false;304// Remove internal conditional branches.305CB->dropAllReferences();306// make CB unreachable and let downstream to delete the block.307new UnreachableInst(CB->getContext(), CB);308} while (Iteration);309310LLVM_DEBUG(dbgs() << "Use parallel and/or in:\n" << *FirstCondBlock);311return true;312}313314/// Compare blocks from two if-regions, where \param Head2 is the entry of the315/// 2nd if-region. \param Block1 is a block in the 1st if-region to compare.316/// \param Block2 is a block in the 2nd if-region to compare. \returns true if317/// Block1 and Block2 have identical instructions and do not have318/// memory reference alias with Head2.319bool FlattenCFGOpt::CompareIfRegionBlock(BasicBlock *Block1, BasicBlock *Block2,320BasicBlock *Head2) {321Instruction *PTI2 = Head2->getTerminator();322Instruction *PBI2 = &Head2->front();323324// Check whether instructions in Block1 and Block2 are identical325// and do not alias with instructions in Head2.326BasicBlock::iterator iter1 = Block1->begin();327BasicBlock::iterator end1 = Block1->getTerminator()->getIterator();328BasicBlock::iterator iter2 = Block2->begin();329BasicBlock::iterator end2 = Block2->getTerminator()->getIterator();330331while (true) {332if (iter1 == end1) {333if (iter2 != end2)334return false;335break;336}337338if (!iter1->isIdenticalTo(&*iter2))339return false;340341// Illegal to remove instructions with side effects except342// non-volatile stores.343if (iter1->mayHaveSideEffects()) {344Instruction *CurI = &*iter1;345StoreInst *SI = dyn_cast<StoreInst>(CurI);346if (!SI || SI->isVolatile())347return false;348}349350// For simplicity and speed, data dependency check can be351// avoided if read from memory doesn't exist.352if (iter1->mayReadFromMemory())353return false;354355if (iter1->mayWriteToMemory()) {356for (BasicBlock::iterator BI(PBI2), BE(PTI2); BI != BE; ++BI) {357if (BI->mayReadFromMemory() || BI->mayWriteToMemory()) {358// Check alias with Head2.359if (!AA || !AA->isNoAlias(&*iter1, &*BI))360return false;361}362}363}364++iter1;365++iter2;366}367368return true;369}370371/// Check whether \param BB is the merge block of a if-region. If yes, check372/// whether there exists an adjacent if-region upstream, the two if-regions373/// contain identical instructions and can be legally merged. \returns true if374/// the two if-regions are merged.375///376/// From:377/// if (a)378/// statement;379/// if (b)380/// statement;381///382/// To:383/// if (a || b)384/// statement;385///386///387/// And from:388/// if (a)389/// ;390/// else391/// statement;392/// if (b)393/// ;394/// else395/// statement;396///397/// To:398/// if (a && b)399/// ;400/// else401/// statement;402///403/// We always take the form of the first if-region. This means that if the404/// statement in the first if-region, is in the "then-path", while in the second405/// if-region it is in the "else-path", then we convert the second to the first406/// form, by inverting the condition and the branch successors. The same407/// approach goes for the opposite case.408bool FlattenCFGOpt::MergeIfRegion(BasicBlock *BB, IRBuilder<> &Builder) {409// We cannot merge the if-region if the merge point has phi nodes.410if (isa<PHINode>(BB->front()))411return false;412413BasicBlock *IfTrue2, *IfFalse2;414BranchInst *DomBI2 = GetIfCondition(BB, IfTrue2, IfFalse2);415if (!DomBI2)416return false;417Instruction *CInst2 = dyn_cast<Instruction>(DomBI2->getCondition());418if (!CInst2)419return false;420421BasicBlock *SecondEntryBlock = CInst2->getParent();422if (SecondEntryBlock->hasAddressTaken())423return false;424425BasicBlock *IfTrue1, *IfFalse1;426BranchInst *DomBI1 = GetIfCondition(SecondEntryBlock, IfTrue1, IfFalse1);427if (!DomBI1)428return false;429Instruction *CInst1 = dyn_cast<Instruction>(DomBI1->getCondition());430if (!CInst1)431return false;432433BasicBlock *FirstEntryBlock = CInst1->getParent();434// Don't die trying to process degenerate/unreachable code.435if (FirstEntryBlock == SecondEntryBlock)436return false;437438// Either then-path or else-path should be empty.439bool InvertCond2 = false;440BinaryOperator::BinaryOps CombineOp;441if (IfFalse1 == FirstEntryBlock) {442// The else-path is empty, so we must use "or" operation to combine the443// conditions.444CombineOp = BinaryOperator::Or;445if (IfFalse2 != SecondEntryBlock) {446if (IfTrue2 != SecondEntryBlock)447return false;448449InvertCond2 = true;450std::swap(IfTrue2, IfFalse2);451}452453if (!CompareIfRegionBlock(IfTrue1, IfTrue2, SecondEntryBlock))454return false;455} else if (IfTrue1 == FirstEntryBlock) {456// The then-path is empty, so we must use "and" operation to combine the457// conditions.458CombineOp = BinaryOperator::And;459if (IfTrue2 != SecondEntryBlock) {460if (IfFalse2 != SecondEntryBlock)461return false;462463InvertCond2 = true;464std::swap(IfTrue2, IfFalse2);465}466467if (!CompareIfRegionBlock(IfFalse1, IfFalse2, SecondEntryBlock))468return false;469} else470return false;471472Instruction *PTI2 = SecondEntryBlock->getTerminator();473Instruction *PBI2 = &SecondEntryBlock->front();474475// Check whether \param SecondEntryBlock has side-effect and is safe to476// speculate.477for (BasicBlock::iterator BI(PBI2), BE(PTI2); BI != BE; ++BI) {478Instruction *CI = &*BI;479if (isa<PHINode>(CI) || CI->mayHaveSideEffects() ||480!isSafeToSpeculativelyExecute(CI))481return false;482}483484// Merge \param SecondEntryBlock into \param FirstEntryBlock.485FirstEntryBlock->back().eraseFromParent();486FirstEntryBlock->splice(FirstEntryBlock->end(), SecondEntryBlock);487BranchInst *PBI = cast<BranchInst>(FirstEntryBlock->getTerminator());488assert(PBI->getCondition() == CInst2);489BasicBlock *SaveInsertBB = Builder.GetInsertBlock();490BasicBlock::iterator SaveInsertPt = Builder.GetInsertPoint();491Builder.SetInsertPoint(PBI);492if (InvertCond2) {493InvertBranch(PBI, Builder);494}495Value *NC = Builder.CreateBinOp(CombineOp, CInst1, PBI->getCondition());496PBI->replaceUsesOfWith(PBI->getCondition(), NC);497Builder.SetInsertPoint(SaveInsertBB, SaveInsertPt);498499// Remove IfTrue1500if (IfTrue1 != FirstEntryBlock) {501IfTrue1->dropAllReferences();502IfTrue1->eraseFromParent();503}504505// Remove IfFalse1506if (IfFalse1 != FirstEntryBlock) {507IfFalse1->dropAllReferences();508IfFalse1->eraseFromParent();509}510511// Remove \param SecondEntryBlock512SecondEntryBlock->dropAllReferences();513SecondEntryBlock->eraseFromParent();514LLVM_DEBUG(dbgs() << "If conditions merged into:\n" << *FirstEntryBlock);515return true;516}517518bool FlattenCFGOpt::run(BasicBlock *BB) {519assert(BB && BB->getParent() && "Block not embedded in function!");520assert(BB->getTerminator() && "Degenerate basic block encountered!");521522IRBuilder<> Builder(BB);523524if (FlattenParallelAndOr(BB, Builder) || MergeIfRegion(BB, Builder))525return true;526return false;527}528529/// FlattenCFG - This function is used to flatten a CFG. For530/// example, it uses parallel-and and parallel-or mode to collapse531/// if-conditions and merge if-regions with identical statements.532bool llvm::FlattenCFG(BasicBlock *BB, AAResults *AA) {533return FlattenCFGOpt(AA).run(BB);534}535536537