This fixes bug encountered when compiling Substring(). --- include/jit/vars.h | 5 ++- jit/interval.c | 33 +++++++++++++++ jit/linear-scan.c | 1 + jit/spill-reload.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 141 insertions(+), 11 deletions(-)
diff --git a/include/jit/vars.h b/include/jit/vars.h index 482f10a..1821bb3 100644 --- a/include/jit/vars.h +++ b/include/jit/vars.h @@ -4,6 +4,8 @@ #include "lib/list.h" #include "arch/registers.h" #include "vm/types.h" +#include "compilation-unit.h" + #include <stdbool.h> #include <assert.h> @@ -111,5 +113,6 @@ struct live_interval *alloc_interval(struct var_info *); void free_interval(struct live_interval *); struct live_interval *split_interval_at(struct live_interval *, unsigned long pos); unsigned long next_use_pos(struct live_interval *, unsigned long); - +struct live_interval *vreg_start_interval(struct compilation_unit *, unsigned long); +struct live_interval *interval_child_at(struct live_interval *, unsigned long); #endif /* __JIT_VARS_H */ diff --git a/jit/interval.c b/jit/interval.c index e450b94..03da977 100644 --- a/jit/interval.c +++ b/jit/interval.c @@ -121,3 +121,36 @@ unsigned long next_use_pos(struct live_interval *it, unsigned long pos) return min; } + +struct live_interval *vreg_start_interval(struct compilation_unit *cu, unsigned long vreg) +{ + struct var_info *var; + + var = cu->var_infos; + + while (var) { + if (var->vreg == vreg) + break; + + var = var->next; + } + + if (var == NULL) + return NULL; + + return var->interval; +} + +struct live_interval *interval_child_at(struct live_interval *parent, unsigned long pos) +{ + struct live_interval *it = parent; + + while (it) { + if (in_range(&it->range, pos)) + return it; + + it = it->next_child; + } + + return NULL; +} diff --git a/jit/linear-scan.c b/jit/linear-scan.c index ca3053b..cceb145 100644 --- a/jit/linear-scan.c +++ b/jit/linear-scan.c @@ -381,6 +381,7 @@ int allocate_registers(struct compilation_unit *cu) if (current->reg != REG_UNASSIGNED) list_add(¤t->interval_node, &active); } + free(registers); return 0; diff --git a/jit/spill-reload.c b/jit/spill-reload.c index 94d2af7..4d1c409 100644 --- a/jit/spill-reload.c +++ b/jit/spill-reload.c @@ -30,8 +30,17 @@ #include "arch/instruction.h" +#include "lib/bitset.h" + #include <errno.h> +#include <stdio.h> +#include <string.h> + +struct live_interval_mapping { + struct live_interval *from, *to; +}; + static struct insn *last_insn(struct live_interval *interval) { unsigned long end; @@ -44,13 +53,12 @@ static struct insn *last_insn(struct live_interval *interval) return ret; } -static int insert_spill_insn(struct live_interval *interval, struct compilation_unit *cu) +static struct stack_slot *spill_interval(struct live_interval *interval, struct compilation_unit *cu) { - struct insn *last = last_insn(interval); struct stack_slot *slot; struct var_info *reg; struct insn *spill; - + struct insn *last = last_insn(interval); /* * We've already done register allocation, so use fixed registers for * spilling and reloading. @@ -59,18 +67,26 @@ static int insert_spill_insn(struct live_interval *interval, struct compilation_ slot = get_spill_slot_32(cu->stack_frame); if (!slot) - return -ENOMEM; + return NULL; spill = spill_insn(reg, slot); if (!spill) - return -ENOMEM; - - interval->spill_slot = slot; + return NULL; spill->bytecode_offset = last->bytecode_offset; list_add(&spill->insn_list_node, &last->insn_list_node); + return slot; +} + +static int insert_spill_insn(struct live_interval *interval, struct compilation_unit *cu) +{ + interval->spill_slot = spill_interval(interval, cu); + + if (!interval->spill_slot) + return -ENOMEM; + return 0; } @@ -84,14 +100,14 @@ static struct insn *first_insn(struct live_interval *interval) return ret; } -static int insert_reload_insn(struct live_interval *interval, struct compilation_unit *cu) +static int insert_reload_insn(struct live_interval *interval, struct compilation_unit *cu, struct stack_slot *from) { struct insn *first = first_insn(interval); struct insn *reload; struct var_info *reg; reg = get_fixed_var(cu, interval->reg); - reload = reload_insn(interval->spill_parent->spill_slot, reg); + reload = reload_insn(from, reg); if (!reload) return -ENOMEM; @@ -110,7 +126,7 @@ static int __insert_spill_reload_insn(struct live_interval *interval, struct com goto out; if (interval->need_reload) { - err = insert_reload_insn(interval, cu); + err = insert_reload_insn(interval, cu, interval->spill_parent->spill_slot); if (err) goto out; } @@ -124,6 +140,79 @@ out: return err; } +static void maybe_add_mov_for_vreg(struct compilation_unit *cu, struct basic_block *from, struct basic_block *to, unsigned long vreg, struct live_interval_mapping *mappings, int *nrmapped) +{ + struct live_interval *parent_it; + struct live_interval *from_it, *to_it; + + parent_it = vreg_start_interval(cu, vreg); + from_it = interval_child_at(parent_it, from->end); + to_it = interval_child_at(parent_it, to->start); + + /* We seem to have some vregs that are alive at the beginning of a bb, + * but have no interval covering them. In that case, no mov is to be inserted. + */ + if (!from_it || !to_it) + return; + + if (from_it != to_it) { + printf("vreg %lu at position %lu is not in the same interval...\n", vreg, from->end); + mappings[*nrmapped].from = from_it; + mappings[*nrmapped].to = to_it; + (*nrmapped)++; + } +} + +static void insert_mov_insns(struct compilation_unit *cu, struct live_interval_mapping *mappings, int nrmapped) +{ + int i; + struct stack_slot *slots[nrmapped]; + + /* Spill all intervals that have to be resolved */ + for (i = 0; i < nrmapped; i++) { + printf("mapping it %#x to it %#x\n", (unsigned int)mappings[i].from, (unsigned int)mappings[i].to); + if (mappings[i].from->need_spill) + slots[i] = mappings[i].from->spill_slot; + else + slots[i] = spill_interval(mappings[i].from, cu); + + /* Reload those intervals into their new location */ + if (mappings[i].to->need_reload) { + NOT_IMPLEMENTED; + } else { + insert_reload_insn(mappings[i].from, cu, slots[i]); + } + } +} + +static void resolve_data_flow(struct compilation_unit *cu) +{ + struct basic_block *this, *succ; + unsigned int isucc; + unsigned long vreg; + + /* This implements the algorithm ResolveDataFlow described by + * Christian Wimmer in 2004 */ + for_each_basic_block(this, &cu->bb_list) { + for (isucc = 0; isucc < this->nr_successors; isucc++) { + struct live_interval_mapping mappings[this->nr_predecessors]; + int nrmapped = 0; + + memset(mappings, 0, this->nr_predecessors * sizeof(struct live_interval_mapping)); + + succ = this->successors[isucc]; + + for (vreg = 0; vreg < cu->nr_vregs; vreg++) { + if (test_bit(succ->live_in_set->bits, vreg)) { + maybe_add_mov_for_vreg(cu, this, succ, vreg, mappings, &nrmapped); + } + } + + insert_mov_insns(cu, mappings, nrmapped); + } + } +} + int insert_spill_reload_insns(struct compilation_unit *cu) { struct var_info *var; @@ -138,5 +227,9 @@ int insert_spill_reload_insns(struct compilation_unit *cu) break; } } + + /* Make sure intervals spilled across basic block boundaries will + * be reloaded correctly */ + resolve_data_flow(cu); return err; } -- 1.5.6.3 ------------------------------------------------------------------------------ Enter the BlackBerry Developer Challenge This is your chance to win up to $100,000 in prizes! For a limited time, vendors submitting new applications to BlackBerry App World(TM) will have the opportunity to enter the BlackBerry Developer Challenge. See full prize details at: http://p.sf.net/sfu/Challenge _______________________________________________ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel