This fixes the performance issue in liveness analysis. Signed-off-by: Vegard Nossum <vegard.nos...@gmail.com> --- include/jit/compilation-unit.h | 7 +++++- include/jit/vars.h | 3 -- jit/compilation-unit.c | 21 +++++++++++++++-- jit/interval.c | 25 +-------------------- jit/liveness.c | 40 ---------------------------------- jit/spill-reload.c | 30 ++++++++++++-------------- test/jit/Makefile | 1 - test/jit/interval-test.c | 46 ---------------------------------------- test/jit/liveness-test.c | 32 ++++++++++++++++++--------- 9 files changed, 60 insertions(+), 145 deletions(-) delete mode 100644 test/jit/interval-test.c
diff --git a/include/jit/compilation-unit.h b/include/jit/compilation-unit.h index 61ea66b..37178c1 100644 --- a/include/jit/compilation-unit.h +++ b/include/jit/compilation-unit.h @@ -3,8 +3,8 @@ #include "arch/registers.h" #include "jit/basic-block.h" - #include "lib/list.h" +#include "lib/radix-tree.h" #include "vm/stack.h" #include "vm/static.h" #include "vm/types.h" @@ -72,6 +72,11 @@ struct compilation_unit { * inside JIT code. */ unsigned long *bc_offset_map; + + /* + * This maps LIR offset to instruction. + */ + struct radix_tree *lir_insn_map; }; struct compilation_unit *compilation_unit_alloc(struct vm_method *); diff --git a/include/jit/vars.h b/include/jit/vars.h index e0e7bed..07aa6be 100644 --- a/include/jit/vars.h +++ b/include/jit/vars.h @@ -81,9 +81,6 @@ struct live_interval { linear scan. */ struct list_head interval_node; - /* Array of instructions within this interval. */ - struct insn **insn_array; - /* Do we need to spill the register of this interval? */ bool need_spill; diff --git a/jit/compilation-unit.c b/jit/compilation-unit.c index 9a207ac..e8a044b 100644 --- a/jit/compilation-unit.c +++ b/jit/compilation-unit.c @@ -109,6 +109,8 @@ struct compilation_unit *compilation_unit_alloc(struct vm_method *method) cu->fixed_var_infos[i] = ret; } + + cu->lir_insn_map = NULL; } return cu; @@ -136,8 +138,7 @@ static void free_var_infos(struct var_info *var_infos) static void free_bc_offset_map(unsigned long *map) { - if (map) - free(map); + free(map); } static void free_tableswitch_list(struct compilation_unit *cu) @@ -150,6 +151,11 @@ static void free_tableswitch_list(struct compilation_unit *cu) } } +static void free_lir_insn_map(struct compilation_unit *cu) +{ + free_radix_tree(cu->lir_insn_map); +} + void free_compilation_unit(struct compilation_unit *cu) { struct basic_block *bb, *tmp_bb; @@ -165,6 +171,7 @@ void free_compilation_unit(struct compilation_unit *cu) free_stack_frame(cu->stack_frame); free_bc_offset_map(cu->bc_offset_map); free_tableswitch_list(cu); + free_lir_insn_map(cu); free(cu); } @@ -219,11 +226,19 @@ void compute_insn_positions(struct compilation_unit *cu) struct basic_block *bb; unsigned long pos = 0; + cu->lir_insn_map = alloc_radix_tree(8, 8 * sizeof(pos)); + if (!cu->lir_insn_map) + die("oom"); + for_each_basic_block(bb, &cu->bb_list) { struct insn *insn; for_each_insn(insn, &bb->insn_list) { - insn->lir_pos = pos++; + insn->lir_pos = pos; + + radix_tree_insert(cu->lir_insn_map, pos, insn); + + ++pos; } } } diff --git a/jit/interval.c b/jit/interval.c index ccdc84e..8a7620f 100644 --- a/jit/interval.c +++ b/jit/interval.c @@ -56,33 +56,14 @@ void free_interval(struct live_interval *interval) if (interval->next_child) free_interval(interval->next_child); - free(interval->insn_array); free(interval); } -static int split_insn_array(struct live_interval *src, struct live_interval *dst) -{ - unsigned long src_len, dst_len, size; - - src_len = range_len(&src->range); - dst_len = range_len(&dst->range); - - size = dst_len * sizeof(struct insn *); - dst->insn_array = zalloc(size); - if (!dst->insn_array) - return warn("out of memory"), -ENOMEM; - - memcpy(dst->insn_array, src->insn_array + src_len, size); - - return 0; -} - struct live_interval *split_interval_at(struct live_interval *interval, unsigned long pos) { struct use_position *this, *next; struct live_interval *new; - int err; new = alloc_interval(interval->var_info); if (!new) @@ -100,11 +81,7 @@ struct live_interval *split_interval_at(struct live_interval *interval, list_move(&this->use_pos_list, &new->use_positions); this->interval = new; } - err = split_insn_array(interval, new); - if (err) { - free_interval(new); - return NULL; - } + new->next_child = interval->next_child; new->prev_child = interval; interval->next_child = new; diff --git a/jit/liveness.c b/jit/liveness.c index 8ffb1cb..619a988 100644 --- a/jit/liveness.c +++ b/jit/liveness.c @@ -36,45 +36,6 @@ #include <errno.h> #include <stdlib.h> -static void __update_interval_insn(struct live_interval *interval, - struct basic_block *bb) -{ - struct insn *insn; - - for_each_insn(insn, &bb->insn_list) { - unsigned long offset; - - if (!in_range(&interval->range, insn->lir_pos)) - continue; - - offset = insn->lir_pos - interval->range.start; - interval->insn_array[offset] = insn; - } -} - -static int update_interval_insns(struct compilation_unit *cu) -{ - struct var_info *var; - int err = 0; - - for_each_variable(var, cu->var_infos) { - struct live_interval *interval = var->interval; - struct basic_block *bb; - unsigned long nr; - - nr = range_len(&interval->range); - interval->insn_array = calloc(nr, sizeof(struct insn *)); - if (!interval->insn_array) { - err = -ENOMEM; - break; - } - for_each_basic_block(bb, &cu->bb_list) { - __update_interval_insn(var->interval, bb); - } - } - return err; -} - static void __update_live_range(struct live_range *range, unsigned long pos) { if (range->start > pos) @@ -272,7 +233,6 @@ int analyze_liveness(struct compilation_unit *cu) update_live_ranges(cu); - err = update_interval_insns(cu); out: return err; } diff --git a/jit/spill-reload.c b/jit/spill-reload.c index 1d6e774..9ce571f 100644 --- a/jit/spill-reload.c +++ b/jit/spill-reload.c @@ -43,13 +43,21 @@ struct live_interval_mapping { struct live_interval *from, *to; }; -static struct insn *last_insn(struct live_interval *interval) +static struct insn *first_insn(struct compilation_unit *cu, struct live_interval *interval) { - unsigned long end; struct insn *ret; - end = range_len(&interval->range) - 1; - ret = interval->insn_array[end]; + ret = radix_tree_lookup(cu->lir_insn_map, interval->range.start); + assert(ret != NULL); + + return ret; +} + +static struct insn *last_insn(struct compilation_unit *cu, struct live_interval *interval) +{ + struct insn *ret; + + ret = radix_tree_lookup(cu->lir_insn_map, interval->range.end - 1); assert(ret != NULL); return ret; @@ -84,7 +92,7 @@ spill_interval(struct live_interval *interval, static int insert_spill_insn(struct live_interval *interval, struct compilation_unit *cu) { - interval->spill_slot = spill_interval(interval, cu, last_insn(interval), false); + interval->spill_slot = spill_interval(interval, cu, last_insn(cu, interval), false); if (!interval->spill_slot) return warn("out of memory"), -ENOMEM; @@ -92,16 +100,6 @@ insert_spill_insn(struct live_interval *interval, struct compilation_unit *cu) return 0; } -static struct insn *first_insn(struct live_interval *interval) -{ - struct insn *ret; - - ret = interval->insn_array[0]; - assert(ret != NULL); - - return ret; -} - static int insert_reload_insn(struct live_interval *interval, struct compilation_unit *cu, struct stack_slot *from, @@ -159,7 +157,7 @@ static int __insert_spill_reload_insn(struct live_interval *interval, struct com if (interval->need_reload) { err = insert_reload_insn(interval, cu, interval->spill_parent->spill_slot, - first_insn(interval)); + first_insn(cu, interval)); if (err) goto out; } diff --git a/test/jit/Makefile b/test/jit/Makefile index 5c26268..f669c08 100644 --- a/test/jit/Makefile +++ b/test/jit/Makefile @@ -82,7 +82,6 @@ TEST_OBJS := \ cfg-analyzer-test.o \ compilation-unit-test.o \ expression-test.o \ - interval-test.o \ invoke-bc-test.o \ linear-scan-test.o \ live-range-test.o \ diff --git a/test/jit/interval-test.c b/test/jit/interval-test.c deleted file mode 100644 index 23db794..0000000 --- a/test/jit/interval-test.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2008 Pekka Enberg - */ -#include "arch/instruction.h" -#include "jit/vars.h" -#include <libharness.h> -#include <stdlib.h> - -void test_split_interval_at(void) -{ - struct live_interval *new_interval; - struct insn insns[2]; - struct var_info var; - unsigned int i; - - var.interval = alloc_interval(&var); - var.interval->insn_array = calloc(ARRAY_SIZE(insns), sizeof(struct insn *)); - - for (i = 0; i < ARRAY_SIZE(insns); i++) { - struct insn *insn = &insns[i]; - - insn->lir_pos = i; - register_set_insn(&insn->x.reg, insn); - insert_register_to_interval(var.interval, &insn->x.reg); - var.interval->insn_array[i] = insn; - } - var.interval->range.start = 0; - var.interval->range.end = ARRAY_SIZE(insns); - - assert_ptr_equals(var.interval, insns[0].x.reg.interval); - assert_ptr_equals(var.interval, insns[1].x.reg.interval); - - new_interval = split_interval_at(var.interval, 1); - - assert_ptr_equals(var.interval, insns[0].x.reg.interval); - assert_int_equals(0, var.interval->range.start); - assert_int_equals(1, var.interval->range.end); - assert_ptr_equals(&insns[0], var.interval->insn_array[0]); - - assert_ptr_equals(new_interval, insns[1].x.reg.interval); - assert_int_equals(1, new_interval->range.start); - assert_int_equals(2, new_interval->range.end); - assert_ptr_equals(&insns[1], new_interval->insn_array[0]); - - free_interval(var.interval); -} diff --git a/test/jit/liveness-test.c b/test/jit/liveness-test.c index f154206..10bfb72 100644 --- a/test/jit/liveness-test.c +++ b/test/jit/liveness-test.c @@ -31,6 +31,16 @@ static void assert_defines(struct basic_block *bb, struct var_info *var) assert_false(test_bit(bb->use_set->bits, var->vreg)); } +static void assert_insn_at_equals(struct insn *insn, struct compilation_unit *cu, struct live_interval *interval, unsigned int offset) +{ + struct insn *insn2; + + insn2 = radix_tree_lookup(cu->lir_insn_map, + interval->range.start + offset); + + assert_ptr_equals(insn, insn2); +} + void test_variable_range_limited_to_basic_block(void) { struct compilation_unit *cu; @@ -62,12 +72,12 @@ void test_variable_range_limited_to_basic_block(void) assert_live_range(r1->interval, 0, 3); assert_live_range(r2->interval, 1, 3); - assert_ptr_equals(insn[0], r1->interval->insn_array[0]); - assert_ptr_equals(insn[1], r1->interval->insn_array[1]); - assert_ptr_equals(insn[2], r1->interval->insn_array[2]); + assert_insn_at_equals(insn[0], cu, r1->interval, 0); + assert_insn_at_equals(insn[1], cu, r1->interval, 1); + assert_insn_at_equals(insn[2], cu, r1->interval, 2); - assert_ptr_equals(insn[1], r2->interval->insn_array[0]); - assert_ptr_equals(insn[2], r2->interval->insn_array[1]); + assert_insn_at_equals(insn[1], cu, r2->interval, 0); + assert_insn_at_equals(insn[2], cu, r2->interval, 1); free_compilation_unit(cu); } @@ -109,13 +119,13 @@ void test_variable_range_spans_two_basic_blocks(void) assert_live_range(r1->interval, 0, 4); assert_live_range(r2->interval, 2, 4); - assert_ptr_equals(insn[0], r1->interval->insn_array[0]); - assert_ptr_equals(insn[1], r1->interval->insn_array[1]); - assert_ptr_equals(insn[2], r1->interval->insn_array[2]); - assert_ptr_equals(insn[3], r1->interval->insn_array[3]); + assert_insn_at_equals(insn[0], cu, r1->interval, 0); + assert_insn_at_equals(insn[1], cu, r1->interval, 1); + assert_insn_at_equals(insn[2], cu, r1->interval, 2); + assert_insn_at_equals(insn[3], cu, r1->interval, 3); - assert_ptr_equals(insn[2], r2->interval->insn_array[0]); - assert_ptr_equals(insn[3], r2->interval->insn_array[1]); + assert_insn_at_equals(insn[2], cu, r2->interval, 0); + assert_insn_at_equals(insn[3], cu, r2->interval, 1); free_compilation_unit(cu); } -- 1.6.0.4 ------------------------------------------------------------------------------ Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day trial. Simplify your report design, integration and deployment - and focus on what you do best, core application coding. Discover what's new with Crystal Reports now. http://p.sf.net/sfu/bobj-july _______________________________________________ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel