-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This commit adds the analysis pass to find natural loops and subloops. It uses the algorithm from LLVM LoopInfo anaylsis pass for the same, heavily uses the dominance tree to find the backedges and loop headers.
- Loading branch information
1 parent
3e3518e
commit 7b3bc0a
Showing
5 changed files
with
179 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,114 @@ | ||
#include "blocks/loops.h" | ||
#include <algorithm> | ||
|
||
std::shared_ptr<loop> loop_info::allocate_loop(std::shared_ptr<basic_block> header) { | ||
if (!header) | ||
return nullptr; | ||
|
||
loops.push_back(std::make_shared<loop>(header)); | ||
bb_loop_map[header->id] = loops.back(); | ||
return loops.back(); | ||
} | ||
|
||
void loop_info::analyze() { | ||
std::vector<int> idom = dta.get_idom(); | ||
for (unsigned int i = 0; i < idom.size(); i++) { | ||
std::cout << i << " : " << idom[i] << "\n"; | ||
|
||
for (int idom_id: dta.get_postorder_idom_map()) { | ||
std::vector<int> backedges; | ||
int header = idom_id; | ||
|
||
for (auto backedge: dta.cfg_[header]->predecessor) { | ||
if (dta.dominates(header, backedge->id) && dta.is_reachable_from_entry(backedge->id)) { | ||
backedges.push_back(backedge->id); | ||
} | ||
} | ||
|
||
if (!backedges.empty()) { | ||
std::shared_ptr<loop> new_loop = allocate_loop(dta.cfg_[header]); | ||
if (!new_loop) | ||
continue; | ||
|
||
int num_blocks = 0; | ||
int num_subloops = 0; | ||
|
||
auto backedge_iter = backedges.begin(); | ||
// do a reverse CFG traversal to map basic blocks in this loop. | ||
basic_block::cfg_block worklist(backedges.size()); | ||
std::generate(worklist.begin(), worklist.end(), [&backedge_iter, this](){ | ||
return dta.cfg_[*(backedge_iter++)]; | ||
}); | ||
|
||
while (!worklist.empty()) { | ||
unsigned int predecessor_bb_id = worklist.back()->id; | ||
worklist.pop_back(); | ||
|
||
auto subloop_iter = bb_loop_map.find(predecessor_bb_id); | ||
if (subloop_iter == bb_loop_map.end()) { | ||
if (!dta.is_reachable_from_entry(predecessor_bb_id)) | ||
continue; | ||
|
||
bb_loop_map[predecessor_bb_id] = new_loop; | ||
++num_blocks; | ||
// loop has no blocks between header and backedge | ||
if (predecessor_bb_id == new_loop->header_block->id) | ||
continue; | ||
|
||
worklist.insert(worklist.end(), dta.cfg_[predecessor_bb_id]->predecessor.begin(), dta.cfg_[predecessor_bb_id]->predecessor.end()); | ||
} | ||
else { | ||
// this block has already been discovered, mapped to some other loop | ||
// find the outermost loop | ||
std::shared_ptr<loop> subloop = subloop_iter->second; | ||
while (subloop->parent_loop) { | ||
subloop = subloop->parent_loop; | ||
} | ||
|
||
if (subloop == new_loop) | ||
continue; | ||
|
||
// discovered a subloop of this loop | ||
subloop->parent_loop = new_loop; | ||
++num_subloops; | ||
num_blocks = num_blocks + subloop->blocks.size(); | ||
predecessor_bb_id = subloop->header_block->id; | ||
|
||
for (auto pred: dta.cfg_[predecessor_bb_id]->predecessor) { | ||
auto loop_iter = bb_loop_map.find(pred->id); | ||
// do not check if loop_iter != bb_loop_map.end(), as a results | ||
// basic blocks that are not directly part of the natural loops | ||
// are skipped, like loop latches. | ||
if (loop_iter->second != subloop) | ||
worklist.push_back(pred); | ||
} | ||
} | ||
} | ||
new_loop->subloops.reserve(num_subloops); | ||
new_loop->blocks.reserve(num_blocks); | ||
} | ||
} | ||
} | ||
|
||
// populate all subloops and loops with blocks | ||
for (auto bb_id: dta.get_postorder()) { | ||
auto subloop_iter = bb_loop_map.find(bb_id); | ||
std::shared_ptr<loop> subloop = nullptr; | ||
if (subloop_iter != bb_loop_map.end() && (subloop = subloop_iter->second) && dta.cfg_[bb_id] == subloop_iter->second->header_block) { | ||
// check if it is the outermost loop | ||
if (subloop->parent_loop != nullptr) { | ||
subloop->parent_loop->subloops.push_back(subloop); | ||
} | ||
else { | ||
top_level_loops.push_back(subloop); | ||
} | ||
|
||
std::reverse(subloop->blocks.begin(), subloop->blocks.end()); | ||
std::reverse(subloop->subloops.begin(), subloop->subloops.end()); | ||
|
||
subloop = subloop->parent_loop; | ||
} | ||
|
||
while (subloop) { | ||
subloop->blocks.push_back(dta.cfg_[bb_id]); | ||
subloop = subloop->parent_loop; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters