]> git.unchartedbackwaters.co.uk Git - francis/libjit.git/commitdiff
implement the "combine" part of the clean algorithm
authorAleksey Demakov <ademakov@gmail.com>
Sun, 1 Nov 2009 06:14:50 +0000 (12:14 +0600)
committerAleksey Demakov <ademakov@gmail.com>
Sun, 1 Nov 2009 06:14:50 +0000 (12:14 +0600)
ChangeLog
jit/jit-block.c

index b9231747a238a580f4ff7cdafbd23cd3960da5ab..1aea39c2f986a4bb20d7c9e78dcb2173a0c12db4 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2009-11-01  Aleksey Demakov  <ademakov@gmail.com>
+
+       * jit/jit-block.c (_jit_block_clean_cfg): implement the "combine" part
+       of cleanup algorithm.
+
 2009-10-31  Klaus Treichel  <ktreichel@web.de>
 
        * jit/jit-compile.c (_JIT_RESULT_TO_OBJECT, _JIT_RESULT_FROM_OBJECT):
index 82e27911de9aef4d6f5d65110381cbb84d2d920e..23c2f587a794331517083a04dadc3fcadf8aa61b 100644 (file)
@@ -370,14 +370,14 @@ merge_empty(jit_function_t func, jit_block_t block, int *changed)
        }
 
        /* If there is an incoming fallthrough edge then retarget it
-          if the outgoing edge is also fallthough. Otherwise adjust
+          if the outgoing edge is also fallthrough. Otherwise adjust
           the preds array to contain this edge only.  */
-       if(fallthru_edge != NULL)
+       if(fallthru_edge)
        {
                if(succ_edge->flags == _JIT_EDGE_FALLTHRU)
                {
                        *changed = 1;
-                       if(!attach_edge_dst(pred_edge, succ_block))
+                       if(!attach_edge_dst(fallthru_edge, succ_block))
                        {
                                jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY);
                        }
@@ -401,6 +401,84 @@ merge_empty(jit_function_t func, jit_block_t block, int *changed)
        }
 }
 
+/* Combine non-empty block with its successor */
+static void
+combine_block(jit_function_t func, jit_block_t block, int *changed)
+{
+       jit_block_t succ_block;
+       int branch, num_insns, max_insns;
+       jit_insn_t insns;
+
+       /* Find block successor */
+       succ_block = block->succs[0]->dst;
+
+       /* Does block end with a (redundant) branch instruction? */
+       branch = (block->succs[0]->flags == _JIT_EDGE_BRANCH);
+
+       /* If the branch is there then preallocate memory for it,
+          doing it here simplifies handling of the out-of-memory
+          condition */
+       if(branch && !succ_block->max_insns)
+       {
+               succ_block->insns = jit_malloc(sizeof(struct _jit_insn));
+               if(!succ_block->insns)
+               {
+                       jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY);
+               }
+               succ_block->max_insns = 1;
+       }
+
+       /* Allocate enough memory for combined instructions */
+       max_insns = block->max_insns;
+       num_insns = block->num_insns + succ_block->num_insns;
+       if(num_insns > max_insns)
+       {
+               max_insns = num_insns;
+               insns = (jit_insn_t) jit_realloc(block->insns,
+                                                max_insns * sizeof(struct _jit_insn));
+               if(!insns)
+               {
+                       jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY);
+               }
+       }
+       else
+       {
+               insns = block->insns;
+       }
+
+       /* Copy instruction from the successor block after the instructions
+          of the original block */
+       if(succ_block->num_insns)
+       {
+               jit_memcpy(insns + block->num_insns,
+                          succ_block->insns,
+                          succ_block->num_insns * sizeof(struct _jit_insn));
+       }
+
+       /* Move combined instructions to the successor, but if there was
+          a branch in the original block then keep the branch around,
+          merge_empty() will take care of it if it may be optimized away.
+          To reduce the number of allocations, swap the arrays around
+          rather than allocating a fresh array for the empty block. */
+       block->insns = succ_block->insns;
+       block->max_insns = succ_block->max_insns;
+       if(branch)
+       {
+               /* Copy the branch instruction */
+               jit_memcpy(block->insns,
+                          insns + block->num_insns - 1,
+                          sizeof(struct _jit_insn));
+               /* In the combined block turn branch into NOP */
+               insns[block->num_insns - 1].opcode = JIT_OP_NOP;
+       }
+       block->num_insns = branch;
+       succ_block->insns = insns;
+       succ_block->max_insns = max_insns;
+       succ_block->num_insns = num_insns;
+
+       merge_empty(func, block, changed);
+}
+
 /* Delete block along with references to it */
 static void
 eliminate_block(jit_block_t block)
@@ -602,6 +680,10 @@ _jit_block_clean_cfg(jit_function_t func)
                {
                        continue;
                }
+
+               /* Take care of redundant branches that is, if possible, either
+                  replace a branch with NOP turning it to a fall-through case
+                  or conditional branch reduce to unconditional */
                if(block->succs[0]->flags == _JIT_EDGE_BRANCH)
                {
                        insn = _jit_block_get_last(block);
@@ -615,34 +697,40 @@ _jit_block_clean_cfg(jit_function_t func)
                                /* Replace useless branch with NOP */
                                changed = 1;
                                insn->opcode = JIT_OP_NOP;
-                               if(block->num_succs == 1)
+                               if(block->num_succs == 2)
+                               {
+                                       /* For conditional branch delete the branch
+                                          edge while leaving the fallthough edge
+                                          intact */
+                                       delete_edge(func, block->succs[0]);
+                               }
+                               else
                                {
                                        /* For unconditional branch replace the branch
                                           edge with a fallthrough edge */
                                        block->ends_in_dead = 0;
                                        block->succs[0]->flags = _JIT_EDGE_FALLTHRU;
                                }
-                               else
-                               {
-                                       /* For conditional branch delete the branch
-                                          edge while leaving the fallthough edge */
-                                       delete_edge(func, block->succs[0]);
-                               }
                        }
-                       else if(block->num_succs == 2 && block->next->num_succs == 1
+                       else if(block->num_succs == 2
+                               && block->next->num_succs == 1
                                && block->next->succs[0]->flags == _JIT_EDGE_BRANCH
                                && block->succs[0]->dst == block->next->succs[0]->dst
                                && is_empty_block(block->next))
                        {
-                               /* Replace conditional branch with unconditional,
-                                  remove the fallthough edge while leaving the branch
-                                  edge */
+                               /* For conditional branch followed by unconditional
+                                  that has the same target make the first branch
+                                  unconditional too, remove the fallthough edge while
+                                  leaving the branch edge intact */
                                changed = 1;
                                insn->opcode = JIT_OP_BR;
                                block->ends_in_dead = 1;
                                delete_edge(func, block->succs[1]);
                        }
                }
+
+               /* Try to simplify basic blocks that end with fall-thtough or
+                  unconditional branch */
                if(block->num_succs == 1
                   && (block->succs[0]->flags == _JIT_EDGE_BRANCH
                       || block->succs[0]->flags == _JIT_EDGE_FALLTHRU))
@@ -652,9 +740,18 @@ _jit_block_clean_cfg(jit_function_t func)
                                /* Remove empty block */
                                merge_empty(func, block, &changed);
                        }
-               }
+                       else if(block->succs[0]->dst->num_preds == 1)
+                       {
+                               /* Combine with the successor block if it has
+                                  only one predecessor */
+                               combine_block(func, block, &changed);
+                       }
 
-               /* TODO: "combine blocks" and "hoist branch" parts of the Clean algorithm */
+                       /* TODO: "hoist branch" part of the Clean algorithm.
+                          It is somewhat complicated as libjit conditional
+                          branches differ too much from ILOC conditional
+                          branches */
+               }
        }
 
        if(changed)