1 //===- ReduceBasicBlocks.cpp - Specialized Delta Pass ---------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements a function which calls the Generic Delta pass in order
10 // to reduce uninteresting BasicBlocks from defined functions.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "ReduceBasicBlocks.h"
15 #include "Utils.h"
16 #include "llvm/ADT/DenseSet.h"
17 #include "llvm/IR/BasicBlock.h"
18 #include "llvm/IR/Constants.h"
19 #include "llvm/IR/Instruction.h"
20 #include "llvm/IR/Instructions.h"
21 #include "llvm/IR/LLVMContext.h"
22 #include "llvm/IR/Value.h"
23 #include "llvm/Support/Casting.h"
24 #include "llvm/Support/raw_ostream.h"
25 #include <vector>
26 
27 using namespace llvm;
28 
29 /// Replaces BB Terminator with one that only contains Chunk BBs
replaceBranchTerminator(BasicBlock & BB,const DenseSet<BasicBlock * > & BBsToKeep)30 static void replaceBranchTerminator(BasicBlock &BB,
31                                     const DenseSet<BasicBlock *> &BBsToKeep) {
32   auto *Term = BB.getTerminator();
33   std::vector<BasicBlock *> ChunkSuccessors;
34   for (auto *Succ : successors(&BB))
35     if (BBsToKeep.count(Succ))
36       ChunkSuccessors.push_back(Succ);
37 
38   // BB only references Chunk BBs
39   if (ChunkSuccessors.size() == Term->getNumSuccessors())
40     return;
41 
42   bool IsBranch = isa<BranchInst>(Term) || isa<InvokeInst>(Term);
43   Value *Address = nullptr;
44   if (auto *IndBI = dyn_cast<IndirectBrInst>(Term))
45     Address = IndBI->getAddress();
46 
47   Term->replaceAllUsesWith(getDefaultValue(Term->getType()));
48   Term->eraseFromParent();
49 
50   if (ChunkSuccessors.empty()) {
51     // Scan forward in BB list to try find a block that is kept.
52     Function &F = *BB.getParent();
53     Function::iterator FI = BB.getIterator();
54     FI++;
55     while (FI != F.end()) {
56       auto &FIB = *FI;
57       if (BBsToKeep.count(&FIB) && !isa<PHINode>(FIB.begin())) {
58         BranchInst::Create(&FIB, &BB);
59         return;
60       }
61       FI++;
62     }
63     // If that fails then resort to replacing with a ret.
64     auto *FnRetTy = BB.getParent()->getReturnType();
65     ReturnInst::Create(BB.getContext(),
66                        FnRetTy->isVoidTy() ? nullptr : getDefaultValue(FnRetTy),
67                        &BB);
68     return;
69   }
70 
71   if (IsBranch)
72     BranchInst::Create(ChunkSuccessors[0], &BB);
73 
74   if (Address) {
75     auto *NewIndBI =
76         IndirectBrInst::Create(Address, ChunkSuccessors.size(), &BB);
77     for (auto *Dest : ChunkSuccessors)
78       NewIndBI->addDestination(Dest);
79   }
80 }
81 
82 /// Removes uninteresting BBs from switch, if the default case ends up being
83 /// uninteresting, the switch is replaced with a void return (since it has to be
84 /// replace with something)
85 static void
removeUninterestingBBsFromSwitch(SwitchInst & SwInst,const DenseSet<BasicBlock * > & BBsToKeep)86 removeUninterestingBBsFromSwitch(SwitchInst &SwInst,
87                                  const DenseSet<BasicBlock *> &BBsToKeep) {
88   if (!BBsToKeep.count(SwInst.getDefaultDest())) {
89     auto *FnRetTy = SwInst.getParent()->getParent()->getReturnType();
90     ReturnInst::Create(SwInst.getContext(),
91                        FnRetTy->isVoidTy() ? nullptr : getDefaultValue(FnRetTy),
92                        SwInst.getParent());
93     SwInst.eraseFromParent();
94   } else
95     for (int I = 0, E = SwInst.getNumCases(); I != E; ++I) {
96       auto Case = SwInst.case_begin() + I;
97       if (!BBsToKeep.count(Case->getCaseSuccessor())) {
98         SwInst.removeCase(Case);
99         --I;
100         --E;
101       }
102     }
103 }
104 
105 /// Removes out-of-chunk arguments from functions, and modifies their calls
106 /// accordingly. It also removes allocations of out-of-chunk arguments.
extractBasicBlocksFromModule(Oracle & O,Module & Program)107 static void extractBasicBlocksFromModule(Oracle &O, Module &Program) {
108   DenseSet<BasicBlock *> BBsToKeep;
109 
110   SmallVector<BasicBlock *> BBsToDelete;
111   for (auto &F : Program) {
112     for (auto &BB : F) {
113       if (O.shouldKeep())
114         BBsToKeep.insert(&BB);
115       else {
116         BBsToDelete.push_back(&BB);
117         // Remove out-of-chunk BB from successor phi nodes
118         for (auto *Succ : successors(&BB))
119           Succ->removePredecessor(&BB);
120       }
121     }
122   }
123 
124   // Replace terminators that reference out-of-chunk BBs
125   for (auto &F : Program)
126     for (auto &BB : F) {
127       if (auto *SwInst = dyn_cast<SwitchInst>(BB.getTerminator()))
128         removeUninterestingBBsFromSwitch(*SwInst, BBsToKeep);
129       else
130         replaceBranchTerminator(BB, BBsToKeep);
131     }
132 
133   // Replace out-of-chunk switch uses
134   for (auto &BB : BBsToDelete) {
135     // Instructions might be referenced in other BBs
136     for (auto &I : *BB)
137       I.replaceAllUsesWith(getDefaultValue(I.getType()));
138     if (BB->getParent()->size() == 1) {
139       // this is the last basic block of the function, thus we must also make
140       // sure to remove comdat and set linkage to external
141       auto F = BB->getParent();
142       F->deleteBody();
143       F->setComdat(nullptr);
144     } else {
145       BB->eraseFromParent();
146     }
147   }
148 }
149 
reduceBasicBlocksDeltaPass(TestRunner & Test)150 void llvm::reduceBasicBlocksDeltaPass(TestRunner &Test) {
151   outs() << "*** Reducing Basic Blocks...\n";
152   runDeltaPass(Test, extractBasicBlocksFromModule);
153 }
154