//===- FlatternCFG.cpp - Code to perform CFG flattening -------------------===// // // 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 // //===----------------------------------------------------------------------===// // // Reduce conditional branches in CFG. // //===----------------------------------------------------------------------===// #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Value.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include <cassert> usingnamespacellvm; #define DEBUG_TYPE … namespace { class FlattenCFGOpt { … }; } // end anonymous namespace /// If \param [in] BB has more than one predecessor that is a conditional /// branch, attempt to use parallel and/or for the branch condition. \returns /// true on success. /// /// Before: /// ...... /// %cmp10 = fcmp une float %tmp1, %tmp2 /// br i1 %cmp10, label %if.then, label %lor.rhs /// /// lor.rhs: /// ...... /// %cmp11 = fcmp une float %tmp3, %tmp4 /// br i1 %cmp11, label %if.then, label %ifend /// /// if.end: // the merge block /// ...... /// /// if.then: // has two predecessors, both of them contains conditional branch. /// ...... /// br label %if.end; /// /// After: /// ...... /// %cmp10 = fcmp une float %tmp1, %tmp2 /// ...... /// %cmp11 = fcmp une float %tmp3, %tmp4 /// %cmp12 = or i1 %cmp10, %cmp11 // parallel-or mode. /// br i1 %cmp12, label %if.then, label %ifend /// /// if.end: /// ...... /// /// if.then: /// ...... /// br label %if.end; /// /// Current implementation handles two cases. /// Case 1: BB is on the else-path. /// /// BB1 /// / | /// BB2 | /// / \ | /// BB3 \ | where, BB1, BB2 contain conditional branches. /// \ | / BB3 contains unconditional branch. /// \ | / BB4 corresponds to BB which is also the merge. /// BB => BB4 /// /// /// Corresponding source code: /// /// if (a == b && c == d) /// statement; // BB3 /// /// Case 2: BB is on the then-path. /// /// BB1 /// / | /// | BB2 /// \ / | where BB1, BB2 contain conditional branches. /// BB => BB3 | BB3 contains unconditiona branch and corresponds /// \ / to BB. BB4 is the merge. /// BB4 /// /// Corresponding source code: /// /// if (a == b || c == d) /// statement; // BB3 /// /// In both cases, BB is the common successor of conditional branches. /// In Case 1, BB (BB4) has an unconditional branch (BB3) as /// its predecessor. In Case 2, BB (BB3) only has conditional branches /// as its predecessors. bool FlattenCFGOpt::FlattenParallelAndOr(BasicBlock *BB, IRBuilder<> &Builder) { … } /// Compare blocks from two if-regions, where \param Head2 is the entry of the /// 2nd if-region. \param Block1 is a block in the 1st if-region to compare. /// \param Block2 is a block in the 2nd if-region to compare. \returns true if /// Block1 and Block2 have identical instructions and do not have /// memory reference alias with Head2. bool FlattenCFGOpt::CompareIfRegionBlock(BasicBlock *Block1, BasicBlock *Block2, BasicBlock *Head2) { … } /// Check whether \param BB is the merge block of a if-region. If yes, check /// whether there exists an adjacent if-region upstream, the two if-regions /// contain identical instructions and can be legally merged. \returns true if /// the two if-regions are merged. /// /// From: /// if (a) /// statement; /// if (b) /// statement; /// /// To: /// if (a || b) /// statement; /// /// /// And from: /// if (a) /// ; /// else /// statement; /// if (b) /// ; /// else /// statement; /// /// To: /// if (a && b) /// ; /// else /// statement; /// /// We always take the form of the first if-region. This means that if the /// statement in the first if-region, is in the "then-path", while in the second /// if-region it is in the "else-path", then we convert the second to the first /// form, by inverting the condition and the branch successors. The same /// approach goes for the opposite case. bool FlattenCFGOpt::MergeIfRegion(BasicBlock *BB, IRBuilder<> &Builder) { … } bool FlattenCFGOpt::run(BasicBlock *BB) { … } /// FlattenCFG - This function is used to flatten a CFG. For /// example, it uses parallel-and and parallel-or mode to collapse /// if-conditions and merge if-regions with identical statements. bool llvm::FlattenCFG(BasicBlock *BB, AAResults *AA) { … }