16f3f19a3SMatt Arsenault //===- ReduceBasicBlocks.cpp - Specialized Delta Pass ---------------------===//
2070598bbSDavid Blaikie //
3070598bbSDavid Blaikie // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4070598bbSDavid Blaikie // See https://llvm.org/LICENSE.txt for license information.
5070598bbSDavid Blaikie // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6070598bbSDavid Blaikie //
7070598bbSDavid Blaikie //===----------------------------------------------------------------------===//
8070598bbSDavid Blaikie //
9070598bbSDavid Blaikie // This file implements a function which calls the Generic Delta pass in order
106f3f19a3SMatt Arsenault // to reduce uninteresting BasicBlocks from defined functions.
11070598bbSDavid Blaikie //
12070598bbSDavid Blaikie //===----------------------------------------------------------------------===//
13070598bbSDavid Blaikie 
14070598bbSDavid Blaikie #include "ReduceBasicBlocks.h"
15*2962f9dfSJohn Regehr #include "Utils.h"
16cd8aa234SFlorian Hahn #include "llvm/ADT/DenseSet.h"
17070598bbSDavid Blaikie #include "llvm/IR/BasicBlock.h"
18a5bbc6efSBill Wendling #include "llvm/IR/Constants.h"
19070598bbSDavid Blaikie #include "llvm/IR/Instruction.h"
20070598bbSDavid Blaikie #include "llvm/IR/Instructions.h"
21070598bbSDavid Blaikie #include "llvm/IR/LLVMContext.h"
22070598bbSDavid Blaikie #include "llvm/IR/Value.h"
23070598bbSDavid Blaikie #include "llvm/Support/Casting.h"
24070598bbSDavid Blaikie #include "llvm/Support/raw_ostream.h"
25070598bbSDavid Blaikie #include <vector>
26070598bbSDavid Blaikie 
27070598bbSDavid Blaikie using namespace llvm;
28070598bbSDavid Blaikie 
29070598bbSDavid Blaikie /// Replaces BB Terminator with one that only contains Chunk BBs
replaceBranchTerminator(BasicBlock & BB,const DenseSet<BasicBlock * > & BBsToKeep)30070598bbSDavid Blaikie static void replaceBranchTerminator(BasicBlock &BB,
31cd8aa234SFlorian Hahn                                     const DenseSet<BasicBlock *> &BBsToKeep) {
3256fa1b4fSSamuel   auto *Term = BB.getTerminator();
33f7db8b7aSMatt Arsenault   std::vector<BasicBlock *> ChunkSuccessors;
3456fa1b4fSSamuel   for (auto *Succ : successors(&BB))
35070598bbSDavid Blaikie     if (BBsToKeep.count(Succ))
36f7db8b7aSMatt Arsenault       ChunkSuccessors.push_back(Succ);
37070598bbSDavid Blaikie 
38070598bbSDavid Blaikie   // BB only references Chunk BBs
39f7db8b7aSMatt Arsenault   if (ChunkSuccessors.size() == Term->getNumSuccessors())
40070598bbSDavid Blaikie     return;
41070598bbSDavid Blaikie 
42af1dd0b1SRoman Lebedev   bool IsBranch = isa<BranchInst>(Term) || isa<InvokeInst>(Term);
43fa7f168aSDavid Blaikie   Value *Address = nullptr;
4456fa1b4fSSamuel   if (auto *IndBI = dyn_cast<IndirectBrInst>(Term))
45fa7f168aSDavid Blaikie     Address = IndBI->getAddress();
46fa7f168aSDavid Blaikie 
47*2962f9dfSJohn Regehr   Term->replaceAllUsesWith(getDefaultValue(Term->getType()));
48070598bbSDavid Blaikie   Term->eraseFromParent();
49070598bbSDavid Blaikie 
50f7db8b7aSMatt Arsenault   if (ChunkSuccessors.empty()) {
51bb8e0232SMarkus Lavin     // Scan forward in BB list to try find a block that is kept.
52bb8e0232SMarkus Lavin     Function &F = *BB.getParent();
53bb8e0232SMarkus Lavin     Function::iterator FI = BB.getIterator();
54bb8e0232SMarkus Lavin     FI++;
55bb8e0232SMarkus Lavin     while (FI != F.end()) {
56bb8e0232SMarkus Lavin       auto &FIB = *FI;
57bb8e0232SMarkus Lavin       if (BBsToKeep.count(&FIB) && !isa<PHINode>(FIB.begin())) {
58bb8e0232SMarkus Lavin         BranchInst::Create(&FIB, &BB);
59bb8e0232SMarkus Lavin         return;
60bb8e0232SMarkus Lavin       }
61bb8e0232SMarkus Lavin       FI++;
62bb8e0232SMarkus Lavin     }
63bb8e0232SMarkus Lavin     // If that fails then resort to replacing with a ret.
64a5bb2475SFlorian Hahn     auto *FnRetTy = BB.getParent()->getReturnType();
65a5bb2475SFlorian Hahn     ReturnInst::Create(BB.getContext(),
66*2962f9dfSJohn Regehr                        FnRetTy->isVoidTy() ? nullptr : getDefaultValue(FnRetTy),
67a5bb2475SFlorian Hahn                        &BB);
68070598bbSDavid Blaikie     return;
69070598bbSDavid Blaikie   }
70070598bbSDavid Blaikie 
71fa7f168aSDavid Blaikie   if (IsBranch)
72f7db8b7aSMatt Arsenault     BranchInst::Create(ChunkSuccessors[0], &BB);
73070598bbSDavid Blaikie 
741796aad5SDavid Blaikie   if (Address) {
7556fa1b4fSSamuel     auto *NewIndBI =
76f7db8b7aSMatt Arsenault         IndirectBrInst::Create(Address, ChunkSuccessors.size(), &BB);
77f7db8b7aSMatt Arsenault     for (auto *Dest : ChunkSuccessors)
78070598bbSDavid Blaikie       NewIndBI->addDestination(Dest);
79070598bbSDavid Blaikie   }
80070598bbSDavid Blaikie }
81070598bbSDavid Blaikie 
82070598bbSDavid Blaikie /// Removes uninteresting BBs from switch, if the default case ends up being
83070598bbSDavid Blaikie /// uninteresting, the switch is replaced with a void return (since it has to be
84070598bbSDavid Blaikie /// replace with something)
852f161736SDwight Guth static void
removeUninterestingBBsFromSwitch(SwitchInst & SwInst,const DenseSet<BasicBlock * > & BBsToKeep)862f161736SDwight Guth removeUninterestingBBsFromSwitch(SwitchInst &SwInst,
87cd8aa234SFlorian Hahn                                  const DenseSet<BasicBlock *> &BBsToKeep) {
88070598bbSDavid Blaikie   if (!BBsToKeep.count(SwInst.getDefaultDest())) {
89a5bb2475SFlorian Hahn     auto *FnRetTy = SwInst.getParent()->getParent()->getReturnType();
90a5bb2475SFlorian Hahn     ReturnInst::Create(SwInst.getContext(),
91*2962f9dfSJohn Regehr                        FnRetTy->isVoidTy() ? nullptr : getDefaultValue(FnRetTy),
92a5bb2475SFlorian Hahn                        SwInst.getParent());
93070598bbSDavid Blaikie     SwInst.eraseFromParent();
94070598bbSDavid Blaikie   } else
95070598bbSDavid Blaikie     for (int I = 0, E = SwInst.getNumCases(); I != E; ++I) {
96070598bbSDavid Blaikie       auto Case = SwInst.case_begin() + I;
97070598bbSDavid Blaikie       if (!BBsToKeep.count(Case->getCaseSuccessor())) {
98070598bbSDavid Blaikie         SwInst.removeCase(Case);
99070598bbSDavid Blaikie         --I;
100070598bbSDavid Blaikie         --E;
101070598bbSDavid Blaikie       }
102070598bbSDavid Blaikie     }
103070598bbSDavid Blaikie }
104070598bbSDavid Blaikie 
105070598bbSDavid Blaikie /// Removes out-of-chunk arguments from functions, and modifies their calls
106070598bbSDavid Blaikie /// accordingly. It also removes allocations of out-of-chunk arguments.
extractBasicBlocksFromModule(Oracle & O,Module & Program)10777bc3ba3SArthur Eubanks static void extractBasicBlocksFromModule(Oracle &O, Module &Program) {
1084081df43SFlorian Hahn   DenseSet<BasicBlock *> BBsToKeep;
109070598bbSDavid Blaikie 
1104081df43SFlorian Hahn   SmallVector<BasicBlock *> BBsToDelete;
1114081df43SFlorian Hahn   for (auto &F : Program) {
112070598bbSDavid Blaikie     for (auto &BB : F) {
1134081df43SFlorian Hahn       if (O.shouldKeep())
1144081df43SFlorian Hahn         BBsToKeep.insert(&BB);
1154081df43SFlorian Hahn       else {
116070598bbSDavid Blaikie         BBsToDelete.push_back(&BB);
117070598bbSDavid Blaikie         // Remove out-of-chunk BB from successor phi nodes
118070598bbSDavid Blaikie         for (auto *Succ : successors(&BB))
119070598bbSDavid Blaikie           Succ->removePredecessor(&BB);
120070598bbSDavid Blaikie       }
121070598bbSDavid Blaikie     }
1224081df43SFlorian Hahn   }
123070598bbSDavid Blaikie 
124070598bbSDavid Blaikie   // Replace terminators that reference out-of-chunk BBs
12577bc3ba3SArthur Eubanks   for (auto &F : Program)
126070598bbSDavid Blaikie     for (auto &BB : F) {
127070598bbSDavid Blaikie       if (auto *SwInst = dyn_cast<SwitchInst>(BB.getTerminator()))
128070598bbSDavid Blaikie         removeUninterestingBBsFromSwitch(*SwInst, BBsToKeep);
129070598bbSDavid Blaikie       else
130070598bbSDavid Blaikie         replaceBranchTerminator(BB, BBsToKeep);
131070598bbSDavid Blaikie     }
132070598bbSDavid Blaikie 
133070598bbSDavid Blaikie   // Replace out-of-chunk switch uses
134070598bbSDavid Blaikie   for (auto &BB : BBsToDelete) {
135070598bbSDavid Blaikie     // Instructions might be referenced in other BBs
136070598bbSDavid Blaikie     for (auto &I : *BB)
137*2962f9dfSJohn Regehr       I.replaceAllUsesWith(getDefaultValue(I.getType()));
13816c3db8dSDwight Guth     if (BB->getParent()->size() == 1) {
13916c3db8dSDwight Guth       // this is the last basic block of the function, thus we must also make
14016c3db8dSDwight Guth       // sure to remove comdat and set linkage to external
14116c3db8dSDwight Guth       auto F = BB->getParent();
14216c3db8dSDwight Guth       F->deleteBody();
14316c3db8dSDwight Guth       F->setComdat(nullptr);
14416c3db8dSDwight Guth     } else {
145070598bbSDavid Blaikie       BB->eraseFromParent();
146070598bbSDavid Blaikie     }
147070598bbSDavid Blaikie   }
14816c3db8dSDwight Guth }
149070598bbSDavid Blaikie 
reduceBasicBlocksDeltaPass(TestRunner & Test)150070598bbSDavid Blaikie void llvm::reduceBasicBlocksDeltaPass(TestRunner &Test) {
151070598bbSDavid Blaikie   outs() << "*** Reducing Basic Blocks...\n";
1526f288bd7SArthur Eubanks   runDeltaPass(Test, extractBasicBlocksFromModule);
153070598bbSDavid Blaikie }
154