mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
969b5e7601
Remove from the `IfEqualNode` the reference to the BBNode corresponding to the original `switch`, since we cannot have the guarantee that this node will remain allocated in the same place (the pointer could be invalidated). Also insert other fixes.
370 lines
10 KiB
C++
370 lines
10 KiB
C++
/// \file ASTNode.cpp
|
|
/// \brief
|
|
|
|
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
// Standard includes
|
|
#include <cstdlib>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
|
|
// Local libraries includes
|
|
#include "revng-c/RestructureCFGPass/ASTNode.h"
|
|
|
|
using namespace llvm;
|
|
|
|
void IfNode::addConditionalNodesFrom(IfNode *Other) {
|
|
for (BasicBlockNode *Node : Other->conditionalNodes()) {
|
|
ConditionalNodes.push_back(Node);
|
|
}
|
|
}
|
|
|
|
bool CodeNode::isEqual(ASTNode *Node) {
|
|
if (auto *OtherCode = dyn_cast<CodeNode>(Node)) {
|
|
if ((getOriginalBB() != nullptr)
|
|
and (getOriginalBB() == OtherCode->getOriginalBB())) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
BasicBlockNode *CodeNode::getFirstCFG() {
|
|
return CFGNode;
|
|
}
|
|
|
|
void CodeNode::updateBBNodePointers(BBNodeMap &SubstitutionMap) {
|
|
if (CFGNode != nullptr) {
|
|
revng_assert(SubstitutionMap.count(CFGNode) != 0);
|
|
CFGNode = SubstitutionMap[CFGNode];
|
|
} else {
|
|
CFGNode = nullptr;
|
|
}
|
|
}
|
|
|
|
void CodeNode::updateASTNodesPointers(ASTNodeMap &SubstitutionMap) {
|
|
// A CodeNode should not contain any reference to other AST nodes, we do not
|
|
// need to apply updates.
|
|
}
|
|
|
|
bool IfNode::isEqual(ASTNode *Node) {
|
|
if (auto *OtherIf = dyn_cast<IfNode>(Node)) {
|
|
if ((getOriginalBB() != nullptr)
|
|
and (getOriginalBB() == OtherIf->getOriginalBB())) {
|
|
|
|
// TODO: this is necessary since we may not have one between `then` or
|
|
// `else` branches, refactor in a more elegant way
|
|
bool ComparisonState = true;
|
|
if (hasThen()) {
|
|
ComparisonState = Then->isEqual(OtherIf->getThen());
|
|
}
|
|
if (hasElse()) {
|
|
ComparisonState = Else->isEqual(OtherIf->getElse());
|
|
}
|
|
return ComparisonState;
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
BasicBlockNode *IfNode::getFirstCFG() {
|
|
return CFGNode;
|
|
}
|
|
|
|
void IfNode::updateBBNodePointers(BBNodeMap &SubstitutionMap) {
|
|
revng_assert(CFGNode != nullptr);
|
|
CFGNode = SubstitutionMap.at(CFGNode);
|
|
for (BasicBlockNode *&Elem : ConditionalNodes) {
|
|
Elem = SubstitutionMap.at(Elem);
|
|
}
|
|
}
|
|
|
|
void IfNode::updateASTNodesPointers(ASTNodeMap &SubstitutionMap) {
|
|
// Update the pointers to the `then` and `else` branches.
|
|
if (hasThen()) {
|
|
revng_assert(SubstitutionMap.count(Then) != 0);
|
|
Then = SubstitutionMap[Then];
|
|
}
|
|
|
|
if (hasElse()) {
|
|
revng_assert(SubstitutionMap.count(Else) != 0);
|
|
Else = SubstitutionMap[Else];
|
|
}
|
|
}
|
|
|
|
bool ScsNode::isEqual(ASTNode *Node) {
|
|
if (auto *OtherScs = dyn_cast<ScsNode>(Node)) {
|
|
if (Body->isEqual(OtherScs->getBody())) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
BasicBlockNode *ScsNode::getFirstCFG() {
|
|
return CFGNode;
|
|
}
|
|
|
|
void ScsNode::updateBBNodePointers(BBNodeMap &SubstitutionMap) {
|
|
// Invalidate the pointer to the CFGNode, since the corresponding node will
|
|
// not exist anymore after the flattening phase.
|
|
CFGNode = nullptr;
|
|
|
|
// revng_assert(SubstitutionMap.count(CFGNode) != 0);
|
|
if (SubstitutionMap.count(CFGNode) > 0) {
|
|
// CFGNode = SubstitutionMap[CFGNode];
|
|
}
|
|
}
|
|
|
|
void ScsNode::updateASTNodesPointers(ASTNodeMap &SubstitutionMap) {
|
|
// The link to the body AST node should be fixed explicitly during the
|
|
// flattening.
|
|
}
|
|
|
|
bool SequenceNode::isEqual(ASTNode *Node) {
|
|
if (auto *OtherSequence = dyn_cast<SequenceNode>(Node)) {
|
|
bool ComparisonState = true;
|
|
int FirstDimension = NodeList.size();
|
|
int SecondDimension = OtherSequence->listSize();
|
|
if (FirstDimension != SecondDimension) {
|
|
ComparisonState = false;
|
|
}
|
|
|
|
// Continue the comparison only if the sequence node size are the same
|
|
if (ComparisonState) {
|
|
revng_assert(FirstDimension == SecondDimension);
|
|
for (int I = 0; I < FirstDimension; I++) {
|
|
ASTNode *FirstNode = getNodeN(I);
|
|
ASTNode *SecondNode = OtherSequence->getNodeN(I);
|
|
|
|
// As soon as two nodes does not match, exit and make the comparison
|
|
// fail
|
|
if (!FirstNode->isEqual(SecondNode)) {
|
|
ComparisonState = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ComparisonState;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
BasicBlockNode *SequenceNode::getFirstCFG() {
|
|
return getNodeN(0)->getCFGNode();
|
|
}
|
|
|
|
void SequenceNode::updateBBNodePointers(BBNodeMap &SubstitutionMap) {
|
|
// This should do nothing, since we should be adjusting the pointers when
|
|
// iterating over the ASTTree.
|
|
}
|
|
|
|
void SequenceNode::updateASTNodesPointers(ASTNodeMap &SubstitutionMap) {
|
|
// Update all the pointers of the sequence node.
|
|
for (auto NodeIt = NodeList.begin(); NodeIt != NodeList.end(); NodeIt++) {
|
|
ASTNode *Node = *NodeIt;
|
|
revng_assert(SubstitutionMap.count(Node) != 0);
|
|
ASTNode *NewNode = SubstitutionMap[Node];
|
|
*NodeIt = NewNode;
|
|
}
|
|
}
|
|
|
|
void BreakNode::dump(std::ofstream &ASTFile) {
|
|
ASTFile << "\"" << this->getName() << "\" [";
|
|
ASTFile << "label=\"break\"";
|
|
ASTFile << ",shape=\"box\",color=\"red\"];\n";
|
|
}
|
|
|
|
void ContinueNode::dump(std::ofstream &ASTFile) {
|
|
ASTFile << "\"" << this->getName() << "\" [";
|
|
ASTFile << "label=\"continue\"";
|
|
ASTFile << ",shape=\"box\",color=\"red\"];\n";
|
|
}
|
|
|
|
void ContinueNode::addComputationIfNode(IfNode *ComputationIfNode) {
|
|
assert(ComputationIf == nullptr);
|
|
ComputationIf = ComputationIfNode;
|
|
}
|
|
|
|
IfNode *ContinueNode::getComputationIfNode() {
|
|
assert(ComputationIf != nullptr);
|
|
return ComputationIf;
|
|
}
|
|
|
|
void CodeNode::dump(std::ofstream &ASTFile) {
|
|
ASTFile << "\"" << this->getName() << "\" [";
|
|
ASTFile << "label=\"" << this->getName();
|
|
ASTFile << "\"";
|
|
ASTFile << ",shape=\"box\",color=\"red\"];\n";
|
|
}
|
|
|
|
void IfNode::dump(std::ofstream &ASTFile) {
|
|
ASTFile << "\"" << this->getName() << "\" [";
|
|
|
|
// For the label of the If node go take all the nodes in the list
|
|
std::string ConditionalNames;
|
|
for (BasicBlockNode *Conditional : this->conditionalNodes()) {
|
|
ConditionalNames += Conditional->getNameStr() + ", ";
|
|
}
|
|
ConditionalNames.pop_back();
|
|
ConditionalNames.pop_back();
|
|
|
|
// ASTFile << "label=\"" << ConditionalNames;
|
|
ASTFile << "label=\"" << this->getName();
|
|
ASTFile << "\"";
|
|
ASTFile << ",shape=\"invhouse\",color=\"blue\"];\n";
|
|
|
|
if (this->getThen() != nullptr) {
|
|
ASTFile << "\"" << this->getName() << "\""
|
|
<< " -> \"" << this->getThen()->getName() << "\""
|
|
<< " [color=green,label=\"then\"];\n";
|
|
this->getThen()->dump(ASTFile);
|
|
}
|
|
|
|
if (this->getElse() != nullptr) {
|
|
ASTFile << "\"" << this->getName() << "\""
|
|
<< " -> \"" << this->getElse()->getName() << "\""
|
|
<< " [color=green,label=\"else\"];\n";
|
|
this->getElse()->dump(ASTFile);
|
|
}
|
|
}
|
|
|
|
void ScsNode::dump(std::ofstream &ASTFile) {
|
|
ASTFile << "\"" << this->getName() << "\" [";
|
|
ASTFile << "label=\"" << this->getName();
|
|
ASTFile << "\"";
|
|
ASTFile << ",shape=\"circle\",color=\"black\"];\n";
|
|
|
|
// After do-while and while match loop nodes could be empty
|
|
//revng_assert(this->getBody() != nullptr);
|
|
if (this->getBody() != nullptr) {
|
|
ASTFile << "\"" << this->getName() << "\""
|
|
<< " -> \"" << this->getBody()->getName() << "\""
|
|
<< " [color=green,label=\"body\"];\n";
|
|
this->getBody()->dump(ASTFile);
|
|
}
|
|
}
|
|
|
|
void SequenceNode::dump(std::ofstream &ASTFile) {
|
|
ASTFile << "\"" << this->getName() << "\" [";
|
|
ASTFile << "label=\"" << this->getName();
|
|
ASTFile << "\"";
|
|
ASTFile << ",shape=\"box\",color=\"black\"];\n";
|
|
|
|
int SuccessorIndex = 0;
|
|
for (ASTNode *Successor : this->nodes()) {
|
|
ASTFile << "\"" << this->getName() << "\""
|
|
<< " -> \"" << Successor->getName() << "\""
|
|
<< " [color=green,label=\"elem " << SuccessorIndex << "\"];\n";
|
|
Successor->dump(ASTFile);
|
|
SuccessorIndex += 1;
|
|
}
|
|
}
|
|
|
|
void SwitchNode::dump(std::ofstream &ASTFile) {
|
|
ASTFile << "\"" << this->getName() << "\" [";
|
|
ASTFile << "label=\"" << this->getName();
|
|
ASTFile << "\"";
|
|
ASTFile << ",shape=\"hexagon\",color=\"black\"];\n";
|
|
|
|
int CaseIndex = 0;
|
|
for (auto Case : this->cases()) {
|
|
ASTFile << "\"" << this->getName() << "\""
|
|
<< " -> \"" << Case.second->getName() << "\""
|
|
<< " [color=green,label=\"case " << Case.first << "\"];\n";
|
|
Case.second->dump(ASTFile);
|
|
CaseIndex += 1;
|
|
}
|
|
}
|
|
|
|
bool SwitchNode::isEqual(ASTNode *Node) {
|
|
if (auto *OtherSwitch = dyn_cast<SwitchNode>(Node)) {
|
|
bool ComparisonState = true;
|
|
int FirstDimension = CaseList.size();
|
|
int SecondDimension = OtherSwitch->CaseSize();
|
|
if (FirstDimension != SecondDimension) {
|
|
ComparisonState = false;
|
|
}
|
|
|
|
// Continue the comparison only if the sequence node size are the same
|
|
if (ComparisonState) {
|
|
revng_assert(FirstDimension == SecondDimension);
|
|
for (int I = 0; I < FirstDimension; I++) {
|
|
ASTNode *FirstNode = getCaseN(I);
|
|
ASTNode *SecondNode = OtherSwitch->getCaseN(I);
|
|
|
|
// As soon as two nodes does not match, exit and make the comparison
|
|
// fail
|
|
if (!FirstNode->isEqual(SecondNode)) {
|
|
ComparisonState = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ComparisonState;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
BasicBlockNode *SwitchNode::getFirstCFG() {
|
|
return CFGNode;
|
|
}
|
|
|
|
void SwitchNode::updateBBNodePointers(BBNodeMap &SubstitutionMap) {
|
|
revng_assert(CFGNode != nullptr);
|
|
CFGNode = SubstitutionMap.at(CFGNode);
|
|
}
|
|
|
|
void SwitchNode::updateASTNodesPointers(ASTNodeMap &SubstitutionMap) {
|
|
// Update all the case pointers.
|
|
for (auto &Case : CaseList) {
|
|
Case.second = SubstitutionMap.at(Case.second);
|
|
}
|
|
}
|
|
|
|
void IfEqualNode::dump(std::ofstream &ASTFile) {
|
|
ASTFile << "\"" << this->getName() << "\" [";
|
|
|
|
// For the label of the If node go take all the nodes in the list
|
|
std::string ConditionalNames;
|
|
for (BasicBlockNode *Conditional : this->conditionalNodes()) {
|
|
ConditionalNames += Conditional->getNameStr() + ", ";
|
|
}
|
|
ConditionalNames.pop_back();
|
|
ConditionalNames.pop_back();
|
|
|
|
// ASTFile << "label=\"" << ConditionalNames;
|
|
ASTFile << "label=\"" << this->getName();
|
|
ASTFile << "\"";
|
|
ASTFile << ",shape=\"invtrapezium\",color=\"blue\"];\n";
|
|
|
|
if (this->getThen() != nullptr) {
|
|
ASTFile << "\"" << this->getName() << "\""
|
|
<< " -> \"" << this->getThen()->getName() << "\""
|
|
<< " [color=green,label=\"then\"];\n";
|
|
this->getThen()->dump(ASTFile);
|
|
}
|
|
|
|
if (this->getElse() != nullptr) {
|
|
ASTFile << "\"" << this->getName() << "\""
|
|
<< " -> \"" << this->getElse()->getName() << "\""
|
|
<< " [color=green,label=\"else\"];\n";
|
|
this->getElse()->dump(ASTFile);
|
|
}
|
|
}
|