blob: 1f5957ef911a01305a985370748a8e50098c90bf [file] [log] [blame]
David Blaikie070598b2019-09-18 21:45:05 +00001//===- ReduceArguments.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 Arguments from defined functions.
11//
12//===----------------------------------------------------------------------===//
13
14#include "ReduceBasicBlocks.h"
15#include "llvm/IR/BasicBlock.h"
16#include "llvm/IR/Instruction.h"
17#include "llvm/IR/Instructions.h"
18#include "llvm/IR/LLVMContext.h"
19#include "llvm/IR/Value.h"
20#include "llvm/Support/Casting.h"
21#include "llvm/Support/raw_ostream.h"
22#include <vector>
23
24using namespace llvm;
25
26/// Replaces BB Terminator with one that only contains Chunk BBs
27static void replaceBranchTerminator(BasicBlock &BB,
28 std::set<BasicBlock *> BBsToKeep) {
29 auto Term = BB.getTerminator();
30 std::vector<BasicBlock *> ChunkSucessors;
31 for (auto Succ : successors(&BB))
32 if (BBsToKeep.count(Succ))
33 ChunkSucessors.push_back(Succ);
34
35 // BB only references Chunk BBs
36 if (ChunkSucessors.size() == Term->getNumSuccessors())
37 return;
38
39 Term->eraseFromParent();
40
41 if (ChunkSucessors.empty()) {
42 ReturnInst::Create(BB.getContext(), nullptr, &BB);
43 return;
44 }
45
46 if (isa<BranchInst>(Term))
47 BranchInst::Create(ChunkSucessors[0], &BB);
48
49 if (auto IndBI = dyn_cast<IndirectBrInst>(Term)) {
50 auto NewIndBI =
51 IndirectBrInst::Create(IndBI->getAddress(), ChunkSucessors.size(), &BB);
52 for (auto Dest : ChunkSucessors)
53 NewIndBI->addDestination(Dest);
54 }
55}
56
57/// Removes uninteresting BBs from switch, if the default case ends up being
58/// uninteresting, the switch is replaced with a void return (since it has to be
59/// replace with something)
60static void removeUninterestingBBsFromSwitch(SwitchInst &SwInst,
61 std::set<BasicBlock *> BBsToKeep) {
62 if (!BBsToKeep.count(SwInst.getDefaultDest())) {
63 ReturnInst::Create(SwInst.getContext(), nullptr, SwInst.getParent());
64 SwInst.eraseFromParent();
65 } else
66 for (int I = 0, E = SwInst.getNumCases(); I != E; ++I) {
67 auto Case = SwInst.case_begin() + I;
68 if (!BBsToKeep.count(Case->getCaseSuccessor())) {
69 SwInst.removeCase(Case);
70 --I;
71 --E;
72 }
73 }
74}
75
76/// Removes out-of-chunk arguments from functions, and modifies their calls
77/// accordingly. It also removes allocations of out-of-chunk arguments.
78/// @returns the Module stripped of out-of-chunk functions
79static void extractBasicBlocksFromModule(std::vector<Chunk> ChunksToKeep,
80 Module *Program) {
David Blaikiec4da7ee2019-09-18 22:30:25 +000081 int I = 0, BBCount = 0;
David Blaikie070598b2019-09-18 21:45:05 +000082 std::set<BasicBlock *> BBsToKeep;
83
84 for (auto &F : *Program)
85 for (auto &BB : F)
David Blaikiec4da7ee2019-09-18 22:30:25 +000086 if (I < (int)ChunksToKeep.size()) {
David Blaikie070598b2019-09-18 21:45:05 +000087 if (ChunksToKeep[I].contains(++BBCount))
88 BBsToKeep.insert(&BB);
89 if (ChunksToKeep[I].end == BBCount)
90 ++I;
91 }
92
93 std::vector<BasicBlock *> BBsToDelete;
94 for (auto &F : *Program)
95 for (auto &BB : F) {
96 if (!BBsToKeep.count(&BB)) {
97 BBsToDelete.push_back(&BB);
98 // Remove out-of-chunk BB from successor phi nodes
99 for (auto *Succ : successors(&BB))
100 Succ->removePredecessor(&BB);
101 }
102 }
103
104 // Replace terminators that reference out-of-chunk BBs
105 for (auto &F : *Program)
106 for (auto &BB : F) {
107 if (auto *SwInst = dyn_cast<SwitchInst>(BB.getTerminator()))
108 removeUninterestingBBsFromSwitch(*SwInst, BBsToKeep);
109 else
110 replaceBranchTerminator(BB, BBsToKeep);
111 }
112
113 // Replace out-of-chunk switch uses
114 for (auto &BB : BBsToDelete) {
115 // Instructions might be referenced in other BBs
116 for (auto &I : *BB)
117 I.replaceAllUsesWith(UndefValue::get(I.getType()));
118 BB->eraseFromParent();
119 }
120}
121
122/// Counts the amount of basic blocks and prints their name & respective index
David Blaikiec4da7ee2019-09-18 22:30:25 +0000123static int countBasicBlocks(Module *Program) {
David Blaikie070598b2019-09-18 21:45:05 +0000124 // TODO: Silence index with --quiet flag
125 outs() << "----------------------------\n";
126 int BBCount = 0;
127 for (auto &F : *Program)
128 for (auto &BB : F) {
129 if (BB.hasName())
130 outs() << "\t" << ++BBCount << ": " << BB.getName() << "\n";
131 else
132 outs() << "\t" << ++BBCount << ": Unnamed\n";
133 }
134
135 return BBCount;
136}
137
138void llvm::reduceBasicBlocksDeltaPass(TestRunner &Test) {
139 outs() << "*** Reducing Basic Blocks...\n";
David Blaikiec4da7ee2019-09-18 22:30:25 +0000140 int BBCount = countBasicBlocks(Test.getProgram());
David Blaikie070598b2019-09-18 21:45:05 +0000141 runDeltaPass(Test, BBCount, extractBasicBlocksFromModule);
142}