mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
733f5008b3
We introduce a simplification step, which looks for `switch`es that can be reduced to simpler `if` statements. Specifically, the logic is the following: 1) When we identify a `switch` statement composed by a single `case` and a possible default, we transform it into an `if` with the `case` now corresponding to the `then`, and the `default` corresponding to the `else`, if present. 2) When we identify a `switch` statement composed by two `case`s, and no `default` is present, we can promote it to an `if` with `then` `else` branches. Other key details: - The promotion happens only if we can identify at least one of the `case`s that have a single element in the `case` label. If this is not the case, we do not promote one to RHS of the `if` condition. - A new `CompareNode` class, inheriting from `ExprNode`, is created, in order to represent the equality or inequality condition of an `IfNode` instance that is the result of the promotion. This `CompareNode` can represent for the LHS both an `llvm::Value` or the `loop_state_var`, while it embeds the RHS constant which completes the comparison. - We remove `SwitchBreak` AST nodes that may now appear as children of an `if` node promoted from a `switch`. - We introduce in the `CompareNode` the `weaved` concept. Indeed, if a promotion of a weaved `switch` happens, we should avoid the serialization of the instructions leading to the computation of the condition of the original `switch`, because they have been already emitted by the main related dominating `switch`. We also introduce an additional simplification step, which takes care of: - Promoting `!(==)` to `(!=)` and `!(!=)` to `(==)`, if the inner equal/not equal is represented via a `CompareNode`. - Promoting `x == 0` to `!x` and `x != 0` to `x`. To be able to correctly emit (or not) the instructions computing a condition of an `IfNode`, we need to add the `EmittBB` flag, an additional parameter to the `buildGHASTCondition` function, which controls the emission of the statements of a basic block computing a condition. Consequently, the `IfNode` acquires a `IsWeaved` field, which is used to mirror the property having the same name on `SwitchNode`. Being now possible a promotion from a dual `SwitchNode` to an `IfNode`, we need to represent this property on the `IfNode` too.
131 lines
3.8 KiB
C++
131 lines
3.8 KiB
C++
#pragma once
|
|
|
|
//
|
|
// Copyright rev.ng Labs Srl. See LICENSE.md for details.
|
|
//
|
|
|
|
#include <cstdlib>
|
|
#include <type_traits>
|
|
|
|
#include "revng-c/RestructureCFG/ASTNode.h"
|
|
|
|
// Forward declarations.
|
|
class ASTNode;
|
|
|
|
template<class NodeT>
|
|
class BasicBlockNode;
|
|
|
|
class SequenceNode;
|
|
|
|
class ASTTree {
|
|
|
|
public:
|
|
using ast_deleter_t = decltype(&ASTNode::deleteASTNode);
|
|
using ast_destructor = std::integral_constant<ast_deleter_t,
|
|
&ASTNode::deleteASTNode>;
|
|
using ast_unique_ptr = std::unique_ptr<ASTNode, ast_destructor>;
|
|
using getPointerT = ASTNode *(*) (ast_unique_ptr &);
|
|
|
|
static ASTNode *getPointer(ast_unique_ptr &Original) {
|
|
return Original.get();
|
|
}
|
|
|
|
static_assert(std::is_same_v<decltype(&getPointer), getPointerT>);
|
|
|
|
using links_container = std::vector<ast_unique_ptr>;
|
|
using internal_iterator = typename links_container::iterator;
|
|
using links_iterator = llvm::mapped_iterator<internal_iterator, getPointerT>;
|
|
using links_range = llvm::iterator_range<links_iterator>;
|
|
|
|
using expr_deleter_t = decltype(&ExprNode::deleteExprNode);
|
|
using expr_destructor = std::integral_constant<expr_deleter_t,
|
|
&ExprNode::deleteExprNode>;
|
|
using expr_unique_ptr = std::unique_ptr<ExprNode, expr_destructor>;
|
|
|
|
using links_container_expr = std::vector<expr_unique_ptr>;
|
|
using links_iterator_expr = typename links_container_expr::iterator;
|
|
using links_range_expr = llvm::iterator_range<links_iterator_expr>;
|
|
|
|
using ASTNodeMap = ASTNode::ASTNodeMap;
|
|
using BasicBlockNodeBB = ASTNode::BasicBlockNodeBB;
|
|
using BBNodeMap = ASTNode::BBNodeMap;
|
|
|
|
links_iterator begin() {
|
|
return llvm::map_iterator(ASTNodeList.begin(), getPointer);
|
|
}
|
|
links_iterator end() {
|
|
return llvm::map_iterator(ASTNodeList.end(), getPointer);
|
|
}
|
|
|
|
links_iterator_expr beginExpr() { return CondExprList.begin(); }
|
|
links_iterator_expr endExpr() { return CondExprList.end(); }
|
|
|
|
private:
|
|
links_container ASTNodeList = {};
|
|
std::map<BasicBlockNodeBB *, ASTNode *> BBASTMap = {};
|
|
std::map<ASTNode *, BasicBlockNodeBB *> ASTBBMap = {};
|
|
ASTNode *RootNode = nullptr;
|
|
unsigned IDCounter = 0;
|
|
links_container_expr CondExprList = {};
|
|
|
|
public:
|
|
ASTTree() = default;
|
|
|
|
// Default movable
|
|
ASTTree(ASTTree &&) = default;
|
|
ASTTree &operator=(ASTTree &&) = default;
|
|
|
|
// Non copyable
|
|
ASTTree(const ASTTree &) = delete;
|
|
ASTTree &operator=(const ASTTree &) = delete;
|
|
|
|
private:
|
|
ASTNode *addASTNodeImpl(ast_unique_ptr &&ASTObject);
|
|
|
|
public:
|
|
SequenceNode *addSequenceNode();
|
|
|
|
SwitchBreakNode *addSwitchBreak(SwitchNode *SN);
|
|
|
|
unsigned getNewID() { return IDCounter++; }
|
|
|
|
links_range nodes() { return llvm::make_range(begin(), end()); }
|
|
|
|
links_range_expr expressions() {
|
|
return llvm::make_range(beginExpr(), endExpr());
|
|
}
|
|
|
|
links_container::size_type size() const;
|
|
|
|
void addASTNode(BasicBlockNodeBB *Node, ast_unique_ptr &&ASTObject);
|
|
|
|
ASTNode *addASTNode(ast_unique_ptr &&ASTObject);
|
|
|
|
void removeASTNode(ASTNode *Node);
|
|
|
|
ASTNode *findASTNode(BasicBlockNodeBB *BlockNode);
|
|
|
|
BasicBlockNodeBB *findCFGNode(ASTNode *Node);
|
|
|
|
void setRoot(ASTNode *Root);
|
|
|
|
ASTNode *getRoot() const;
|
|
|
|
ASTNode *copyASTNodesFrom(ASTTree &OldAST);
|
|
|
|
/// Dump a GraphViz file on a file using an absolute path
|
|
debug_function void dumpASTOnFile(const std::string &FileName) const;
|
|
|
|
/// Dump a GraphViz file on a file using an absolute path
|
|
debug_function void dumpASTOnFile(const char *FName) const {
|
|
return dumpASTOnFile(std::string(FName));
|
|
}
|
|
|
|
/// Dump a GraphViz file on a file representing this function
|
|
debug_function void dumpASTOnFile(const std::string &FolderName,
|
|
const std::string &FunctionName,
|
|
const std::string &FileName) const;
|
|
|
|
ExprNode *addCondExpr(expr_unique_ptr &&Expr);
|
|
};
|