2 #include <unordered_set>
4 #include "../IRContextPass.h"
5 #include "diagnostics/Diagnostics.h"
6 #include "tir/BasicBlock.h"
7 #include "tir/Constant.h"
8 #include "tir/Instructions.h"
9 #include "utils/PassManager.h"
11 using std::string_view;
13 using utils::PassManager;
30 class DominantorTree {
32 DominantorTree(Function* func) : func(func) {
33 computePostorderIdx(func);
34 computeDominators(func);
35 computeFrontiers(func);
38 std::ostream& print(std::ostream& os)
const {
40 os <<
"*** Dominator Tree ***\n";
42 if(doms.contains(b)) {
44 b->printName(os) <<
") = ";
45 doms.at(b)->printName(os) << std::endl;
49 os <<
"*** Dominance Frontier ***\n";
50 for(
auto [b, frontier] : frontiers) {
52 b->printName(os) <<
") = {";
54 for(
auto f : frontier) {
55 if(!first) os <<
", ";
65 auto& DF(BasicBlock* b) {
return frontiers[b]; }
68 BasicBlock* getIDom(BasicBlock* b) {
69 return doms.contains(b) ? doms.at(b) :
nullptr;
74 std::unordered_map<BasicBlock*, BasicBlock*> doms;
75 std::unordered_map<BasicBlock*,
int> poidx;
76 std::unordered_map<BasicBlock*, std::unordered_set<BasicBlock*>> frontiers;
78 void computePostorderIdx(Function* func);
79 void computeDominators(Function* func);
80 BasicBlock* intersect(BasicBlock* b1, BasicBlock* b2);
81 void computeFrontiers(Function* func);
94 HoistAlloca(Function* func, DE& diag) : func(func), DT{func} {
97 auto dbg = diag.ReportDebug();
101 for(
auto alloca : func->allocas()) {
102 if(canAllocaBeReplaced(alloca)) {
103 placePHINodes(alloca);
109 print(diag.ReportDebug().get());
113 std::ostream& print(std::ostream& os)
const {
114 os <<
"*** PHI node insertion points ***\n";
115 for(
auto [alloca, phis] : allocaPhiMap) {
116 os <<
" Insert PHI for: ";
117 alloca->printName(os) <<
"\n";
118 for(
auto bb : phis) {
120 bb->printName(os) <<
"\n";
130 std::unordered_map<AllocaInst*, std::vector<BasicBlock*>> allocaPhiMap;
133 void placePHINodes(AllocaInst* alloca);
134 bool canAllocaBeReplaced(AllocaInst* alloca);
135 void replaceUses(AllocaInst* alloca);
142 void DominantorTree::computePostorderIdx(Function* func) {
144 for(
auto b : func->reversePostOrder()) poidx[b] = i++;
147 void DominantorTree::computeDominators(Function* func) {
148 doms[func->getEntryBlock()] = func->getEntryBlock();
152 for(
auto b : func->reversePostOrder()) {
153 BasicBlock* newIdom =
nullptr;
154 for(
auto pred : b->predecessors()) {
155 if(doms.contains(pred)) {
159 newIdom = intersect(pred, newIdom);
163 if(!newIdom)
continue;
164 if(!doms.contains(b) || doms[b] != newIdom) {
172 BasicBlock* DominantorTree::intersect(BasicBlock* b1, BasicBlock* b2) {
173 BasicBlock* finger1 = b1;
174 BasicBlock* finger2 = b2;
175 while(finger1 != finger2) {
176 while(poidx[finger1] > poidx[finger2]) finger1 = doms[finger1];
177 while(poidx[finger2] > poidx[finger1]) finger2 = doms[finger2];
182 void DominantorTree::computeFrontiers(Function* func) {
185 for(
auto p : b->predecessors()) {
189 if(numPreds < 2)
continue;
190 for(
auto pred : b->predecessors()) {
191 BasicBlock* runner = pred;
192 while(runner != doms[b]) {
193 frontiers[runner].insert(b);
194 runner = doms[runner];
204 bool HoistAlloca::canAllocaBeReplaced(AllocaInst* alloca) {
206 if(!alloca->type()->isIntegerType() && !alloca->type()->isPointerType())
209 for(
auto user : alloca->users()) {
210 if(!dyn_cast<LoadInst>(user) && !dyn_cast<StoreInst>(user))
return false;
216 void HoistAlloca::placePHINodes(AllocaInst* V) {
217 std::unordered_set<BasicBlock*> DFPlus;
218 std::unordered_set<BasicBlock*> Work;
219 std::queue<BasicBlock*> W;
221 for(
auto user : V->users()) {
222 if(
auto X = dyn_cast<StoreInst>(user)) {
223 Work.insert(X->parent());
228 BasicBlock* X = W.front();
230 for(
auto Y : DT.DF(X)) {
231 if(DFPlus.contains(Y))
continue;
232 allocaPhiMap[V].push_back(Y);
234 if(!Work.contains(Y)) {
243 void HoistAlloca::replaceUses(AllocaInst* V) {
253 class MemToReg
final :
public Pass {
255 MemToReg(PassManager& PM)
noexcept : Pass(PM) {}
258 for(
auto func : CU.functions()) {
259 if(!func->hasBody() || !func->getEntryBlock())
continue;
260 if(PM().Diag().Verbose()) {
261 PM().Diag().ReportDebug()
262 <<
"*** Running on function: " << func->name() <<
" ***";
264 HoistAlloca hoister{func, PM().Diag()};
271 void computeDependencies()
override {
272 ComputeDependency(GetPass<IRContextPass>());