From: Aleksey Demakov Date: Sat, 9 May 2009 21:54:31 +0000 (+0000) Subject: allow multiple labels for single block X-Git-Tag: before.move.to.git~4 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=551af48b566827746b2cb3086e1000076abd6149;p=francis%2Flibjit.git allow multiple labels for single block --- diff --git a/ChangeLog b/ChangeLog index ceaad70..fc86490 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2009-05-10 Aleksey Demakov + + * 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 * jit/jit-internal.h, jit/jit-block.c, jit/jit-insn.c, diff --git a/include/jit/jit-block.h b/include/jit/jit-block.h index eda9f02..65fb092 100644 --- a/include/jit/jit-block.h +++ b/include/jit/jit-block.h @@ -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; diff --git a/jit/jit-block.c b/jit/jit-block.c index 0f35f56..2bfe7b6 100644 --- a/jit/jit-block.c +++ b/jit/jit-block.c @@ -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 { diff --git a/jit/jit-dump.c b/jit/jit-dump.c index c8c4932..c9b7935 100644 --- a/jit/jit-dump.c +++ b/jit/jit-dump.c @@ -25,14 +25,14 @@ #include #include #ifdef HAVE_STDLIB_H - #include +# include #endif #ifdef HAVE_UNISTD_H - #include +# include #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 = ""; break; + case JIT_TYPE_PTR: name = "ptr"; break; + default: name = ""; 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); diff --git a/jit/jit-function.c b/jit/jit-function.c index fe423f5..b95195f 100644 --- a/jit/jit-function.c +++ b/jit/jit-function.c @@ -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; } diff --git a/jit/jit-insn.c b/jit/jit-insn.c index cca465a..0dcda9a 100644 --- a/jit/jit-insn.c +++ b/jit/jit-insn.c @@ -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; } diff --git a/jit/jit-internal.h b/jit/jit-internal.h index 7e7f951..e785e0b 100644 --- a/jit/jit-internal.h +++ b/jit/jit-internal.h @@ -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.