#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #include #include #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Instructions.h" #include "revng/RestructureCFG/BasicBlockNode.h" #include "revng/RestructureCFG/RegionCFGTreeBB.h" #include "revng/RestructureCFG/Utils.h" // Trait exposing the weight of a generic object wrapped by `BasicBlockNode`. template struct WeightTraits {}; // Specialization of the WeightTraits for the the `BasicBlock` class, which // simply returns the number of instruction composing it. template<> struct WeightTraits { static size_t getWeight(llvm::BasicBlock *BB) { // By default they weight of a BB is the number of instructions it contains. size_t Weight = BB->size(); // If the terminator is an unconditional branch we decrease the weight by // one, because unconditional branches are never emitted in C. if (auto *Br = dyn_cast(BB->getTerminator())) { if (Br->isUnconditional()) --Weight; } return Weight; } }; template inline BasicBlockNode::BasicBlockNode(RegionCFGT *Parent, NodeT OriginalNode, RegionCFGT *Collapsed, llvm::StringRef Name, Type T, unsigned Value) : ID(Parent->getNewID()), Parent(Parent), CollapsedRegion(Collapsed), NodeType(T), Name(Name), StateVariableValue(Value), OriginalNode(OriginalNode), Weaved(false) { } // Needed by `DomTreeBuilder`. template inline void BasicBlockNode::printAsOperand(llvm::raw_ostream &O, bool /* PrintType */) const { O << Name; } template inline void BasicBlockNode::removeSuccessor(BasicBlockNodeT *Succ) { size_t Removed = 0; const auto IsSucc = [&Removed, Succ](const node_edgeinfo_pair &P) { if (P.first == Succ) { ++Removed; return true; } return false; }; Successors.erase(std::remove_if(Successors.begin(), Successors.end(), IsSucc), Successors.end()); revng_assert(Removed == 1); // needs to remove exactly one successor } template inline typename BasicBlockNode::node_edgeinfo_pair BasicBlockNode::extractSuccessorEdge(BasicBlockNodeT *Succ) { size_t Removed = 0; node_edgeinfo_pair Extracted; const auto IsSucc = [&Removed, &Extracted, Succ](const node_edgeinfo_pair &P) { if (P.first == Succ) { ++Removed; Extracted = P; return true; } return false; }; Successors.erase(std::remove_if(Successors.begin(), Successors.end(), IsSucc), Successors.end()); revng_assert(Removed == 1); // needs to remove exactly one successor return Extracted; } template inline const typename BasicBlockNode::node_edgeinfo_pair & BasicBlockNode::getSuccessorEdge(const BasicBlockNodeT *Succ) const { const auto IsSucc = [Succ](const node_edgeinfo_pair &P) { return P.first == Succ; }; auto SuccEnd = Successors.end(); auto SuccEdgeIt = std::find_if(Successors.begin(), SuccEnd, IsSucc); revng_assert(SuccEdgeIt != SuccEnd); revng_assert(std::find_if(std::next(SuccEdgeIt), SuccEnd, IsSucc) == SuccEnd); return *SuccEdgeIt; } template inline typename BasicBlockNode::node_edgeinfo_pair & BasicBlockNode::getSuccessorEdge(BasicBlockNodeT *Succ) { const auto IsSucc = [Succ](node_edgeinfo_pair &P) { return P.first == Succ; }; auto SuccEnd = Successors.end(); auto SuccEdgeIt = std::find_if(Successors.begin(), SuccEnd, IsSucc); revng_assert(SuccEdgeIt != SuccEnd); revng_assert(std::find_if(std::next(SuccEdgeIt), SuccEnd, IsSucc) == SuccEnd); return *SuccEdgeIt; } template inline void BasicBlockNode::removePredecessor(BasicBlockNodeT *Pred) { size_t Removed = 0; const auto IsPred = [&Removed, Pred](const node_edgeinfo_pair &P) { if (P.first == Pred) { ++Removed; return true; } return false; }; Predecessors.erase(std::remove_if(Predecessors.begin(), Predecessors.end(), IsPred), Predecessors.end()); revng_assert(Removed == 1); // needs to remove exactly one predecessor } template inline typename BasicBlockNode::node_edgeinfo_pair BasicBlockNode::extractPredecessorEdge(BasicBlockNodeT *Pred) { size_t Removed = 0; node_edgeinfo_pair Extracted; const auto IsPred = [&Removed, &Extracted, Pred](const node_edgeinfo_pair &P) { if (P.first == Pred) { ++Removed; Extracted = P; return true; } return false; }; Predecessors.erase(std::remove_if(Predecessors.begin(), Predecessors.end(), IsPred), Predecessors.end()); revng_assert(Removed == 1); // needs to remove exactly one predecessor return Extracted; } template inline const typename BasicBlockNode::node_edgeinfo_pair & BasicBlockNode::getPredecessorEdge(const BasicBlockNodeT *Pred) const { const auto IsPred = [Pred](const node_edgeinfo_pair &P) { return P.first == Pred; }; auto PredEnd = Predecessors.end(); auto PredEdgeIt = std::find_if(Predecessors.begin(), PredEnd, IsPred); revng_assert(PredEdgeIt != PredEnd); revng_assert(std::find_if(std::next(PredEdgeIt), PredEnd, IsPred) == PredEnd); return *PredEdgeIt; } template inline typename BasicBlockNode::node_edgeinfo_pair & BasicBlockNode::getPredecessorEdge(BasicBlockNodeT *Pred) { const auto IsPred = [Pred](node_edgeinfo_pair &P) { return P.first == Pred; }; auto PredEnd = Predecessors.end(); auto PredEdgeIt = std::find_if(Predecessors.begin(), PredEnd, IsPred); revng_assert(PredEdgeIt != PredEnd); revng_assert(std::find_if(std::next(PredEdgeIt), PredEnd, IsPred) == PredEnd); return *PredEdgeIt; } template using BBNodeMap = typename BasicBlockNode::BBNodeMap; template using links_container = typename BasicBlockNode::links_container; template inline void handleNeighbors(const BBNodeMap &SubMap, links_container &Neighbors) { Neighbors.erase(std::remove_if(Neighbors.begin(), Neighbors.end(), [&SubMap](const auto &LabeledNode) { return !SubMap.contains(LabeledNode.first); }), Neighbors.end()); for (auto &NeighborLabelPair : Neighbors) { auto &Neighbor = NeighborLabelPair.first; revng_assert(SubMap.contains(Neighbor)); Neighbor = SubMap.at(Neighbor); } } template inline void BasicBlockNode::updatePointers(const BBNodeMap &SubMap) { handleNeighbors(SubMap, Predecessors); handleNeighbors(SubMap, Successors); } template inline llvm::StringRef BasicBlockNode::getName() const { return llvm::StringRef(Name); } template inline bool BasicBlockNode::isEquivalentTo(BasicBlockNodeT *Other) const { // Early failure if the IDs of the nodes are different. if (getID() != Other->getID()) { return false; } // Early failure if the number of successors for a node is not equal. size_t SuccessorNumber = successor_size(); size_t OtherSuccessorNumber = Other->successor_size(); if (SuccessorNumber != OtherSuccessorNumber) { return false; } for (size_t I = 0; I < SuccessorNumber; I++) { BasicBlockNode *SuccessorI = getSuccessorI(I); BasicBlockNode *OtherSuccessorI = Other->getSuccessorI(I); if (not SuccessorI->isEquivalentTo(OtherSuccessorI)) { return false; } } return true; } template inline size_t BasicBlockNode::getWeight() const { switch (NodeType) { case Type::Code: { revng_assert(OriginalNode != nullptr); return WeightTraits::getWeight(OriginalNode); } break; case Type::Collapsed: { revng_assert(CollapsedRegion != nullptr); return CollapsedRegion->getUntangleWeight(); } break; case Type::Tile: { revng_abort("getWeight() not implemented for tiles."); } break; case Type::Empty: { // Empty nodes contain nothing, their weight is 0 return 0; } break; case Type::EntryDispatcher: case Type::ExitDispatcher: case Type::Break: case Type::Continue: case Type::EntrySet: case Type::ExitSet: { // These nodes all cost 1, because they contain a single statement. return 1; } break; default: revng_abort("getWeight() still not implemented."); } return 0; }