]> git.unchartedbackwaters.co.uk Git - francis/libjit.git/commitdiff
allow multiple labels for single block
authorAleksey Demakov <ademakov@gmail.com>
Sat, 9 May 2009 21:54:31 +0000 (21:54 +0000)
committerAleksey Demakov <ademakov@gmail.com>
Sat, 9 May 2009 21:54:31 +0000 (21:54 +0000)
ChangeLog
include/jit/jit-block.h
jit/jit-block.c
jit/jit-dump.c
jit/jit-function.c
jit/jit-insn.c
jit/jit-internal.h

index ceaad704a72cb88c02ced4e33f98cf0cbb556ebd..fc864903a5aea6e1a61452b0a6ce753f0d2de252 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2009-05-10  Aleksey Demakov  <ademakov@gmail.com>
+
+       * jit/jit-internal.h (struct _jit_label_info): add srtuct.
+       (struct _jit_builder): replace label_blocks with label_info.
+
+       * jit/jit-block.c (_jit_block_record_label):
+       * jit/jit-dump.c (jit_dump_function):
+       * jit/jit-insn.c (jit_insn_label): allow more than one label per
+       basic block.
+
+       * include/jit/jit-block.h:
+       * jit/jit-block.c (jit_block_get_next_label): add function.
+
 2009-05-09  Aleksey Demakov  <ademakov@gmail.com>
 
        * jit/jit-internal.h, jit/jit-block.c, jit/jit-insn.c,
index eda9f024d86747cb6db434b3c912befc5066a5fb..65fb0927fcbb50ee283e74aa233c90330a596e48 100644 (file)
@@ -30,14 +30,16 @@ extern      "C" {
 jit_function_t jit_block_get_function(jit_block_t block) JIT_NOTHROW;
 jit_context_t jit_block_get_context(jit_block_t block) JIT_NOTHROW;
 jit_label_t jit_block_get_label(jit_block_t block) JIT_NOTHROW;
-jit_block_t jit_block_next
-       (jit_function_t func, jit_block_t previous) JIT_NOTHROW;
-jit_block_t jit_block_previous
-       (jit_function_t func, jit_block_t previous) JIT_NOTHROW;
-jit_block_t jit_block_from_label
-       (jit_function_t func, jit_label_t label) JIT_NOTHROW;
+jit_label_t jit_block_get_next_label(jit_block_t block,
+                                    jit_label_t label) JIT_NOTHROW;
+jit_block_t jit_block_next(jit_function_t func,
+                          jit_block_t previous) JIT_NOTHROW;
+jit_block_t jit_block_previous(jit_function_t func,
+                              jit_block_t previous) JIT_NOTHROW;
+jit_block_t jit_block_from_label(jit_function_t func,
+                                jit_label_t label) JIT_NOTHROW;
 int jit_block_set_meta(jit_block_t block, int type, void *data,
-                                          jit_meta_free_func free_data) JIT_NOTHROW;
+                      jit_meta_free_func free_data) JIT_NOTHROW;
 void *jit_block_get_meta(jit_block_t block, int type) JIT_NOTHROW;
 void jit_block_free_meta(jit_block_t block, int type) JIT_NOTHROW;
 int jit_block_is_reachable(jit_block_t block) JIT_NOTHROW;
index 0f35f569a4e2766e6d98741c47012a8bac720a8a..2bfe7b625ca80bf52441d4f406c61166879eb264 100644 (file)
@@ -36,51 +36,6 @@ typedef struct _jit_block_stack_entry
        int index;
 } _jit_block_stack_entry_t;
 
-static jit_block_t
-create_block(jit_function_t func)
-{
-       jit_block_t block;
-
-       /* Allocate memory for the block */
-       block = jit_cnew(struct _jit_block);
-       if(!block)
-       {
-               return 0;
-       }
-
-       /* Initialize the block */
-       block->func = func;
-       block->label = jit_label_undefined;
-
-       return block;
-}
-
-static void
-free_block(jit_block_t block)
-{
-       jit_meta_destroy(&block->meta);
-       jit_free(block->succs);
-       jit_free(block->preds);
-       jit_free(block->insns);
-       jit_free(block);
-}
-
-/* Block may not be deleted right when it was found useless from
-   the control flow perspective as it might be referenced from
-   elsewhere, for instance, from some jit_value_t */
-static void
-delete_block(jit_block_t block)
-{
-       jit_free(block->succs);
-       block->succs = 0;
-       jit_free(block->preds);
-       block->preds = 0;
-       jit_free(block->insns);
-       block->insns = 0;
-
-       block->next = block->func->builder->deleted_blocks;
-       block->func->builder->deleted_blocks = block->next;
-}
 
 static int
 create_edge(jit_function_t func, jit_block_t src, jit_block_t dst, int flags, int create)
@@ -332,6 +287,32 @@ attach_edge_dst(_jit_edge_t edge, jit_block_t block)
        return 1;
 }
 
+/* Delete edge along with references to it */
+static void
+delete_edge(jit_function_t func, _jit_edge_t edge)
+{
+       detach_edge_src(edge);
+       detach_edge_dst(edge);
+       jit_memory_pool_dealloc(&func->builder->edge_pool, edge);
+}
+
+/* Block may not be deleted right when it was found useless from
+   the control flow perspective as it might be referenced from
+   elsewhere, for instance, from some jit_value_t */
+static void
+delete_block(jit_block_t block)
+{
+       jit_free(block->succs);
+       block->succs = 0;
+       jit_free(block->preds);
+       block->preds = 0;
+       jit_free(block->insns);
+       block->insns = 0;
+
+       block->next = block->func->builder->deleted_blocks;
+       block->func->builder->deleted_blocks = block->next;
+}
+
 /* The block is empty if it contains nothing apart from an unconditional branch */
 static int
 is_empty_block(jit_block_t block)
@@ -352,6 +333,23 @@ is_empty_block(jit_block_t block)
        return 1;
 }
 
+static void
+merge_labels(jit_function_t func, jit_block_t block, jit_label_t label)
+{
+       _jit_label_info_t *info;
+       jit_label_t alias;
+
+       while(label != jit_label_undefined)
+       {
+               info = &func->builder->label_info[label];
+               alias = info->alias;
+               info->block = block;
+               info->alias = block->label;
+               block->label = label;
+               label = alias;
+       }
+}
+
 /* Merge empty block with its successor */
 static int
 merge_empty(jit_function_t func, jit_block_t block, int *changed)
@@ -364,23 +362,8 @@ merge_empty(jit_function_t func, jit_block_t block, int *changed)
        succ_edge = block->succs[0];
        succ_block = succ_edge->dst;
 
-       /* Retarget label to the successor block. */
-       if(block->label != jit_label_undefined)
-       {
-               func->builder->label_blocks[block->label] = succ_block;
-               if(succ_block->label == jit_label_undefined)
-               {
-                       succ_block->label = block->label;
-               }
-               else
-               {
-                       /* FIXME: If both blocks have labels then this results
-                          into a duplicate label which is not recorded in the
-                          target block. This shouldn't cause big problems now
-                          but perhaps some sort of block-to-label-list mappings
-                          might be useful someday. */
-               }
-       }
+       /* Retarget labels bound to this block to the successor block. */
+       merge_labels(func, succ_block, block->label);
 
        /* Retarget all incoming edges except a fallthrough edge */
        fallthru_edge = 0;
@@ -435,15 +418,6 @@ merge_empty(jit_function_t func, jit_block_t block, int *changed)
        return 1;
 }
 
-/* Delete edge along with references to it */
-static void
-delete_edge(jit_function_t func, _jit_edge_t edge)
-{
-       detach_edge_src(edge);
-       detach_edge_dst(edge);
-       jit_memory_pool_dealloc(&func->builder->edge_pool, edge);
-}
-
 /* Delete block along with references to it */
 static void
 eliminate_block(jit_block_t block)
@@ -553,13 +527,13 @@ free_order(jit_function_t func)
 int
 _jit_block_init(jit_function_t func)
 {
-       func->builder->entry_block = create_block(func);
+       func->builder->entry_block = _jit_block_create(func);
        if(!func->builder->entry_block)
        {
                return 0;
        }
 
-       func->builder->exit_block = create_block(func);
+       func->builder->exit_block = _jit_block_create(func);
        if(!func->builder->exit_block)
        {
                return 0;
@@ -581,7 +555,7 @@ _jit_block_free(jit_function_t func)
        while(block)
        {
                next = block->next;
-               free_block(block);
+               _jit_block_destroy(block);
                block = next;
        }
 
@@ -589,7 +563,7 @@ _jit_block_free(jit_function_t func)
        while(block)
        {
                next = block->next;
-               free_block(block);
+               _jit_block_destroy(block);
                block = next;
        }
 
@@ -792,41 +766,40 @@ _jit_block_compute_postorder(jit_function_t func)
 }
 
 jit_block_t
-_jit_block_create(jit_function_t func, jit_label_t *label)
+_jit_block_create(jit_function_t func)
 {
        jit_block_t block;
 
-       /* Create the block */
-       block = create_block(func);
+       /* Allocate memory for the block */
+       block = jit_cnew(struct _jit_block);
        if(!block)
        {
                return 0;
        }
 
-       /* Set the block label */
-       if(label)
-       {
-               if(*label == jit_label_undefined)
-               {
-                       *label = (func->builder->next_label)++;
-               }
-               block->label = *label;
-               if(!_jit_block_record_label(block))
-               {
-                       jit_free(block);
-                       return 0;
-               }
-       }
-
-       /* Add the block to the end of the function's list */
-       block->next = func->builder->exit_block;
-       block->prev = func->builder->exit_block->prev;
-       block->next->prev = block;
-       block->prev->next = block;
+       /* Initialize the block */
+       block->func = func;
+       block->label = jit_label_undefined;
 
        return block;
 }
 
+void
+_jit_block_destroy(jit_block_t block)
+{
+       /* Free all the memory owned by the block. CFG edges are not freed
+          because each edge is shared between two blocks so the ownership
+          of the edge is ambiguous. Sometimes an edge may be redirected to
+          another block rather than freed. Therefore edges are freed (or
+          not freed) separately. However succs and preds arrays are freed,
+          these contain pointers to edges, not edges themselves. */
+       jit_meta_destroy(&block->meta);
+       jit_free(block->succs);
+       jit_free(block->preds);
+       jit_free(block->insns);
+       jit_free(block);
+}
+
 void
 _jit_block_detach(jit_block_t first, jit_block_t last)
 {
@@ -853,34 +826,42 @@ _jit_block_attach_before(jit_block_t block, jit_block_t first, jit_block_t last)
 }
 
 int
-_jit_block_record_label(jit_block_t block)
+_jit_block_record_label(jit_block_t block, jit_label_t label)
 {
-       jit_builder_t builder = block->func->builder;
+       jit_builder_t builder;
        jit_label_t num;
-       jit_block_t *blocks;
-       if(block->label >= builder->max_label_blocks)
+       _jit_label_info_t *info;
+
+       builder = block->func->builder;
+       if(label >= builder->max_label_info)
        {
-               num = builder->max_label_blocks;
+               num = builder->max_label_info;
                if(num < 64)
                {
                        num = 64;
                }
-               while(num <= block->label)
+               while(num <= label)
                {
                        num *= 2;
                }
-               blocks = (jit_block_t *)jit_realloc(builder->label_blocks,
-                                                   num * sizeof(jit_block_t));
-               if(!blocks)
+
+               info = (_jit_label_info_t *) jit_realloc(builder->label_info,
+                                                        num * sizeof(_jit_label_info_t));
+               if(!info)
                {
                        return 0;
                }
-               jit_memzero(blocks + builder->max_label_blocks,
-                           sizeof(jit_block_t) * (num - builder->max_label_blocks));
-               builder->label_blocks = blocks;
-               builder->max_label_blocks = num;
+
+               jit_memzero(info + builder->max_label_info,
+                           sizeof(_jit_label_info_t) * (num - builder->max_label_info));
+               builder->label_info = info;
+               builder->max_label_info = num;
        }
-       builder->label_blocks[block->label] = block;
+
+       builder->label_info[label].block = block;
+       builder->label_info[label].alias = block->label;
+       block->label = label;
+
        return 1;
 }
 
@@ -986,10 +967,33 @@ jit_block_get_label(jit_block_t block)
        {
                return block->label;
        }
-       else
+       return jit_label_undefined;
+}
+
+/*@
+ * @deftypefun jit_label_t jit_block_get_next_label (jit_block_t @var{block, jit_label_t @var{label}})
+ * Get the next label associated with a block.
+ * @end deftypefun
+@*/
+jit_label_t
+jit_block_get_next_label(jit_block_t block, jit_label_t label)
+{
+       jit_builder_t builder;
+       if(block)
        {
-               return jit_label_undefined;
+               if(label == jit_label_undefined)
+               {
+                       return block->label;
+               }
+               builder = block->func->builder;
+               if(builder
+                  && label < builder->max_label_info
+                  && block == builder->label_info[label].block)
+               {
+                       return builder->label_info[label].alias;
+               }
        }
+       return jit_label_undefined;
 }
 
 /*@
@@ -1049,9 +1053,9 @@ jit_block_previous(jit_function_t func, jit_block_t previous)
 jit_block_t
 jit_block_from_label(jit_function_t func, jit_label_t label)
 {
-       if(func && func->builder && label < func->builder->max_label_blocks)
+       if(func && func->builder && label < func->builder->max_label_info)
        {
-               return func->builder->label_blocks[label];
+               return func->builder->label_info[label].block;
        }
        else
        {
index c8c49320971f5a06bfbc6084028a86f3f522438a..c9b7935d4908086f0119f59d8a7be0e1e7681a13 100644 (file)
 #include <jit/jit-dump.h>
 #include <config.h>
 #ifdef HAVE_STDLIB_H
-       #include <stdlib.h>
+include <stdlib.h>
 #endif
 #ifdef HAVE_UNISTD_H
-       #include <unistd.h>
+include <unistd.h>
 #endif
 
 #if defined(JIT_BACKEND_INTERP)
-       #include "jit-interp.h"
+include "jit-interp.h"
 #endif
 
 /*@
@@ -56,16 +56,16 @@ void jit_dump_type(FILE *stream, jit_type_t type)
        }
        switch(type->kind)
        {
-               case JIT_TYPE_VOID:                     name = "void"; break;
+               case JIT_TYPE_VOID:             name = "void"; break;
                case JIT_TYPE_SBYTE:            name = "sbyte"; break;
                case JIT_TYPE_UBYTE:            name = "ubyte"; break;
                case JIT_TYPE_SHORT:            name = "short"; break;
                case JIT_TYPE_USHORT:           name = "ushort"; break;
-               case JIT_TYPE_INT:                      name = "int"; break;
-               case JIT_TYPE_UINT:                     name = "uint"; break;
-               case JIT_TYPE_NINT:                     name = "nint"; break;
+               case JIT_TYPE_INT:              name = "int"; break;
+               case JIT_TYPE_UINT:             name = "uint"; break;
+               case JIT_TYPE_NINT:             name = "nint"; break;
                case JIT_TYPE_NUINT:            name = "nuint"; break;
-               case JIT_TYPE_LONG:                     name = "long"; break;
+               case JIT_TYPE_LONG:             name = "long"; break;
                case JIT_TYPE_ULONG:            name = "ulong"; break;
                case JIT_TYPE_FLOAT32:          name = "float32"; break;
                case JIT_TYPE_FLOAT64:          name = "float64"; break;
@@ -74,7 +74,7 @@ void jit_dump_type(FILE *stream, jit_type_t type)
                case JIT_TYPE_STRUCT:
                {
                        fprintf(stream, "struct<%u>",
-                                       (unsigned int)(jit_type_get_size(type)));
+                               (unsigned int)(jit_type_get_size(type)));
                        return;
                }
                /* Not reached */
@@ -82,14 +82,14 @@ void jit_dump_type(FILE *stream, jit_type_t type)
                case JIT_TYPE_UNION:
                {
                        fprintf(stream, "union<%u>",
-                                       (unsigned int)(jit_type_get_size(type)));
+                               (unsigned int)(jit_type_get_size(type)));
                        return;
                }
                /* Not reached */
 
                case JIT_TYPE_SIGNATURE:        name = "signature"; break;
-               case JIT_TYPE_PTR:                      name = "ptr"; break;
-               default:                                        name = "<unknown-type>"; break;
+               case JIT_TYPE_PTR:              name = "ptr"; break;
+               default:                        name = "<unknown-type>"; break;
        }
        fputs(name, stream);
 }
@@ -763,11 +763,11 @@ void jit_dump_function(FILE *stream, jit_function_t func, const char *name)
        jit_block_t block;
        jit_insn_iter_t iter;
        jit_insn_t insn;
-       int prev_block;
        jit_type_t signature;
        unsigned int param;
        unsigned int num_params;
        jit_value_t value;
+       jit_label_t label;
 
        /* Bail out if we don't have sufficient information to dump */
        if(!stream || !func)
@@ -847,20 +847,30 @@ void jit_dump_function(FILE *stream, jit_function_t func, const char *name)
        {
                /* Output each of the three address blocks in turn */
                block = 0;
-               prev_block = 0;
                while((block = jit_block_next(func, block)) != 0)
                {
-                       /* Output the block's label, if it has one */
+                       /* Output the block's labels, if it has any */
+                       label = jit_block_get_label(block);
                        if(block->label != jit_label_undefined)
                        {
-                               fprintf(stream, ".L%ld:\n", (long)(block->label));
+                               for(;;)
+                               {
+                                       fprintf(stream, ".L%ld:", (long) label);
+                                       label = jit_block_get_next_label(block, label);
+                                       if(label == jit_label_undefined)
+                                       {
+                                               fprintf(stream, "\n");
+                                               break;
+                                       }
+                                       fprintf(stream, " ");
+                               }
                        }
-                       else if (prev_block && _jit_block_get_last(block) != 0)
+                       else if (block != func->builder->entry_block
+                                /*&& _jit_block_get_last(block) != 0*/)
                        {
                                /* A new block was started, but it doesn't have a label yet */
                                fprintf(stream, ".L:\n");
                        }
-                       prev_block = 1;
 
                        /* Dump the instructions in the block */
                        jit_insn_iter_init(&iter, block);
index fe423f5491fa9082e44f72bcea1dd530c1e6ea6b..b95195fade50031c9c7301889a50955ad80bff26 100644 (file)
@@ -212,8 +212,7 @@ int _jit_function_ensure_builder(jit_function_t func)
        func->builder->init_block = func->builder->current_block;
 
        /* Start first block for function body */
-       func->builder->current_block = _jit_block_create(func, 0);
-       if(!func->builder->current_block)
+       if(!jit_insn_new_block(func))
        {
                _jit_function_free_builder(func);
                return 0;
@@ -232,7 +231,7 @@ void _jit_function_free_builder(jit_function_t func)
                jit_memory_pool_free(&(func->builder->value_pool), _jit_value_free);
                jit_memory_pool_free(&(func->builder->meta_pool), _jit_meta_free_one);
                jit_free(func->builder->param_values);
-               jit_free(func->builder->label_blocks);
+               jit_free(func->builder->label_info);
                jit_free(func->builder);
                func->builder = 0;
        }
index cca465a319ac98ea36195fe95e32c38bb5bb65ab..0dcda9a059eaf7ad1d6bd022cb7de2efabadc36d 100644 (file)
@@ -1072,17 +1072,20 @@ int jit_insn_dest_is_value(jit_insn_t insn)
 
 /*@
  * @deftypefun void jit_insn_label (jit_function_t @var{func}, jit_label_t *@var{label})
- * Start a new block within the function @var{func} and give it the
- * specified @var{label}.  Returns zero if out of memory.
+ * Start a new basic block within the function @var{func} and give it the
+ * specified @var{label}.  If the call is made when a new block was just
+ * created by any previous call then that block is reused, no new block
+ * is created.  Returns zero if out of memory.
  *
  * If the contents of @var{label} are @code{jit_label_undefined}, then this
  * function will allocate a new label for this block.  Otherwise it will
  * reuse the specified label from a previous branch instruction.
  * @end deftypefun
 @*/
-int jit_insn_label(jit_function_t func, jit_label_t *label)
+int
+jit_insn_label(jit_function_t func, jit_label_t *label)
 {
-       jit_block_t current;
+       jit_block_t block;
 
        if(!_jit_function_ensure_builder(func))
        {
@@ -1093,33 +1096,36 @@ int jit_insn_label(jit_function_t func, jit_label_t *label)
                return 0;
        }
 
-       current = func->builder->current_block;
-       if(current->label == jit_label_undefined && !_jit_block_get_last(current))
+       /* Create a new block if the current one is not empty */
+       block = func->builder->current_block;
+       if(_jit_block_get_last(block))
        {
-               /* We just started a new block after a branch instruction,
-                  so don't bother creating another new block */
-               if(*label == jit_label_undefined)
-               {
-                       *label = (func->builder->next_label)++;
-               }
-               current->label = *label;
-               if(!_jit_block_record_label(current))
+               block = _jit_block_create(func);
+               if(!block)
                {
                        return 0;
                }
        }
-       else
+
+       /* Record the label */
+       if(*label == jit_label_undefined)
        {
-               /* Create a new block */
-               jit_block_t block = _jit_block_create(func, label);
-               if(!block)
-               {
-                       return 0;
-               }
+               *label = (func->builder->next_label)++;
+       }
+       if(!_jit_block_record_label(block, *label))
+       {
+               _jit_block_destroy(block);
+               return 0;
+       }
 
-               /* Set the new block as the current one */
+       /* If the block is newly created then insert it to the end of
+          the function's block list */
+       if(block != func->builder->current_block)
+       {
+               _jit_block_attach_before(func->builder->exit_block, block, block);
                func->builder->current_block = block;
        }
+
        return 1;
 }
 
@@ -1128,14 +1134,22 @@ int jit_insn_label(jit_function_t func, jit_label_t *label)
  * Start a new basic block, without giving it an explicit label.
  * @end deftypefun
 @*/
-int jit_insn_new_block(jit_function_t func)
+int
+jit_insn_new_block(jit_function_t func)
 {
-       jit_block_t block = _jit_block_create(func, 0);
+       jit_block_t block;
+
+       /* Create a new block */
+       block = _jit_block_create(func);
        if(!block)
        {
                return 0;
        }
+
+       /* Insert the block to the end of the function's block list */
+       _jit_block_attach_before(func->builder->exit_block, block, block);
        func->builder->current_block = block;
+
        return 1;
 }
 
index 7e7f951a9fea638f5c3cbe0ed5298b6b831cc473..e785e0b906fa59ae00bc512900e6411c3c3a7b33 100644 (file)
@@ -313,6 +313,22 @@ struct _jit_insn
 #define        JIT_INSN_VALUE2_OTHER_FLAGS     0x0800
 #define        JIT_INSN_DEST_IS_VALUE          0x1000
 
+/*
+ * Information about each label associated with a function.
+ *
+ * Multiple labels may belong to the same basic block. Such labels are
+ * linked into list.
+ */
+typedef struct _jit_label_info _jit_label_info_t;
+struct _jit_label_info
+{
+       /* Block the label assigned to */
+       jit_block_t             block;
+
+       /* Next label that might belong to the same block */
+       jit_label_t             alias;
+};
+
 /*
  * Information that is associated with a function for building
  * the instructions and values.  This structure can be discarded
@@ -344,8 +360,8 @@ struct _jit_builder
        jit_label_t             next_label;
 
        /* Mapping from label numbers to blocks */
-       jit_block_t             *label_blocks;
-       jit_label_t             max_label_blocks;
+       _jit_label_info_t       *label_info;
+       jit_label_t             max_label_info;
 
        /* Exception handling definitions for the function */
        jit_value_t             setjmp_value;
@@ -600,7 +616,12 @@ int _jit_block_compute_postorder(jit_function_t func);
 /*
  * Create a new block and associate it with a function.
  */
-jit_block_t _jit_block_create(jit_function_t func, jit_label_t *label);
+jit_block_t _jit_block_create(jit_function_t func);
+
+/*
+ * Destroy a block.
+ */
+void _jit_block_destroy(jit_block_t block);
 
 /*
  * Detach blocks from their current position in a function.
@@ -620,7 +641,7 @@ void _jit_block_attach_before(jit_block_t block, jit_block_t first, jit_block_t
 /*
  * Record the label mapping for a block.
  */
-int _jit_block_record_label(jit_block_t block);
+int _jit_block_record_label(jit_block_t block, jit_label_t label);
 
 /*
  * Add an instruction to a block.