Skip to content

Commit

Permalink
Replace expression_simplification with expression_simplification_rules
Browse files Browse the repository at this point in the history
  • Loading branch information
rihi committed Aug 24, 2023
1 parent 6414d67 commit a3e060e
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 392 deletions.
2 changes: 1 addition & 1 deletion decompiler/pipeline/controlflowanalysis/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .expression_simplification import ExpressionSimplification
from .expression_simplification_rules import ExpressionSimplificationRulesAst, ExpressionSimplificationRulesCfg
from .instruction_length_handler import InstructionLengthHandler
from .readability_based_refinement import ReadabilityBasedRefinement
from .variable_name_generation import VariableNameGeneration
142 changes: 0 additions & 142 deletions decompiler/pipeline/controlflowanalysis/expression_simplification.py

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from abc import ABC, abstractmethod

from decompiler.structures.pseudo import Expression, Operation


class SimplificationRule(ABC):
"""
This class defines the interface for simplification rules that can be applied to expressions.
"""

@abstractmethod
def apply(self, operation: Operation) -> list[tuple[Expression, Expression]]:
"""
Apply the simplification rule to the given operation.
:param operation: The operation to which the simplification rule should be applied.
:return: A list of tuples, each containing a pair of expressions representing the original
and simplified versions resulting from applying the simplification rule to the given operation.
"""
pass
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import logging
from abc import ABC, abstractmethod

from decompiler.backend.cexpressiongenerator import CExpressionGenerator
from decompiler.pipeline.controlflowanalysis.expression_simplification.rules.rule import SimplificationRule
from decompiler.pipeline.stage import PipelineStage
from decompiler.structures.ast.ast_nodes import CodeNode
from decompiler.structures.pseudo import Instruction, Operation
from decompiler.structures.visitors.substitute_visitor import SubstituteVisitor
from decompiler.task import DecompilerTask


class _ExpressionSimplificationRulesBase(PipelineStage, ABC):

def run(self, task: DecompilerTask):
max_iterations = task.options.getint("expression-simplification.max_iterations")
simplify_instructions(self._get_instructions(task), max_iterations)

@abstractmethod
def _get_instructions(self, task: DecompilerTask) -> list[Instruction]:
pass


class ExpressionSimplificationRulesCfg(_ExpressionSimplificationRulesBase):
"""
Pipeline stage that simplifies cfg expressions by applying a set of simplification rules.
"""

name = "expression-simplification-rules-cfg"

def _get_instructions(self, task: DecompilerTask) -> list[Instruction]:
return list(task.graph.instructions)


class ExpressionSimplificationRulesAst(_ExpressionSimplificationRulesBase):
"""
Pipeline stage that simplifies ast expressions by applying a set of simplification rules.
"""

name = "expression-simplification-rules-ast"

def _get_instructions(self, task: DecompilerTask) -> list[Instruction]:
instructions = []
for node in task.syntax_tree.topological_order():
if isinstance(node, CodeNode):
instructions.extend(node.instructions)

return instructions


_pre_rules: list[SimplificationRule] = []
_rules: list[SimplificationRule] = []
_post_rules: list[SimplificationRule] = []


def simplify_instructions(instructions: list[Instruction], max_iterations: int):
rule_sets = [
("pre-rules", _pre_rules),
("rules", _rules),
("post-rules", _post_rules)
]
for rule_name, rule_set in rule_sets:
iteration_count = _simplify_instructions_with_rule_set(instructions, rule_set, max_iterations)
if iteration_count <= max_iterations:
logging.info(f"Expression simplification took {iteration_count} iterations for {rule_name}")
else:
logging.warning(f"Exceeded max iteration count for {rule_name}")


def _simplify_instructions_with_rule_set(
instructions: list[Instruction],
rule_set: list[SimplificationRule],
max_iterations: int
) -> int:
iteration_count = 0

changes = True
while changes:
changes = False

for rule in rule_set:
for instruction in instructions:
for expression in instruction.subexpressions():
while True:
if expression is None:
break
if not isinstance(expression, Operation):
break

substitutions = rule.apply(expression)
if not substitutions:
break

changes = True
iteration_count += 1

if iteration_count > max_iterations:
logging.warning("Took to many iterations for rule set to finish")
return iteration_count

for i, (replacee, replacement) in enumerate(substitutions):
expression_gen = CExpressionGenerator()
logging.debug(
f"[{rule.__class__.__name__}] {i}. Substituting: '{replacee.accept(expression_gen)}'"
f" with '{replacement.accept(expression_gen)}' in '{expression.accept(expression_gen)}'"
)
instruction.accept(SubstituteVisitor.identity(replacee, replacement))

# This is modifying the expression tree, while we are iterating over it.
# This works because we are iterating depth first and only
# modifying already visited nodes.

# if expression got replaced, we need to update the reference
if replacee == expression:
expression = replacement

return iteration_count
12 changes: 9 additions & 3 deletions decompiler/pipeline/default.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"""Module defining the available pipelines."""

from decompiler.pipeline.controlflowanalysis import (
ExpressionSimplification,
ExpressionSimplificationRulesAst,
ExpressionSimplificationRulesCfg,
InstructionLengthHandler,
ReadabilityBasedRefinement,
VariableNameGeneration,
Expand Down Expand Up @@ -35,10 +36,15 @@
IdentityElimination,
CommonSubexpressionElimination,
ArrayAccessDetection,
ExpressionSimplification,
ExpressionSimplificationRulesCfg,
DeadComponentPruner,
GraphExpressionFolding,
EdgePruner,
]

AST_STAGES = [ReadabilityBasedRefinement, ExpressionSimplification, InstructionLengthHandler, VariableNameGeneration]
AST_STAGES = [
ReadabilityBasedRefinement,
ExpressionSimplificationRulesAst,
InstructionLengthHandler,
VariableNameGeneration
]
14 changes: 12 additions & 2 deletions decompiler/util/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,16 @@
"is_hidden_from_gui": true,
"is_hidden_from_cli": false,
"argument_name": "--loop_break_in_cases"
},
{
"dest": "expression-simplification.max_iterations",
"default": 10000,
"type": "number",
"title": "The maximum number of iterations the expression simplification is allowed to take",
"description": "Stop simplifying after this number of iterations is exceeded, even if more possible simplifications are possible",
"is_hidden_from_gui": false,
"is_hidden_from_cli": false,
"argument_name": "--max_expression_simplification_iterations"
}
]
},
Expand All @@ -598,7 +608,7 @@
"dead-code-elimination",
"expression-propagation-memory",
"expression-propagation-function-call",
"expression-simplification",
"expression-simplification-rules-cfg",
"dead-code-elimination",
"redundant-casts-elimination",
"identity-elimination",
Expand All @@ -618,7 +628,7 @@
"dest": "pipeline.ast_stages",
"default": [
"readability-based-refinement",
"expression-simplification",
"expression-simplification-rules-ast",
"instruction-length-handler",
"variable-name-generation"
],
Expand Down
Loading

0 comments on commit a3e060e

Please sign in to comment.