about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--example/disasm/full.py37
-rw-r--r--example/expression/asm_to_ir.py6
-rw-r--r--example/expression/constant_propagation.py5
-rw-r--r--example/expression/graph_dataflow.py6
-rw-r--r--miasm/analysis/data_flow.py314
-rw-r--r--miasm/analysis/outofssa.py4
-rw-r--r--miasm/analysis/simplifier.py55
-rw-r--r--miasm/analysis/ssa.py24
-rw-r--r--miasm/arch/ppc/regs.py11
-rw-r--r--miasm/arch/ppc/sem.py35
-rw-r--r--miasm/ir/analysis.py6
-rw-r--r--miasm/jitter/arch/JitCore_ppc32_regs.h34
-rw-r--r--test/analysis/data_flow.py5
13 files changed, 368 insertions, 174 deletions
diff --git a/example/disasm/full.py b/example/disasm/full.py
index a28d548e..d4fae867 100644
--- a/example/disasm/full.py
+++ b/example/disasm/full.py
@@ -9,7 +9,7 @@ from miasm.analysis.binary import Container
 from miasm.core.asmblock import log_asmblock, AsmCFG
 from miasm.core.interval import interval
 from miasm.analysis.machine import Machine
-from miasm.analysis.data_flow import dead_simp, \
+from miasm.analysis.data_flow import \
     DiGraphDefUse, ReachingDefinitions, \
     replace_stack_vars, load_from_int, del_unused_edges
 from miasm.expression.simplifications import expr_simp
@@ -213,7 +213,6 @@ if args.propagexpr:
 
 
 class IRADelModCallStack(ira):
-
         def call_effects(self, addr, instr):
             assignblks, extra = super(IRADelModCallStack, self).call_effects(addr, instr)
             if not args.calldontmodstack:
@@ -283,34 +282,6 @@ if args.gen_ir:
 
 
 if args.propagexpr:
-    class IRAOutRegs(ira):
-        def get_out_regs(self, block):
-            regs_todo = super(self.__class__, self).get_out_regs(block)
-            out = {}
-            for assignblk in block:
-                for dst in assignblk:
-                    reg = self.ssa_var.get(dst, None)
-                    if reg is None:
-                        continue
-                    if reg in regs_todo:
-                        out[reg] = dst
-            return set(viewvalues(out))
-
-    # Add dummy dependency to uncover out regs assignment
-    for loc in ircfg_a.leaves():
-        irblock = ircfg_a.blocks.get(loc)
-        if irblock is None:
-            continue
-        regs = {}
-        for reg in ir_arch_a.get_out_regs(irblock):
-            regs[reg] = reg
-        assignblks = list(irblock)
-        new_assiblk = AssignBlock(regs, assignblks[-1].instr)
-        assignblks.append(new_assiblk)
-        new_irblock = IRBlock(irblock.loc_key, assignblks)
-        ircfg_a.blocks[loc] = new_irblock
-
-
 
     def is_addr_ro_variable(bs, addr, size):
         """
@@ -327,9 +298,6 @@ if args.propagexpr:
             return False
         return True
 
-    ir_arch_a = IRAOutRegs(mdis.loc_db)
-
-
     class CustomIRCFGSimplifierSSA(IRCFGSimplifierSSA):
         def do_simplify(self, ssa, head):
             modified = super(CustomIRCFGSimplifierSSA, self).do_simplify(ssa, head)
@@ -345,14 +313,13 @@ if args.propagexpr:
                 replace_stack_vars(self.ir_arch, ircfg)
 
             ircfg_simplifier = IRCFGSimplifierCommon(self.ir_arch)
+            ircfg_simplifier.deadremoval.add_expr_to_original_expr(ssa.ssa_variable_to_expr)
             ircfg_simplifier.simplify(ircfg, head)
             return ircfg
 
 
 
-
     head = list(entry_points)[0]
-    ir_arch_a = IRAOutRegs(mdis.loc_db)
     simplifier = CustomIRCFGSimplifierSSA(ir_arch_a)
     ircfg = simplifier.simplify(ircfg_a, head)
     open('final.dot', 'w').write(ircfg.dot())
diff --git a/example/expression/asm_to_ir.py b/example/expression/asm_to_ir.py
index 4bcbb05d..83eac728 100644
--- a/example/expression/asm_to_ir.py
+++ b/example/expression/asm_to_ir.py
@@ -8,7 +8,7 @@ from miasm.core import parse_asm
 from miasm.expression.expression import *
 from miasm.core import asmblock
 from miasm.arch.x86.ira import ir_a_x86_32
-from miasm.analysis.data_flow import dead_simp
+from miasm.analysis.data_flow import DeadRemoval
 
 
 # First, asm code
@@ -40,6 +40,8 @@ patches = asmblock.asm_resolve_final(mn_x86, asmcfg, loc_db)
 # Translate to IR
 ir_arch = ir_a_x86_32(loc_db)
 ircfg = ir_arch.new_ircfg_from_asmcfg(asmcfg)
+deadrm = DeadRemoval(ir_arch)
+
 
 # Display IR
 for lbl, irblock in viewitems(ircfg.blocks):
@@ -48,7 +50,7 @@ for lbl, irblock in viewitems(ircfg.blocks):
 # Dead propagation
 open('graph.dot', 'w').write(ircfg.dot())
 print('*' * 80)
-dead_simp(ir_arch, ircfg)
+deadrm(ircfg)
 open('graph2.dot', 'w').write(ircfg.dot())
 
 # Display new IR
diff --git a/example/expression/constant_propagation.py b/example/expression/constant_propagation.py
index a6efbb46..36a548c5 100644
--- a/example/expression/constant_propagation.py
+++ b/example/expression/constant_propagation.py
@@ -9,7 +9,7 @@ from argparse import ArgumentParser
 from miasm.analysis.machine import Machine
 from miasm.analysis.binary import Container
 from miasm.analysis.cst_propag import propagate_cst_expr
-from miasm.analysis.data_flow import dead_simp, \
+from miasm.analysis.data_flow import DeadRemoval, \
     merge_blocks, remove_empty_assignblks
 from miasm.expression.simplifications import expr_simp
 
@@ -29,6 +29,7 @@ cont = Container.from_stream(open(args.filename, 'rb'))
 mdis = machine.dis_engine(cont.bin_stream, loc_db=cont.loc_db)
 ir_arch = machine.ira(mdis.loc_db)
 addr = int(args.address, 0)
+deadrm = DeadRemoval(ir_arch)
 
 asmcfg = mdis.dis_multiblock(addr)
 ircfg = ir_arch.new_ircfg_from_asmcfg(asmcfg)
@@ -42,7 +43,7 @@ if args.simplify:
     modified = True
     while modified:
         modified = False
-        modified |= dead_simp(ir_arch, ircfg)
+        modified |= deadrm(ircfg)
         modified |= remove_empty_assignblks(ircfg)
         modified |= merge_blocks(ircfg, entry_points)
 
diff --git a/example/expression/graph_dataflow.py b/example/expression/graph_dataflow.py
index c320fba0..e7386e9e 100644
--- a/example/expression/graph_dataflow.py
+++ b/example/expression/graph_dataflow.py
@@ -9,7 +9,7 @@ from miasm.expression.expression import get_expr_mem
 from miasm.analysis.data_analysis import intra_block_flow_raw, inter_block_flow
 from miasm.core.graph import DiGraph
 from miasm.ir.symbexec import SymbolicExecutionEngine
-from miasm.analysis.data_flow import dead_simp
+from miasm.analysis.data_flow import DeadRemoval
 
 
 parser = ArgumentParser("Simple expression use for generating dataflow graph")
@@ -88,7 +88,7 @@ def gen_block_data_flow_graph(ir_arch, ircfg, ad, block_flow_cb):
     for irblock in viewvalues(ircfg.blocks):
         print(irblock)
 
-    dead_simp(ir_arch, ircfg)
+    deadrm(ircfg)
 
 
     irblock_0 = None
@@ -140,6 +140,8 @@ print('ok')
 print('generating dataflow graph for:')
 ir_arch_analysis = machine.ira(mdis.loc_db)
 ircfg = ir_arch_analysis.new_ircfg_from_asmcfg(asmcfg)
+deadrm = DeadRemoval(ir_arch_analysis)
+
 
 for irblock in viewvalues(ircfg.blocks):
     print(irblock)
diff --git a/miasm/analysis/data_flow.py b/miasm/analysis/data_flow.py
index be0e4528..7bd6d72f 100644
--- a/miasm/analysis/data_flow.py
+++ b/miasm/analysis/data_flow.py
@@ -69,6 +69,8 @@ class ReachingDefinitions(dict):
         """
         predecessor_state = {}
         for pred_lbl in self.ircfg.predecessors(block.loc_key):
+            if pred_lbl not in self.ircfg.blocks:
+                continue
             pred = self.ircfg.blocks[pred_lbl]
             for lval, definitions in viewitems(self.get_definitions(pred_lbl, len(pred))):
                 predecessor_state.setdefault(lval, set()).update(definitions)
@@ -201,81 +203,191 @@ class DiGraphDefUse(DiGraph):
         yield self.DotCellDescription(text="", attr={})
 
 
-def dead_simp_useful_assignblks(irarch, defuse, reaching_defs):
-    """Mark useful statements using previous reach analysis and defuse
+class DeadRemoval(object):
+    """
+    Do dead removal
+    """
 
-    Source : Kennedy, K. (1979). A survey of data flow analysis techniques.
-    IBM Thomas J. Watson Research Division,  Algorithm MK
+    def __init__(self, ir_arch, expr_to_original_expr=None):
+        self.ir_arch = ir_arch
+        if expr_to_original_expr is None:
+            expr_to_original_expr = {}
+        self.expr_to_original_expr = expr_to_original_expr
 
-    Return a set of triplets (block, assignblk number, lvalue) of
-    useful definitions
-    PRE: compute_reach(self)
 
-    """
-    ircfg = reaching_defs.ircfg
-    useful = set()
-
-    for block_lbl, block in viewitems(ircfg.blocks):
-        successors = ircfg.successors(block_lbl)
-        for successor in successors:
-            if successor not in ircfg.blocks:
-                keep_all_definitions = True
-                break
-        else:
-            keep_all_definitions = False
-
-        # Block has a nonexistent successor or is a leaf
-        if keep_all_definitions or (len(successors) == 0):
-            valid_definitions = reaching_defs.get_definitions(block_lbl,
-                                                              len(block))
-            for lval, definitions in viewitems(valid_definitions):
-                if lval in irarch.get_out_regs(block) or keep_all_definitions:
-                    for definition in definitions:
-                        useful.add(AssignblkNode(definition[0], definition[1], lval))
-
-        # Force keeping of specific cases
+    def add_expr_to_original_expr(self, expr_to_original_expr):
+        self.expr_to_original_expr.update(expr_to_original_expr)
+
+    def is_unkillable_destination(self, lval, rval):
+        if (
+                lval.is_mem() or
+                self.ir_arch.IRDst == lval or
+                lval.is_id("exception_flags") or
+                rval.is_function_call()
+        ):
+            return True
+        return False
+
+    def get_block_useful_destinations(self, block):
+        """
+        Force keeping of specific cases
+        block: IRBlock instance
+        """
+        useful = set()
         for index, assignblk in enumerate(block):
             for lval, rval in viewitems(assignblk):
-                if (lval.is_mem() or
-                    irarch.IRDst == lval or
-                    lval.is_id("exception_flags") or
-                    rval.is_function_call()):
-                    useful.add(AssignblkNode(block_lbl, index, lval))
+                if self.is_unkillable_destination(lval, rval):
+                    useful.add(AssignblkNode(block.loc_key, index, lval))
+        return useful
 
-    # Useful nodes dependencies
-    for node in useful:
-        for parent in defuse.reachable_parents(node):
-            yield parent
+    def is_tracked_var(self, lval, variable):
+        new_lval = self.expr_to_original_expr.get(lval, lval)
+        return new_lval == variable
 
+    def find_definitions_from_worklist(self, worklist, ircfg):
+        """
+        Find variables definition in @worklist by browsing the @ircfg
+        """
+        locs_done = set()
 
-def dead_simp(irarch, ircfg):
-    """
-    Remove useless assignments.
+        defs = set()
 
-    This function is used to analyse relation of a * complete function *
-    This means the blocks under study represent a solid full function graph.
+        while worklist:
+            found = False
+            elt = worklist.pop()
+            if elt in locs_done:
+                continue
+            locs_done.add(elt)
+            variable, loc_key = elt
+            block = ircfg.get_block(loc_key)
 
-    Source : Kennedy, K. (1979). A survey of data flow analysis techniques.
-    IBM Thomas J. Watson Research Division, page 43
+            if block is None:
+                # Consider no sources in incomplete graph
+                continue
 
-    @ircfg: IntermediateRepresentation instance
-    """
+            for index, assignblk in reversed(list(enumerate(block))):
+                for dst, src in viewitems(assignblk):
+                    if self.is_tracked_var(dst, variable):
+                        defs.add(AssignblkNode(loc_key, index, dst))
+                        found = True
+                        break
+                if found:
+                    break
 
-    modified = False
-    reaching_defs = ReachingDefinitions(ircfg)
-    defuse = DiGraphDefUse(reaching_defs, deref_mem=True)
-    useful = set(dead_simp_useful_assignblks(irarch, defuse, reaching_defs))
-    for block in list(viewvalues(ircfg.blocks)):
-        irs = []
-        for idx, assignblk in enumerate(block):
-            new_assignblk = dict(assignblk)
-            for lval in assignblk:
-                if AssignblkNode(block.loc_key, idx, lval) not in useful:
-                    del new_assignblk[lval]
-                    modified = True
-            irs.append(AssignBlock(new_assignblk, assignblk.instr))
-        ircfg.blocks[block.loc_key] = IRBlock(block.loc_key, irs)
-    return modified
+            if not found:
+                for predecessor in ircfg.predecessors(loc_key):
+                    worklist.add((variable, predecessor))
+
+        return defs
+
+    def find_out_regs_definitions_from_block(self, block, ircfg):
+        """
+        Find definitions of out regs starting from @block
+        """
+        worklist = set()
+        for reg in self.ir_arch.get_out_regs(block):
+            worklist.add((reg, block.loc_key))
+        ret = self.find_definitions_from_worklist(worklist, ircfg)
+        return ret
+
+
+    def add_def_for_incomplete_leaf(self, block, ircfg, reaching_defs):
+        """
+        Add valid definitions at end of @block plus out regs
+        """
+        valid_definitions = reaching_defs.get_definitions(
+            block.loc_key,
+            len(block)
+        )
+        worklist = set()
+        for lval, definitions in viewitems(valid_definitions):
+            for definition in definitions:
+                new_lval = self.expr_to_original_expr.get(lval, lval)
+                worklist.add((new_lval, block.loc_key))
+        ret = self.find_definitions_from_worklist(worklist, ircfg)
+        useful = ret
+        useful.update(self.find_out_regs_definitions_from_block(block, ircfg))
+        return useful
+
+    def get_useful_assignments(self, ircfg, defuse, reaching_defs):
+        """
+        Mark useful statements using previous reach analysis and defuse
+
+        Return a set of triplets (block, assignblk number, lvalue) of
+        useful definitions
+        PRE: compute_reach(self)
+
+        """
+
+        useful = set()
+
+        for block_lbl, block in viewitems(ircfg.blocks):
+            block = ircfg.get_block(block_lbl)
+            if block is None:
+                # skip unknown blocks: won't generate dependencies
+                continue
+
+            block_useful = self.get_block_useful_destinations(block)
+            useful.update(block_useful)
+
+
+            successors = ircfg.successors(block_lbl)
+            for successor in successors:
+                if successor not in ircfg.blocks:
+                    keep_all_definitions = True
+                    break
+            else:
+                keep_all_definitions = False
+
+            if keep_all_definitions:
+                useful.update(self.add_def_for_incomplete_leaf(block, ircfg, reaching_defs))
+                continue
+
+            if len(successors) == 0:
+                useful.update(self.find_out_regs_definitions_from_block(block, ircfg))
+            else:
+                continue
+
+
+
+        # Useful nodes dependencies
+        for node in useful:
+            for parent in defuse.reachable_parents(node):
+                yield parent
+
+    def do_dead_removal(self, ircfg):
+        """
+        Remove useless assignments.
+
+        This function is used to analyse relation of a * complete function *
+        This means the blocks under study represent a solid full function graph.
+
+        Source : Kennedy, K. (1979). A survey of data flow analysis techniques.
+        IBM Thomas J. Watson Research Division, page 43
+
+        @ircfg: IntermediateRepresentation instance
+        """
+
+        modified = False
+        reaching_defs = ReachingDefinitions(ircfg)
+        defuse = DiGraphDefUse(reaching_defs, deref_mem=True)
+        useful = self.get_useful_assignments(ircfg, defuse, reaching_defs)
+        useful = set(useful)
+        for block in list(viewvalues(ircfg.blocks)):
+            irs = []
+            for idx, assignblk in enumerate(block):
+                new_assignblk = dict(assignblk)
+                for lval in assignblk:
+                    if AssignblkNode(block.loc_key, idx, lval) not in useful:
+                        del new_assignblk[lval]
+                        modified = True
+                irs.append(AssignBlock(new_assignblk, assignblk.instr))
+            ircfg.blocks[block.loc_key] = IRBlock(block.loc_key, irs)
+        return modified
+
+    def __call__(self, ircfg):
+        ret = self.do_dead_removal(ircfg)
+        return ret
 
 
 def _test_merge_next_block(ircfg, loc_key):
@@ -680,6 +792,8 @@ class PropagateThroughExprId(object):
         else:
             # Check everyone but node_a.label and node_b.label
             for loc in nodes_to_do - set([node_a.label, node_b.label]):
+                if loc not in ssa.graph.blocks:
+                    continue
                 block = ssa.graph.blocks[loc]
                 if self.has_propagation_barrier(block.assignblks):
                     return True
@@ -725,7 +839,10 @@ class PropagateThroughExprId(object):
         ircfg = ssa.graph
         def_dct = {}
         for node in ircfg.nodes():
-            for index, assignblk in enumerate(ircfg.blocks[node]):
+            block = ircfg.blocks.get(node, None)
+            if block is None:
+                continue
+            for index, assignblk in enumerate(block):
                 for dst, src in viewitems(assignblk):
                     if not dst.is_id():
                         continue
@@ -735,26 +852,6 @@ class PropagateThroughExprId(object):
                     def_dct[dst] = node, index
         return def_dct
 
-    def phi_has_identical_sources(self, ssa, def_dct, var):
-        """
-        If phi operation has identical source values, return it; else None
-        @ssa: SSADiGraph instance
-        @def_dct: dictionary linking variable to its assignment location
-        @var: Phi destination variable
-        """
-        loc_key, index = def_dct[var]
-        sources = ssa.graph.blocks[loc_key][index][var]
-        assert sources.is_op('Phi')
-        sources_values = set()
-        for src in sources.args:
-            assert src in def_dct
-            loc_key, index = def_dct[src]
-            value = ssa.graph.blocks[loc_key][index][src]
-            sources_values.add(value)
-        if len(sources_values) != 1:
-            return None
-        return list(sources_values)[0]
-
     def get_candidates(self, ssa, head, max_expr_depth):
         def_dct = self.get_var_definitions(ssa)
         defuse = SSADefUse.from_ssa(ssa)
@@ -771,10 +868,6 @@ class PropagateThroughExprId(object):
             if node.var.is_mem():
                 continue
             if src.is_op('Phi'):
-                ret = self.phi_has_identical_sources(ssa, def_dct, node.var)
-                if ret:
-                    to_replace[node.var] = ret
-                    node_to_reg[node] = node.var
                 continue
             to_replace[node.var] = src
             node_to_reg[node] = node.var
@@ -891,7 +984,9 @@ class PropagateThroughExprMem(object):
 
         while todo:
             loc_key, index, mem_dst, mem_src = todo.pop()
-            block = ircfg.blocks[loc_key]
+            block = ircfg.blocks.get(loc_key, None)
+            if block is None:
+                continue
             assignblks = list(block)
             block_modified = False
             for i in range(index, len(block)):
@@ -1254,7 +1349,9 @@ class DiGraphLiveness(DiGraph):
         self._blocks = {}
         # Add irblocks gen/kill
         for node in ircfg.nodes():
-            irblock = ircfg.blocks[node]
+            irblock = ircfg.blocks.get(node, None)
+            if irblock is None:
+                continue
             irblockinfos = IRBlockLivenessInfos(irblock)
             self.add_node(irblockinfos.loc_key)
             self.blocks[irblockinfos.loc_key] = irblockinfos
@@ -1357,7 +1454,9 @@ class DiGraphLiveness(DiGraph):
         todo = set(self.leaves())
         while todo:
             node = todo.pop()
-            cur_block = self.blocks[node]
+            cur_block = self.blocks.get(node, None)
+            if cur_block is None:
+                continue
             modified = self.back_propagate_compute(cur_block)
             if not modified:
                 continue
@@ -1376,7 +1475,9 @@ class DiGraphLivenessIRA(DiGraphLiveness):
         """Add ircfg out regs"""
 
         for node in self.leaves():
-            irblock = self.ircfg.blocks[node]
+            irblock = self.ircfg.blocks.get(node, None)
+            if irblock is None:
+                continue
             var_out = ir_arch_a.get_out_regs(irblock)
             irblock_liveness = self.blocks[node]
             irblock_liveness.infos[-1].var_out = var_out
@@ -1454,18 +1555,24 @@ def update_phi_with_deleted_edges(ircfg, edges_to_del):
     @edges_to_del: edges to delete
     """
 
+
+    phi_locs_to_srcs = {}
+    for loc_src, loc_dst in edges_to_del:
+        phi_locs_to_srcs.setdefault(loc_dst, set()).add(loc_src)
+
     modified = False
     blocks = dict(ircfg.blocks)
-    for loc_src, loc_dst in edges_to_del:
+    for loc_dst, loc_srcs in viewitems(phi_locs_to_srcs):
         block = ircfg.blocks[loc_dst]
-        assert block.assignblks
+        if not irblock_has_phi(block):
+            continue
         assignblks = list(block)
         assignblk = assignblks[0]
         out = {}
         for dst, phi_sources in viewitems(assignblk):
             if not phi_sources.is_op('Phi'):
-                out = assignblk
-                break
+                out[dst] = phi_sources
+                continue
             var_to_parents = get_phi_sources_parent_block(
                 ircfg,
                 loc_dst,
@@ -1474,7 +1581,8 @@ def update_phi_with_deleted_edges(ircfg, edges_to_del):
             to_keep = set(phi_sources.args)
             for src in phi_sources.args:
                 parents = var_to_parents[src]
-                if loc_src in parents:
+                remaining = parents.difference(loc_srcs)
+                if not remaining:
                     to_keep.discard(src)
                     modified = True
             assert to_keep
@@ -1504,7 +1612,9 @@ def del_unused_edges(ircfg, heads):
     edges_to_del_1 = set()
     for node in ircfg.nodes():
         successors = set(ircfg.successors(node))
-        block = ircfg.blocks[node]
+        block = ircfg.blocks.get(node, None)
+        if block is None:
+            continue
         dst = block.dst
         possible_dsts = set(solution.value for solution in possible_values(dst))
         if not all(dst.is_loc() for dst in possible_dsts):
@@ -1528,6 +1638,8 @@ def del_unused_edges(ircfg, heads):
     for node in nodes_to_del:
         block = ircfg.blocks[node]
         ircfg.del_node(node)
+        del ircfg.blocks[node]
+
         for assignblock in block:
             for dst in assignblock:
                 deleted_vars.add(dst)
@@ -1551,12 +1663,18 @@ class DiGraphLivenessSSA(DiGraphLivenessIRA):
                 continue
             out = {}
             for sources in viewvalues(irblock[0]):
+                if not sources.is_op('Phi'):
+                    # Some phi sources may have already been resolved to an
+                    # expression
+                    continue
                 var_to_parents = get_phi_sources_parent_block(self, irblock.loc_key, sources.args)
                 for var, var_parents in viewitems(var_to_parents):
                     out.setdefault(var, set()).update(var_parents)
             self.loc_key_to_phi_parents[irblock.loc_key] = out
 
     def back_propagate_to_parent(self, todo, node, parent):
+        if parent not in self.blocks:
+            return
         parent_block = self.blocks[parent]
         cur_block = self.blocks[node]
         irblock = self.ircfg.blocks[node]
diff --git a/miasm/analysis/outofssa.py b/miasm/analysis/outofssa.py
index 497956be..c52b3250 100644
--- a/miasm/analysis/outofssa.py
+++ b/miasm/analysis/outofssa.py
@@ -149,7 +149,9 @@ class UnSSADiGraph(object):
 
         # walk in DFS over the dominator tree
         for loc_key in dominator_tree.walk_depth_first_forward(self.head):
-            irblock = ircfg.blocks[loc_key]
+            irblock = ircfg.blocks.get(loc_key, None)
+            if irblock is None:
+                continue
 
             # Create live index for phi new vars
             # They do not exist in the graph yet, so index is set to None
diff --git a/miasm/analysis/simplifier.py b/miasm/analysis/simplifier.py
index 8c448991..8e9005a8 100644
--- a/miasm/analysis/simplifier.py
+++ b/miasm/analysis/simplifier.py
@@ -8,7 +8,8 @@ from miasm.analysis.ssa import SSADiGraph
 from miasm.analysis.outofssa import UnSSADiGraph
 from miasm.analysis.data_flow import DiGraphLivenessSSA
 from miasm.expression.simplifications import expr_simp
-from miasm.analysis.data_flow import dead_simp, \
+from miasm.ir.ir import AssignBlock, IRBlock
+from miasm.analysis.data_flow import DeadRemoval, \
     merge_blocks, remove_empty_assignblks, \
     PropagateExprIntThroughExprId, PropagateThroughExprId, \
     PropagateThroughExprMem, del_unused_edges
@@ -83,6 +84,7 @@ class IRCFGSimplifierCommon(IRCFGSimplifier):
     def __init__(self, ir_arch, expr_simp=expr_simp):
         self.expr_simp = expr_simp
         super(IRCFGSimplifierCommon, self).__init__(ir_arch)
+        self.deadremoval = DeadRemoval(self.ir_arch)
 
     def init_passes(self):
         self.passes = [
@@ -114,7 +116,7 @@ class IRCFGSimplifierCommon(IRCFGSimplifier):
         @ircfg: IRCFG instance to simplify
         @head: Location instance of the ircfg head
         """
-        modified = dead_simp(self.ir_arch, ircfg)
+        modified = self.deadremoval(ircfg)
         modified |= remove_empty_assignblks(ircfg)
         modified |= merge_blocks(ircfg, set([head]))
         return modified
@@ -144,6 +146,7 @@ class IRCFGSimplifierSSA(IRCFGSimplifierCommon):
         self.propag_int = PropagateExprIntThroughExprId()
         self.propag_expr = PropagateThroughExprId()
         self.propag_mem = PropagateThroughExprMem()
+        self.deadremoval = DeadRemoval(self.ir_arch, self.all_ssa_vars)
 
     def get_forbidden_regs(self):
         """
@@ -168,8 +171,13 @@ class IRCFGSimplifierSSA(IRCFGSimplifierCommon):
             self.do_propagate_mem,
             self.do_propagate_expr,
             self.do_dead_simp_ssa,
+            self.do_remove_empty_assignblks,
+            self.do_del_unused_edges,
+            self.do_merge_blocks,
         ]
 
+
+
     def ircfg_to_ssa(self, ircfg, head):
         """
         Apply the SSA transformation to @ircfg using it's @head
@@ -217,8 +225,15 @@ class IRCFGSimplifierSSA(IRCFGSimplifierCommon):
         @head: Location instance of the graph head
         """
         modified = self.propag_int.propagate(ssa, head)
-        modified |= ssa.graph.simplify(self.expr_simp)
-        modified |= del_unused_edges(ssa.graph, set([head]))
+        return modified
+
+    @fix_point
+    def do_del_unused_edges(self, ssa, head):
+        """
+        Del unused edges of the ssa graph
+        @head: Location instance of the graph head
+        """
+        modified = del_unused_edges(ssa.graph, set([head]))
         return modified
 
     @fix_point
@@ -228,8 +243,6 @@ class IRCFGSimplifierSSA(IRCFGSimplifierCommon):
         @head: Location instance of the graph head
         """
         modified = self.propag_mem.propagate(ssa, head)
-        modified |= ssa.graph.simplify(self.expr_simp)
-        modified |= del_unused_edges(ssa.graph, set([head]))
         return modified
 
     @fix_point
@@ -239,15 +252,31 @@ class IRCFGSimplifierSSA(IRCFGSimplifierCommon):
         @head: Location instance of the graph head
         """
         modified = self.propag_expr.propagate(ssa, head)
-        modified |= ssa.graph.simplify(self.expr_simp)
-        modified |= del_unused_edges(ssa.graph, set([head]))
+        return modified
+
+    @fix_point
+    def do_remove_empty_assignblks(self, ssa, head):
+        """
+        Remove empty assignblks
+        @head: Location instance of the graph head
+        """
+        modified = remove_empty_assignblks(ssa.graph)
+        return modified
+
+    @fix_point
+    def do_merge_blocks(self, ssa, head):
+        """
+        Merge blocks with one parent/son
+        @head: Location instance of the graph head
+        """
+        modified = merge_blocks(ssa.graph, set([head]))
         return modified
 
     @fix_point
     def do_dead_simp_ssa(self, ssa, head):
         """
         Apply:
-        - dead_simp
+        - deadrm
         - remove_empty_assignblks
         - del_unused_edges
         - merge_blocks
@@ -257,10 +286,7 @@ class IRCFGSimplifierSSA(IRCFGSimplifierCommon):
         @ircfg: IRCFG instance to simplify
         @head: Location instance of the ircfg head
         """
-        modified = dead_simp(self.ir_arch, ssa.graph)
-        modified |= remove_empty_assignblks(ssa.graph)
-        modified |= del_unused_edges(ssa.graph, set([head]))
-        modified |= merge_blocks(ssa.graph, set([head]))
+        modified = self.deadremoval(ssa.graph)
         return modified
 
     def do_simplify(self, ssa, head):
@@ -285,6 +311,7 @@ class IRCFGSimplifierSSA(IRCFGSimplifierCommon):
 
     def simplify(self, ircfg, head):
         """
+        Add access to "abi out regs" in each leaf block
         Apply SSA transformation to @ircfg
         Apply passes until reaching a fix point
         Apply out-of-ssa transformation
@@ -295,9 +322,11 @@ class IRCFGSimplifierSSA(IRCFGSimplifierCommon):
         @ircfg: IRCFG instance to simplify
         @head: Location instance of the ircfg head
         """
+
         ssa = self.ircfg_to_ssa(ircfg, head)
         ssa = self.do_simplify_loop(ssa, head)
         ircfg = self.ssa_to_unssa(ssa, head)
         ircfg_simplifier = IRCFGSimplifierCommon(self.ir_arch)
+        ircfg_simplifier.deadremoval.add_expr_to_original_expr(self.all_ssa_vars)
         ircfg_simplifier.simplify(ircfg, head)
         return ircfg
diff --git a/miasm/analysis/ssa.py b/miasm/analysis/ssa.py
index 827be009..7f0b0f13 100644
--- a/miasm/analysis/ssa.py
+++ b/miasm/analysis/ssa.py
@@ -73,9 +73,6 @@ class SSA(object):
         # IRCFG instance
         self.ircfg = ircfg
 
-        # SSA blocks
-        self.blocks = {}
-
         # stack for RHS
         self._stack_rhs = {}
         # stack for LHS
@@ -120,7 +117,6 @@ class SSA(object):
 
     def reset(self):
         """Resets SSA transformation"""
-        self.blocks = {}
         self.expressions = {}
         self._stack_rhs = {}
         self._stack_lhs = {}
@@ -427,12 +423,13 @@ class SSADiGraph(SSA):
         a set of IRBlocks in which the variable gets assigned
         """
 
+        visited_loc = set()
         for loc_key in self.graph.walk_depth_first_forward(head):
             irblock = self.get_block(loc_key)
             if irblock is None:
                 # Incomplete graph
                 continue
-
+            visited_loc.add(loc_key)
             # search for block's IR definitions/destinations
             for assignblk in irblock.assignblks:
                 for dst in assignblk:
@@ -443,6 +440,8 @@ class SSADiGraph(SSA):
                             continue
                         # map variable definition to blocks
                         self.defs.setdefault(dst, set()).add(irblock.loc_key)
+        if visited_loc != set(self.graph.blocks):
+            raise RuntimeError("Cannot operate on a non connected graph")
 
     def _place_phi(self, head):
         """
@@ -608,9 +607,18 @@ class SSADiGraph(SSA):
             if irblock is None:
                 continue
             assignblk = AssignBlock(self._phinodes[loc_key])
-            # insert at the beginning
-            new_irs = IRBlock(loc_key, [assignblk] + list(irblock.assignblks))
-            self.ircfg.blocks[loc_key] = new_irs
+            if irblock_has_phi(irblock):
+                # If first block contains phi, we are updating an existing ssa form
+                # so update phi
+                assignblks = list(irblock.assignblks)
+                out = dict(assignblks[0])
+                out.update(dict(assignblk))
+                assignblks[0] = AssignBlock(out, assignblk.instr)
+                new_irblock = IRBlock(loc_key, assignblks)
+            else:
+                # insert at the beginning
+                new_irblock = IRBlock(loc_key, [assignblk] + list(irblock.assignblks))
+            self.ircfg.blocks[loc_key] = new_irblock
 
     def _fix_no_def_var(self, head):
         """
diff --git a/miasm/arch/ppc/regs.py b/miasm/arch/ppc/regs.py
index 97556931..4b710045 100644
--- a/miasm/arch/ppc/regs.py
+++ b/miasm/arch/ppc/regs.py
@@ -46,10 +46,19 @@ superregs_str = (["SPRG%d" % i for i in range(4)] +
 superregs_expr, superregs_init, superregs = gen_regs(superregs_str,
                                                      globals(), 32)
 
+mmuregs_str = (["SR%d" % i for i in range(16)] +
+               ["IBAT%dU" % i for i in range(4)] +
+               ["IBAT%dL" % i for i in range(4)] +
+               ["DBAT%dU" % i for i in range(4)] +
+               ["DBAT%dL" % i for i in range(4)] +
+               ["SDR1"])
+mmuregs_expr, mmuregs_init, mmuregs = gen_regs(mmuregs_str,
+                                               globals(), 32)
+
 regs_flt_expr = []
 
 all_regs_ids = (gpregs_expr + crfbitregs_expr + xerbitregs_expr +
-                xerbcreg_expr + otherregs_expr + superregs_expr +
+                xerbcreg_expr + otherregs_expr + superregs_expr + mmuregs_expr +
                 [ exception_flags, spr_access, reserve, reserve_address ])
 all_regs_ids_byname = dict([(x.name, x) for x in all_regs_ids])
 all_regs_ids_init = [ExprId("%s_init" % x.name, x.size) for x in all_regs_ids]
diff --git a/miasm/arch/ppc/sem.py b/miasm/arch/ppc/sem.py
index 5e8e394c..fd6db8f3 100644
--- a/miasm/arch/ppc/sem.py
+++ b/miasm/arch/ppc/sem.py
@@ -10,9 +10,19 @@ from miasm.jitter.csts import *
 
 spr_dict = {
     8: LR, 9: CTR, 18: DSISR, 19: DAR,
-    22: DEC, 26: SRR0, 27: SRR1,
+    22: DEC, 25: SDR1, 26: SRR0, 27: SRR1,
     272: SPRG0, 273: SPRG0, 274: SPRG1, 275: SPRG2, 276: SPRG3,
-    284: TBL, 285: TBU, 287: PVR, 1023: PIR
+    284: TBL, 285: TBU, 287: PVR,
+    528: IBAT0U, 529: IBAT0L, 530: IBAT1U, 531: IBAT1L, 532: IBAT2U, 533: IBAT2L, 534: IBAT3U, 535: IBAT3L,
+    536: DBAT0U, 537: DBAT0L, 538: DBAT1U, 539: DBAT1L, 540: DBAT2U, 541: DBAT2L, 542: DBAT3U, 543: DBAT3L,
+    1023: PIR
+}
+
+sr_dict = {
+    0: SR0, 1: SR1, 2: SR2, 3: SR3,
+    4: SR4, 5: SR5, 6: SR6, 7: SR7,
+    8: SR8, 9: SR9, 10: SR10, 11: SR11,
+    12: SR12, 13: SR13, 14: SR14, 15: SR15
 }
 
 crf_dict = dict((ExprId("CR%d" % i, 4),
@@ -23,6 +33,7 @@ crf_dict = dict((ExprId("CR%d" % i, 4),
 ctx = {
     'crf_dict': crf_dict,
     'spr_dict': spr_dict,
+    'sr_dict': sr_dict,
     'expr': expr,
 }
 
@@ -384,6 +395,22 @@ def mn_mtspr(ir, instr, arg1, arg2):
                                     SPR_ACCESS_IS_WRITE), 32)),
                  ExprAssign(exception_flags, ExprInt(EXCEPT_SPR_ACCESS, 32)) ], []
 
+def mn_mtsr(ir, instr, sr, rs):
+    srid = sr.arg.arg
+    return [ ExprAssign(sr_dict[srid], rs) ], []
+
+# TODO
+#def mn_mtsrin(ir, instr, rs, rb):
+#    return [ ExprAssign(sr_dict[rb[0:3]], rs) ], []
+
+def mn_mfsr(ir, instr, rd, sr):
+    srid = sr.arg.arg
+    return [ ExprAssign(rd, sr_dict[srid]) ], []
+
+# TODO
+#def mn_mfsrin(ir, instr, rd, rb):
+#    return [ ExprAssign(rd, sr_dict[rb[0:3]]) ], []
+
 def mn_do_mul(ir, instr, rd, ra, arg2):
     variant = instr.name[3:]
     if variant[-1] == '.':
@@ -809,13 +836,13 @@ sem_dir = {
     'MFCR': mn_do_mfcr,
     'MFMSR': mn_mfmsr,
     'MFSPR': mn_mfspr,
-    'MFSR': mn_do_nop_warn,
+    'MFSR': mn_mfsr,
     'MFSRIN': mn_do_nop_warn,
     'MFTB': mn_mfmsr,
     'MTCRF': mn_mtcrf,
     'MTMSR': mn_mtmsr,
     'MTSPR': mn_mtspr,
-    'MTSR': mn_do_nop_warn,
+    'MTSR': mn_mtsr,
     'MTSRIN': mn_do_nop_warn,
     'NAND': mn_do_nand,
     'NAND.': mn_do_nand,
diff --git a/miasm/ir/analysis.py b/miasm/ir/analysis.py
index 774e66f7..9aa61f59 100644
--- a/miasm/ir/analysis.py
+++ b/miasm/ir/analysis.py
@@ -5,7 +5,6 @@ import logging
 
 from miasm.ir.ir import IntermediateRepresentation, AssignBlock
 from miasm.expression.expression import ExprOp, ExprAssign
-from miasm.analysis.data_flow import dead_simp as new_dead_simp_imp
 
 
 log = logging.getLogger("analysis")
@@ -106,8 +105,3 @@ class ira(IntermediateRepresentation):
     def sizeof_pointer(self):
         "Return the size of a void* in bits"
         raise NotImplementedError("Abstract method")
-
-    def dead_simp(self, ircfg):
-        """Deprecated: See miasm.analysis.data_flow.dead_simp()"""
-        warnings.warn('DEPRECATION WARNING: Please use miasm.analysis.data_flow.dead_simp(ira) instead of ira.dead_simp()')
-        new_dead_simp_imp(self, ircfg)
diff --git a/miasm/jitter/arch/JitCore_ppc32_regs.h b/miasm/jitter/arch/JitCore_ppc32_regs.h
index d15b5e51..a16d1e95 100644
--- a/miasm/jitter/arch/JitCore_ppc32_regs.h
+++ b/miasm/jitter/arch/JitCore_ppc32_regs.h
@@ -87,3 +87,37 @@ JITCORE_PPC_REG_EXPAND(PVR, 32)
 JITCORE_PPC_REG_EXPAND(DEC, 32)
 JITCORE_PPC_REG_EXPAND(TBL, 32)
 JITCORE_PPC_REG_EXPAND(TBU, 32)
+
+JITCORE_PPC_REG_EXPAND(SR0, 32)
+JITCORE_PPC_REG_EXPAND(SR1, 32)
+JITCORE_PPC_REG_EXPAND(SR2, 32)
+JITCORE_PPC_REG_EXPAND(SR3, 32)
+JITCORE_PPC_REG_EXPAND(SR4, 32)
+JITCORE_PPC_REG_EXPAND(SR5, 32)
+JITCORE_PPC_REG_EXPAND(SR6, 32)
+JITCORE_PPC_REG_EXPAND(SR7, 32)
+JITCORE_PPC_REG_EXPAND(SR8, 32)
+JITCORE_PPC_REG_EXPAND(SR9, 32)
+JITCORE_PPC_REG_EXPAND(SR10, 32)
+JITCORE_PPC_REG_EXPAND(SR11, 32)
+JITCORE_PPC_REG_EXPAND(SR12, 32)
+JITCORE_PPC_REG_EXPAND(SR13, 32)
+JITCORE_PPC_REG_EXPAND(SR14, 32)
+JITCORE_PPC_REG_EXPAND(SR15, 32)
+JITCORE_PPC_REG_EXPAND(IBAT0U, 32)
+JITCORE_PPC_REG_EXPAND(IBAT0L, 32)
+JITCORE_PPC_REG_EXPAND(IBAT1U, 32)
+JITCORE_PPC_REG_EXPAND(IBAT1L, 32)
+JITCORE_PPC_REG_EXPAND(IBAT2U, 32)
+JITCORE_PPC_REG_EXPAND(IBAT2L, 32)
+JITCORE_PPC_REG_EXPAND(IBAT3U, 32)
+JITCORE_PPC_REG_EXPAND(IBAT3L, 32)
+JITCORE_PPC_REG_EXPAND(DBAT0U, 32)
+JITCORE_PPC_REG_EXPAND(DBAT0L, 32)
+JITCORE_PPC_REG_EXPAND(DBAT1U, 32)
+JITCORE_PPC_REG_EXPAND(DBAT1L, 32)
+JITCORE_PPC_REG_EXPAND(DBAT2U, 32)
+JITCORE_PPC_REG_EXPAND(DBAT2L, 32)
+JITCORE_PPC_REG_EXPAND(DBAT3U, 32)
+JITCORE_PPC_REG_EXPAND(DBAT3L, 32)
+JITCORE_PPC_REG_EXPAND(SDR1, 32)
diff --git a/test/analysis/data_flow.py b/test/analysis/data_flow.py
index 259aca7c..98efecbe 100644
--- a/test/analysis/data_flow.py
+++ b/test/analysis/data_flow.py
@@ -5,7 +5,7 @@ from future.utils import viewitems
 
 from miasm.expression.expression import ExprId, ExprInt, ExprAssign, ExprMem
 from miasm.core.locationdb import LocationDB
-from miasm.analysis.data_flow import *
+from miasm.analysis.data_flow import DeadRemoval, ReachingDefinitions, DiGraphDefUse
 from miasm.ir.analysis import ira
 from miasm.ir.ir import IRBlock, AssignBlock
 
@@ -82,6 +82,7 @@ class IRATest(ira):
         return set([self.ret_reg, self.sp])
 
 IRA = IRATest(loc_db)
+deadrm = DeadRemoval(IRA)
 
 # graph 1 : Simple graph with dead and alive variables
 
@@ -696,7 +697,7 @@ for test_nb, test in enumerate([(G1_IRA, G1_EXP_IRA),
     defuse = DiGraphDefUse(reaching_defs, deref_mem=True)
 
     # # Simplify graph
-    dead_simp(IRA, g_ira)
+    deadrm(g_ira)
 
     # # Print simplified graph, for debug
     open("simp_graph_%02d.dot" % (test_nb+1), "w").write(g_ira.dot())