mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
cb58b8a526
`ExprNode` and its child classes use LLVM-style RTTI. Until now their destruction was not handled properly, causing the constructor-destructor type mismatch warnings on ASAN. Despite this all the code was working properly, but just for luck, because of the fact that these classes are very shallow. This commit fixes the issue, and allow `ExprNode` and its child classes to be extended without worrying about wrong destructors being invoked.
183 lines
5.6 KiB
C++
183 lines
5.6 KiB
C++
/// \file ASTTree.cpp
|
|
/// \brief
|
|
|
|
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
// Standard includes
|
|
#include <cstdlib>
|
|
|
|
// Local libraries includes
|
|
#include "revng-c/RestructureCFGPass/ASTNode.h"
|
|
#include "revng-c/RestructureCFGPass/ASTTree.h"
|
|
#include "revng-c/RestructureCFGPass/Utils.h"
|
|
|
|
using namespace llvm;
|
|
using ASTNodeMap = std::map<ASTNode *, ASTNode *>;
|
|
using ExprNodeMap = std::map<ExprNode *, ExprNode *>;
|
|
|
|
// Helper to obtain a unique incremental counter (to give name to sequence
|
|
// nodes).
|
|
static int Counter = 1;
|
|
static std::string getID() {
|
|
return std::to_string(Counter++);
|
|
}
|
|
|
|
SequenceNode *ASTTree::addSequenceNode() {
|
|
ASTNodeList.emplace_back(new SequenceNode("sequence " + getID()));
|
|
|
|
// Set the Node ID
|
|
ASTNodeList.back()->setID(getNewID());
|
|
|
|
return llvm::cast<SequenceNode>(ASTNodeList.back().get());
|
|
}
|
|
|
|
size_t ASTTree::size() const {
|
|
return ASTNodeList.size();
|
|
}
|
|
|
|
void ASTTree::addASTNode(BasicBlockNode<BasicBlock *> *Node,
|
|
std::unique_ptr<ASTNode> &&ASTObject) {
|
|
ASTNodeList.emplace_back(std::move(ASTObject));
|
|
|
|
ASTNode *ASTNode = ASTNodeList.back().get();
|
|
|
|
// Set the Node ID
|
|
ASTNode->setID(getNewID());
|
|
|
|
NodeASTMap.insert(std::make_pair(Node, ASTNode));
|
|
}
|
|
|
|
SwitchCheckNode *ASTTree::addSwitchCheck(std::unique_ptr<ASTNode> ASTObject) {
|
|
ASTNodeList.emplace_back(std::move(ASTObject));
|
|
|
|
// Set the Node ID
|
|
ASTNodeList.back()->setID(getNewID());
|
|
|
|
return llvm::cast<SwitchCheckNode>(ASTNodeList.back().get());
|
|
}
|
|
|
|
SwitchNode *ASTTree::addSwitch(std::unique_ptr<ASTNode> ASTObject) {
|
|
ASTNodeList.emplace_back(std::move(ASTObject));
|
|
|
|
// Set the Node ID
|
|
ASTNodeList.back()->setID(getNewID());
|
|
|
|
return llvm::cast<SwitchNode>(ASTNodeList.back().get());
|
|
}
|
|
|
|
ASTNode *ASTTree::findASTNode(BasicBlockNode<BasicBlock *> *BlockNode) {
|
|
revng_assert(NodeASTMap.count(BlockNode) != 0);
|
|
ASTNode *ASTPointer = NodeASTMap[BlockNode];
|
|
return ASTPointer;
|
|
}
|
|
|
|
// TODO: This is higly inefficient (it is a linear scan over a std::map).
|
|
// Consider keeping another map for the inverse direction (and updating
|
|
// it).
|
|
BasicBlockNode<BasicBlock *> *ASTTree::findCFGNode(ASTNode *Node) {
|
|
BasicBlockNode<BasicBlock *> *Result = nullptr;
|
|
for (auto &Pair : NodeASTMap)
|
|
if (Pair.second == Node)
|
|
Result = Pair.first;
|
|
// We may return nullptr, since for example continue and break nodes do not
|
|
// have a corresponding CFGNode.
|
|
return Result;
|
|
}
|
|
|
|
void ASTTree::setRoot(ASTNode *Root) {
|
|
RootNode = Root;
|
|
}
|
|
|
|
ASTNode *ASTTree::getRoot() const {
|
|
return RootNode;
|
|
}
|
|
|
|
ASTNode *
|
|
ASTTree::copyASTNodesFrom(ASTTree &OldAST, BBNodeMap &SubstitutionMap) {
|
|
ASTNodeMap ASTSubstitutionMap{};
|
|
ExprNodeMap CondExprMap{};
|
|
|
|
// Clone each ASTNode in the current AST.
|
|
links_container::difference_type NewNodes = 0;
|
|
for (std::unique_ptr<ASTNode> &Old : OldAST.nodes()) {
|
|
ASTNodeList.emplace_back(std::move(Old->Clone()));
|
|
++NewNodes;
|
|
|
|
// Set the Node ID
|
|
ASTNodeList.back()->setID(getNewID());
|
|
|
|
BasicBlockNode<BasicBlock *> *OldCFGNode = OldAST.findCFGNode(Old.get());
|
|
if (OldCFGNode != nullptr) {
|
|
NodeASTMap.insert(std::make_pair(OldCFGNode, ASTNodeList.back().get()));
|
|
}
|
|
ASTNode *New = ASTNodeList.back().get();
|
|
ASTSubstitutionMap[Old.get()] = New;
|
|
}
|
|
|
|
// Clone the conditional expression nodes.
|
|
for (expr_unique_ptr &OldExpr : OldAST.expressions()) {
|
|
CondExprList.emplace_back(new AtomicNode(*cast<AtomicNode>(OldExpr.get())),
|
|
expr_destructor());
|
|
ExprNode *NewExpr = CondExprList.back().get();
|
|
CondExprMap[OldExpr.get()] = NewExpr;
|
|
}
|
|
|
|
// Update the AST and BBNode pointers inside the newly created AST nodes,
|
|
// to reflect the changes made. Update also the pointer to the conditional
|
|
// expressions just cloned.
|
|
links_iterator BeginInserted = ASTNodeList.end() - NewNodes;
|
|
links_iterator EndInserted = ASTNodeList.end();
|
|
using MovedIteratorRange = llvm::iterator_range<links_container::iterator>;
|
|
MovedIteratorRange Result = llvm::make_range(BeginInserted, EndInserted);
|
|
for (std::unique_ptr<ASTNode> &NewNode : Result) {
|
|
NewNode->updateASTNodesPointers(ASTSubstitutionMap);
|
|
if (auto *If = llvm::dyn_cast<IfNode>(NewNode.get())) {
|
|
If->updateCondExprPtr(CondExprMap);
|
|
}
|
|
}
|
|
|
|
// Update the map between `BasicBlockNode` and `ASTNode`.
|
|
for (auto SubIt : SubstitutionMap) {
|
|
BasicBlockNode<BasicBlock *> *OldBB = SubIt.first;
|
|
BasicBlockNode<BasicBlock *> *NewBB = SubIt.second;
|
|
auto MapIt = NodeASTMap.find(OldBB);
|
|
|
|
// HACK:: update the key of the NodeASTMap
|
|
bool isBreakOrContinue = OldBB->isContinue() or OldBB->isBreak();
|
|
if (not isBreakOrContinue) {
|
|
revng_assert(MapIt != NodeASTMap.end());
|
|
std::swap(NodeASTMap[NewBB], MapIt->second);
|
|
NodeASTMap.erase(MapIt);
|
|
}
|
|
}
|
|
|
|
revng_assert(ASTSubstitutionMap.count(OldAST.getRoot()) != 0);
|
|
return ASTSubstitutionMap[OldAST.getRoot()];
|
|
}
|
|
|
|
void ASTTree::dumpOnFile(std::string FolderName,
|
|
std::string FunctionName,
|
|
std::string FileName) {
|
|
|
|
std::ofstream ASTFile;
|
|
std::string PathName = FolderName + "/" + FunctionName;
|
|
mkdir(FolderName.c_str(), 0775);
|
|
mkdir(PathName.c_str(), 0775);
|
|
ASTFile.open(PathName + "/" + FileName + ".dot");
|
|
if (ASTFile.is_open()) {
|
|
ASTFile << "digraph CFGFunction {\n";
|
|
RootNode->dump(ASTFile);
|
|
ASTFile << "}\n";
|
|
ASTFile.close();
|
|
} else {
|
|
revng_abort("Could not open file for dumping AST.");
|
|
}
|
|
}
|
|
|
|
ExprNode *ASTTree::addCondExpr(expr_unique_ptr &&Expr) {
|
|
CondExprList.emplace_back(std::move(Expr));
|
|
return CondExprList.back().get();
|
|
}
|