| 1 | //===- PostOrderCFGView.cpp - Post order view of CFG blocks ---------------===// |
| 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 post order view of the blocks in a CFG. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #include "clang/Analysis/Analyses/PostOrderCFGView.h" |
| 14 | #include "clang/Analysis/AnalysisDeclContext.h" |
| 15 | #include "clang/Analysis/CFG.h" |
| 16 | |
| 17 | using namespace clang; |
| 18 | |
| 19 | void PostOrderCFGView::anchor() {} |
| 20 | |
| 21 | PostOrderCFGView::PostOrderCFGView(const CFG *cfg) { |
| 22 | Blocks.reserve(n: cfg->getNumBlockIDs()); |
| 23 | |
| 24 | // The CFG orders the blocks of loop bodies before those of loop successors |
| 25 | // (both numerically, and in the successor order of the loop condition |
| 26 | // block). So, RPO necessarily reverses that order, placing the loop successor |
| 27 | // *before* the loop body. For many analyses, particularly those that converge |
| 28 | // to a fixpoint, this results in potentially significant extra work because |
| 29 | // loop successors will necessarily need to be reconsidered once the algorithm |
| 30 | // has reached a fixpoint on the loop body. |
| 31 | // |
| 32 | // This definition of CFG graph traits reverses the order of children, so that |
| 33 | // loop bodies will come first in an RPO. |
| 34 | struct CFGLoopBodyFirstTraits { |
| 35 | using NodeRef = const ::clang::CFGBlock *; |
| 36 | using ChildIteratorType = ::clang::CFGBlock::const_succ_reverse_iterator; |
| 37 | |
| 38 | static ChildIteratorType child_begin(NodeRef N) { return N->succ_rbegin(); } |
| 39 | static ChildIteratorType child_end(NodeRef N) { return N->succ_rend(); } |
| 40 | }; |
| 41 | |
| 42 | struct POTraversal |
| 43 | : llvm::PostOrderTraversalBase<POTraversal, CFGLoopBodyFirstTraits> { |
| 44 | CFGBlockSet BSet; |
| 45 | |
| 46 | POTraversal(const CFG *cfg) : BSet(cfg) { this->init(Start: &cfg->getEntry()); } |
| 47 | bool insertEdge(std::optional<const CFGBlock *>, const CFGBlock *To) { |
| 48 | if (!To) |
| 49 | return false; |
| 50 | return BSet.insert(Block: To).second; |
| 51 | } |
| 52 | }; |
| 53 | |
| 54 | for (const CFGBlock *Block : POTraversal(cfg)) { |
| 55 | BlockOrder[Block] = Blocks.size() + 1; |
| 56 | Blocks.push_back(x: Block); |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | std::unique_ptr<PostOrderCFGView> |
| 61 | PostOrderCFGView::create(AnalysisDeclContext &ctx) { |
| 62 | const CFG *cfg = ctx.getCFG(); |
| 63 | if (!cfg) |
| 64 | return nullptr; |
| 65 | return std::make_unique<PostOrderCFGView>(args&: cfg); |
| 66 | } |
| 67 | |
| 68 | const void *PostOrderCFGView::getTag() { static int x; return &x; } |
| 69 | |
| 70 | bool PostOrderCFGView::BlockOrderCompare::operator()(const CFGBlock *b1, |
| 71 | const CFGBlock *b2) const { |
| 72 | PostOrderCFGView::BlockOrderTy::const_iterator b1It = POV.BlockOrder.find(Val: b1); |
| 73 | PostOrderCFGView::BlockOrderTy::const_iterator b2It = POV.BlockOrder.find(Val: b2); |
| 74 | |
| 75 | unsigned b1V = (b1It == POV.BlockOrder.end()) ? 0 : b1It->second; |
| 76 | unsigned b2V = (b2It == POV.BlockOrder.end()) ? 0 : b2It->second; |
| 77 | return b1V > b2V; |
| 78 | } |
| 79 | |