-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Replace expression_simplification with expression_simplification_rules
- Loading branch information
Showing
7 changed files
with
159 additions
and
392 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
142
decompiler/pipeline/controlflowanalysis/expression_simplification.py
This file was deleted.
Oops, something went wrong.
20 changes: 20 additions & 0 deletions
20
decompiler/pipeline/controlflowanalysis/expression_simplification/rules/rule.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
117 changes: 117 additions & 0 deletions
117
decompiler/pipeline/controlflowanalysis/expression_simplification_rules.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.