From: christian Date: Tue, 15 May 2007 09:55:17 +0000 (+0000) Subject: * src/vm/jit/codegen-common.c: (codegen_emit_phi_moves): Added. (Former X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=979e524c8d5430ff170cfadb40930bdedba6d4bf;p=cacao.git * src/vm/jit/codegen-common.c: (codegen_emit_phi_moves): Added. (Former codegen_insert_phi_moves from codegen.c) * src/vm/jit/codegen-common.h: Function prototype for codegen_emit_phi_moves added. * src/vm/jit/optimizing/lsra.c: Adapted to new instruction format and unified variables. * src/vm/jit/optimizing/lsra.h: Likewise. * src/vm/jit/optimizing/ssa.c: Likewise. * src/vm/jit/optimizing/ssa.h: Likewise. * src/vm/jit/optimizing/graph.c: Likewise. * src/vm/jit/optimizing/graph.h: Likewise. * src/vm/jit/optimizing/dominators.c: Likewise. * src/vm/jit/optimizing/lifetimes.c: Likewise and changed lifetime anaylsis to a worklist algorithmus. * src/vm/jit/optimizing/lifetimes.h: Likewise. * src/vm/jit/i386/codegen.c: (codegen_insert_phi_moves): Moved to src/vm/jit/codegen-common.c codegen_emit_phi_moves (codegen_emit): Necessary Adaptions for SSA. * src/toolbox/worklist.c: (wl_reset): Added. * src/toolbox/worklist.h: Function Prototype for wl_reset added. * src/vm/jit/stack.c: Removed old SSA specific code. --- diff --git a/src/toolbox/worklist.c b/src/toolbox/worklist.c index 5c5d8de08..1e3ae2c75 100644 --- a/src/toolbox/worklist.c +++ b/src/toolbox/worklist.c @@ -112,6 +112,17 @@ bool wl_is_empty(worklist *w) { return (w->W_top == 0); } +/******************************************************************************* +wl_reset + +Empties the worklist. + +IN: worklist *w pointer to worklist created with wl_new +*******************************************************************************/ +void wl_reset(worklist *w, int size) { + w->W_top = 0; + bv_reset(w->W_bv, size); +} /* * These are local overrides for various environment variables in Emacs. diff --git a/src/toolbox/worklist.h b/src/toolbox/worklist.h index 9ec5a3c47..d8d5be07b 100644 --- a/src/toolbox/worklist.h +++ b/src/toolbox/worklist.h @@ -73,6 +73,7 @@ worklist *wl_new(int size); void wl_add(worklist *w, int element); int wl_get(worklist *w); bool wl_is_empty(worklist *w); +void wl_reset(worklist *w, int size); #endif /* _BITVECTOR_H */ diff --git a/src/vm/jit/codegen-common.c b/src/vm/jit/codegen-common.c index f7b44053e..cf9bb1667 100644 --- a/src/vm/jit/codegen-common.c +++ b/src/vm/jit/codegen-common.c @@ -39,7 +39,7 @@ memory. All functions writing values into the data area return the offset relative the begin of the code area (start of procedure). - $Id: codegen-common.c 7864 2007-05-03 21:17:26Z twisti $ + $Id: codegen-common.c 7908 2007-05-15 09:55:17Z christian $ */ @@ -88,6 +88,10 @@ #include "vm/jit/jit.h" #include "vm/jit/md.h" #include "vm/jit/replace.h" +#if defined(ENABLE_SSA) +# include "vm/jit/optimizing/lsra.h" +# include "vm/jit/optimizing/ssa.h" +#endif #include "vm/jit/stacktrace.h" #if defined(ENABLE_INTRP) @@ -1546,6 +1550,97 @@ s4 codegen_reg_of_dst(jitdata *jd, instruction *iptr, s4 tempregnum) } +/* codegen_emit_phi_moves **************************************************** + + Emits phi moves at the end of the basicblock. + +*******************************************************************************/ + +#if defined(ENABLE_SSA) +void codegen_emit_phi_moves(jitdata *jd, basicblock *bptr) +{ + int lt_d,lt_s,i; + lsradata *ls; + codegendata *cd; + varinfo *s, *d; + instruction tmp_i; + + cd = jd->cd; + ls = jd->ls; + + MCODECHECK(512); + + /* Moves from phi functions with highest indices have to be */ + /* inserted first, since this is the order as is used for */ + /* conflict resolution */ + + for(i = ls->num_phi_moves[bptr->nr] - 1; i >= 0 ; i--) { + lt_d = ls->phi_moves[bptr->nr][i][0]; + lt_s = ls->phi_moves[bptr->nr][i][1]; +#if defined(SSA_DEBUG_VERBOSE) + if (compileverbose) + printf("BB %3i Move %3i <- %3i ", bptr->nr, lt_d, lt_s); +#endif + if (lt_s == UNUSED) { +#if defined(SSA_DEBUG_VERBOSE) + if (compileverbose) + printf(" ... not processed \n"); +#endif + continue; + } + + d = VAR(ls->lifetime[lt_d].v_index); + s = VAR(ls->lifetime[lt_s].v_index); + + + if (d->type == -1) { +#if defined(SSA_DEBUG_VERBOSE) + if (compileverbose) + printf("...returning - phi lifetimes where joined\n"); +#endif + return; + } + + if (s->type == -1) { +#if defined(SSA_DEBUG_VERBOSE) + if (compileverbose) + printf("...returning - phi lifetimes where joined\n"); +#endif + return; + } + + tmp_i.opc = 0; + tmp_i.s1.varindex = ls->lifetime[lt_s].v_index; + tmp_i.dst.varindex = ls->lifetime[lt_d].v_index; + emit_copy(jd, &tmp_i); + +#if defined(SSA_DEBUG_VERBOSE) + if (compileverbose) { + if (IS_INMEMORY(d->flags) && IS_INMEMORY(s->flags)) { + /* mem -> mem */ + printf("M%3i <- M%3i",d->vv.regoff,s->vv.regoff); + } + else if (IS_INMEMORY(s->flags)) { + /* mem -> reg */ + printf("R%3i <- M%3i",d->vv.regoff,s->vv.regoff); + } + else if (IS_INMEMORY(d->flags)) { + /* reg -> mem */ + printf("M%3i <- R%3i",d->vv.regoff,s->vv.regoff); + } + else { + /* reg -> reg */ + printf("R%3i <- R%3i",d->vv.regoff,s->vv.regoff); + } + printf("\n"); + } +#endif /* defined(SSA_DEBUG_VERBOSE) */ + } +} +#endif /* defined(ENABLE_SSA) */ + + + /* * These are local overrides for various environment variables in Emacs. * Please do not remove this and leave it at the end of the file, where diff --git a/src/vm/jit/codegen-common.h b/src/vm/jit/codegen-common.h index 2466a4574..c6194a63e 100644 --- a/src/vm/jit/codegen-common.h +++ b/src/vm/jit/codegen-common.h @@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - $Id: codegen-common.h 7864 2007-05-03 21:17:26Z twisti $ + $Id: codegen-common.h 7908 2007-05-15 09:55:17Z christian $ */ @@ -347,6 +347,11 @@ void codegen_critical_section_end(codegendata *cd); /* machine dependent functions */ u1 *md_codegen_get_pv_from_pc(u1 *ra); + +#if defined(ENABLE_SSA) +void codegen_emit_phi_moves(jitdata *jd, basicblock *bptr); +#endif + #endif /* _CODEGEN_COMMON_H */ diff --git a/src/vm/jit/i386/codegen.c b/src/vm/jit/i386/codegen.c index 44457f118..e3fab11a1 100644 --- a/src/vm/jit/i386/codegen.c +++ b/src/vm/jit/i386/codegen.c @@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - $Id: codegen.c 7865 2007-05-03 21:29:40Z twisti $ + $Id: codegen.c 7908 2007-05-15 09:55:17Z christian $ */ @@ -80,12 +80,6 @@ *******************************************************************************/ -#if defined(ENABLE_SSA) -void cg_move(codegendata *cd, s4 type, s4 src_regoff, s4 src_flags, - s4 dst_regoff, s4 dst_flags); -void codegen_insert_phi_moves(jitdata *jd, basicblock *bptr); -#endif - bool codegen_emit(jitdata *jd) { methodinfo *m; @@ -236,12 +230,15 @@ bool codegen_emit(jitdata *jd) for (p = 0, l = 0; p < md->paramcount; p++) { t = md->paramtypes[p].type; + varindex = jd->local_map[l * 5 + t]; #if defined(ENABLE_SSA) if ( ls != NULL ) { - l = ls->local_0[p]; + if (varindex != UNUSED) + varindex = ls->var_0[varindex]; + if ((varindex != UNUSED) && (ls->lifetime[varindex].type == UNUSED)) + varindex = UNUSED; } #endif - varindex = jd->local_map[l * 5 + t]; l++; if (IS_2_WORD_TYPE(t)) /* increment local counter for 2 word types */ l++; @@ -395,9 +392,9 @@ bool codegen_emit(jitdata *jd) } #if defined(ENABLE_SSA) - /* with SSA Header is Basic Block 0 - insert phi Moves if necessary */ + /* with SSA the Header is Basic Block 0 - insert phi Moves if necessary */ if ( ls != NULL) - codegen_insert_phi_moves(jd, ls->basicblocks[0]); + codegen_emit_phi_moves(jd, ls->basicblocks[0]); #endif /* end of header generation */ @@ -2486,9 +2483,11 @@ bool codegen_emit(jitdata *jd) #if defined(ENABLE_SSA) if ( ls != NULL ) { last_cmd_was_goto = true; + /* In case of a Goto phimoves have to be inserted before the */ /* jump */ - codegen_insert_phi_moves(jd, bptr); + + codegen_emit_phi_moves(jd, bptr); } #endif emit_br(cd, iptr->dst.block); @@ -3071,8 +3070,8 @@ gen_method: if (d != TYPE_VOID) { #if defined(ENABLE_SSA) - if ((ls == NULL) || (!IS_TEMPVAR_INDEX(iptr->dst.varindex)) || - (ls->lifetime[-iptr->dst.varindex-1].type != -1)) + if ((ls == NULL) /* || (!IS_TEMPVAR_INDEX(iptr->dst.varindex)) */ || + (ls->lifetime[iptr->dst.varindex].type != UNUSED)) /* a "living" stackslot */ #endif { @@ -3457,10 +3456,12 @@ gen_method: #endif #if defined(ENABLE_SSA) if ( ls != NULL ) { + /* by edge splitting, in Blocks with phi moves there can only */ /* be a goto as last command, no other Jump/Branch Command */ + if (!last_cmd_was_goto) - codegen_insert_phi_moves(jd, bptr); + codegen_emit_phi_moves(jd, bptr); } #endif @@ -3491,176 +3492,6 @@ gen_method: return true; } -#if defined(ENABLE_SSA) -void codegen_insert_phi_moves(jitdata *jd, basicblock *bptr) { - /* look for phi moves */ - int t_a,s_a,i, type; - int t_lt, s_lt; /* lifetime indices of phi_moves */ - s4 t_regoff, s_regoff, s_flags, t_flags; - codegendata *cd; - lsradata *ls; - - MCODECHECK(512); - - ls = jd->ls; - cd = jd->cd; - - /* Moves from phi functions with highest indices have to be */ - /* inserted first, since this is the order as is used for */ - /* conflict resolution */ - for(i = ls->num_phi_moves[bptr->nr] - 1; i >= 0 ; i--) { - t_a = ls->phi_moves[bptr->nr][i][0]; - s_a = ls->phi_moves[bptr->nr][i][1]; -#if defined(SSA_DEBUG_VERBOSE) - if (compileverbose) - printf("BB %3i Move %3i <- %3i ", bptr->nr, t_a, s_a); -#endif - if (t_a >= 0) { - /* local var lifetimes */ - t_lt = ls->maxlifetimes + t_a; - type = ls->lifetime[t_lt].type; - } - else { - t_lt = -t_a-1; - type = ls->lifetime[t_lt].local_ss->s->type; - /* stackslot lifetime */ - } - - if (type == -1) { -#if defined(SSA_DEBUG_VERBOSE) - if (compileverbose) - printf("...returning - phi lifetimes where joined\n"); -#endif - return; - } - - if (s_a >= 0) { - /* local var lifetimes */ - s_lt = ls->maxlifetimes + s_a; - type = ls->lifetime[s_lt].type; - } - else { - s_lt = -s_a-1; - type = ls->lifetime[s_lt].type; - /* stackslot lifetime */ - } - - if (type == -1) { -#if defined(SSA_DEBUG_VERBOSE) - if (compileverbose) - printf("...returning - phi lifetimes where joined\n"); -#endif - return; - } - - if (t_a >= 0) { - t_flags = VAR(t_a)->flags; - t_regoff = VAR(t_a)->vv.regoff; - - } - else { - t_flags = ls->lifetime[t_lt].local_ss->s->flags; - t_regoff = ls->lifetime[t_lt].local_ss->s->regoff; - } - - if (s_a >= 0) { - /* local var move */ - s_flags = VAR(s_a)->flags; - s_regoff = VAR(s_a)->vv.regoff; - } else { - /* stackslot lifetime */ - s_flags = ls->lifetime[s_lt].local_ss->s->flags; - s_regoff = ls->lifetime[s_lt].local_ss->s->regoff; - } - - if (type == -1) { -#if defined(SSA_DEBUG_VERBOSE) - if (compileverbose) - printf("...returning - phi lifetimes where joined\n"); -#endif - return; - } - - cg_move(cd, type, s_regoff, s_flags, t_regoff, t_flags); - -#if defined(SSA_DEBUG_VERBOSE) - if (compileverbose) { - if (IS_INMEMORY(t_flags) && IS_INMEMORY(s_flags)) { - /* mem -> mem */ - printf("M%3i <- M%3i",t_regoff,s_regoff); - } - else if (IS_INMEMORY(s_flags)) { - /* mem -> reg */ - printf("R%3i <- M%3i",t_regoff,s_regoff); - } - else if (IS_INMEMORY(t_flags)) { - /* reg -> mem */ - printf("M%3i <- R%3i",t_regoff,s_regoff); - } - else { - /* reg -> reg */ - printf("R%3i <- R%3i",t_regoff,s_regoff); - } - printf("\n"); - } -#endif /* defined(SSA_DEBUG_VERBOSE) */ - } -} - -void cg_move(codegendata *cd, s4 type, s4 src_regoff, s4 src_flags, - s4 dst_regoff, s4 dst_flags) { - if ((IS_INMEMORY(dst_flags)) && (IS_INMEMORY(src_flags))) { - /* mem -> mem */ - if (dst_regoff != src_regoff) { - if (!IS_2_WORD_TYPE(type)) { - if (IS_FLT_DBL_TYPE(type)) { - emit_flds_membase(cd, REG_SP, src_regoff * 4); - emit_fstps_membase(cd, REG_SP, dst_regoff * 4); - } else{ - emit_mov_membase_reg(cd, REG_SP, src_regoff * 4, - REG_ITMP1); - emit_mov_reg_membase(cd, REG_ITMP1, REG_SP, dst_regoff * 4); - } - } else { /* LONG OR DOUBLE */ - if (IS_FLT_DBL_TYPE(type)) { - emit_fldl_membase( cd, REG_SP, src_regoff * 4); - emit_fstpl_membase(cd, REG_SP, dst_regoff * 4); - } else { - emit_mov_membase_reg(cd, REG_SP, src_regoff * 4, - REG_ITMP1); - emit_mov_reg_membase(cd, REG_ITMP1, REG_SP, dst_regoff * 4); - emit_mov_membase_reg(cd, REG_SP, src_regoff * 4 + 4, - REG_ITMP1); - emit_mov_reg_membase(cd, REG_ITMP1, REG_SP, - dst_regoff * 4 + 4); - } - } - } - } else { - if (IS_FLT_DBL_TYPE(type)) { - log_text("cg_move: flt/dbl type have to be in memory\n"); -/* assert(0); */ - } - if (IS_2_WORD_TYPE(type)) { - log_text("cg_move: longs have to be in memory\n"); -/* assert(0); */ - } - if (IS_INMEMORY(src_flags)) { - /* mem -> reg */ - emit_mov_membase_reg(cd, REG_SP, src_regoff * 4, dst_regoff); - } else if (IS_INMEMORY(dst_flags)) { - /* reg -> mem */ - emit_mov_reg_membase(cd, src_regoff, REG_SP, dst_regoff * 4); - } else { - /* reg -> reg */ - /* only ints can be in regs on i386 */ - M_INTMOVE(src_regoff,dst_regoff); - } - } -} -#endif /* defined(ENABLE_SSA) */ - - /* codegen_emit_stub_compiler ************************************************** Emit a stub routine which calls the compiler. diff --git a/src/vm/jit/optimizing/dominators.c b/src/vm/jit/optimizing/dominators.c index 236d355e1..f9138d7cb 100644 --- a/src/vm/jit/optimizing/dominators.c +++ b/src/vm/jit/optimizing/dominators.c @@ -33,6 +33,8 @@ #include "toolbox/bitvector.h" +#include "vm/jit/jit.h" + #include "vm/jit/optimizing/graph.h" #include "vm/jit/optimizing/dominators.h" diff --git a/src/vm/jit/optimizing/graph.c b/src/vm/jit/optimizing/graph.c index 88a8963eb..461cca8e6 100644 --- a/src/vm/jit/optimizing/graph.c +++ b/src/vm/jit/optimizing/graph.c @@ -30,29 +30,29 @@ */ +#include + +#include "config.h" + #include "mm/memory.h" #include "toolbox/bitvector.h" +#include "vm/jit/jit.h" + #include "vm/jit/optimizing/lsra.h" #include "vm/jit/optimizing/ssa.h" #include "vm/jit/optimizing/graph.h" #ifdef GRAPH_DEBUG_VERBOSE -#include "vm/options.h" +#include "vmcore/options.h" #endif - /* Helpers for graph_make_cfg */ -void graph_add_jsr( methodinfo *m, graphdata *gd, struct _sbr *sbr,int from, - int to); -void graph_add_cfg( methodinfo *m, graphdata *gd, int from, int to); -void graph_add_exceptions(methodinfo *m, codegendata *cd, graphdata *gd); -void graph_add_subs(methodinfo *m, graphdata *gd, struct _sbr *sbr); +void graph_add_cfg( jitdata *jd, graphdata *gd, basicblock *, basicblock *); +void graph_add_exceptions(jitdata *jd, graphdata *gd); void graph_add_edge( graphdata *gd, int from, int to ); -/* Helper for graph_make_subs */ -void graph_add_sub( methodinfo *m, graphdata *gd, int b_index, - graph_element *ret, bool *visited ); + /* Helper for graph_get_first_* */ int graph_get_first_(graph_element *ge, graphiterator *i); void transform_CFG(jitdata *, graphdata *); @@ -161,35 +161,43 @@ void graph_add_edge( graphdata *gd, int from, int to ) { gd->num_pred[to]++; } -/* split the edge from BB from shown by iterator i wiht new_block */ +/* split the edge from BB from shown by iterator i with new_block */ void graph_split_edge(graphdata *gd, int from, graphiterator *i, int new_block) { graphiterator i_pred; graph_element *n; int l, succ; /* i->value is the BB index of the "old" successor */ + succ = (*i)->value; + /* search for iterator showing predecessor edge from BB succ back to */ /* from */ + l = graph_get_first_predecessor(gd, succ, &i_pred); for(; (l != -1) && (l != from); l = graph_get_next(&i_pred)); _GRAPH_ASSERT(l == from); /* change CFG entries */ + (*i)->value = new_block; i_pred->value = new_block; /* and insert the CFG successor and predecesser entries for new_block */ /* 2 entries needed */ + n = DMNEW(graph_element, 2); + /* make the successor entry for new_block */ + n->value = succ; n->next = gd->successor[new_block]; gd->successor[new_block] = n; gd->num_succ[new_block]++; - n++; /* make the predecessor entry for new_block */ + + n++; n->value = from; n->next = gd->predecessor[new_block]; gd->predecessor[new_block] = n; @@ -201,42 +209,35 @@ Generate the Control Flow Graph ( pred,succ,num_pred of lsradata structure) ************************************************/ void graph_make_cfg(jitdata *jd,graphdata *gd) { - instruction *ip; - s4 *s4ptr; - int high, low, count; - int b_index, len; - bool fall_through; - struct _sbr sbr; /* list of subroutines, sorted by header */ + instruction *iptr; + lookup_target_t *lookup; + branch_target_t *table; + int len, i, l; methodinfo *m; codegendata *cd; registerdata *rd; lsradata *ls; + basicblock *bptr; m = jd->m; cd = jd->cd; rd = jd->rd; ls = jd->ls; - sbr.next = NULL; - /* Add edge from new Basic Block 0 (parameter initialization) */ graph_add_edge(gd, 0, 1); - b_index=0; - while (b_index < m->basicblockcount ) { - if (m->basicblocks[b_index].flags >= BBREACHED) { - fall_through = false; - - if ((len = m->basicblocks[b_index].icount)) { - /* set ip to last non NOP instruction */ - ip = m->basicblocks[b_index].iinstr + - m->basicblocks[b_index].icount -1; - while ((len>0) && (ip->opc == ICMD_NOP)) { + for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) { + if (bptr->flags >= BBREACHED) { + if ((len = bptr->icount)) { + /* set iptr to last non NOP instruction */ + iptr = bptr->iinstr + bptr->icount -1; + while ((len>0) && (iptr->opc == ICMD_NOP)) { len--; - ip--; + iptr--; } /* block contains instructions */ - switch (ip->opc) { /* check type of last instruction */ + switch (iptr->opc) { /* check type of last instruction */ case ICMD_RETURN: case ICMD_IRETURN: case ICMD_LRETURN: @@ -244,7 +245,6 @@ void graph_make_cfg(jitdata *jd,graphdata *gd) { case ICMD_DRETURN: case ICMD_ARETURN: case ICMD_ATHROW: -/* graph_add_cfg(m, gd, b_index, m->basicblockcount); */ break; /* function returns -> end of graph */ case ICMD_IFNULL: @@ -275,70 +275,65 @@ void graph_make_cfg(jitdata *jd,graphdata *gd) { case ICMD_IF_LCMPLE: case ICMD_IF_ACMPEQ: case ICMD_IF_ACMPNE: /* branch -> add next block */ - fall_through = true; -/* graph_add_cfg(m, gd, b_index, b_index+1); */ - /* fall throu -> add branch target */ + /* Add branch target */ + graph_add_cfg(jd, gd, bptr, iptr->dst.block); + /* Add fall through path */ + graph_add_cfg(jd, gd, bptr, bptr->next); + break; + case ICMD_GOTO: - graph_add_cfg(m, gd, b_index, m->basicblockindex[ip->op1]); - if (fall_through) - graph_add_cfg(m, gd, b_index, b_index+1); + graph_add_cfg(jd, gd, bptr, iptr->dst.block); break; /* visit branch (goto) target */ case ICMD_TABLESWITCH: /* switch statement */ - s4ptr = ip->val.a; - - graph_add_cfg(m, gd, b_index, m->basicblockindex[*s4ptr]); - - s4ptr++; - low = *s4ptr; - s4ptr++; - high = *s4ptr; - - count = (high-low+1); - - while (--count >= 0) { - s4ptr++; - graph_add_cfg(m, gd, b_index, - m->basicblockindex[*s4ptr]); - } + table = iptr->dst.table; + l = iptr->sx.s23.s2.tablelow; + i = iptr->sx.s23.s3.tablehigh; + i = i - l + 1; + + /* Add default target */ + + graph_add_cfg(jd, gd, bptr, table[0].block); + table += i; + + while (--i >= 0) { + graph_add_cfg(jd, gd, bptr, table->block); + --table; + } break; case ICMD_LOOKUPSWITCH: /* switch statement */ - s4ptr = ip->val.a; - - graph_add_cfg(m, gd, b_index, m->basicblockindex[*s4ptr]); - - ++s4ptr; - count = *s4ptr++; - - while (--count >= 0) { - graph_add_cfg(m, gd, b_index, - m->basicblockindex[s4ptr[1]]); - s4ptr += 2; - } - break; + lookup = iptr->dst.lookup; + i = iptr->sx.s23.s2.lookupcount; + + while (--i >= 0) { + graph_add_cfg(jd, gd, bptr, lookup->target.block); + lookup++; + } - case ICMD_JSR: - graph_add_jsr(m, gd, &sbr, b_index, m->basicblockindex[ip->op1]); + graph_add_cfg(jd, gd, bptr, iptr->sx.s23.s3.lookupdefault.block); break; - + case ICMD_RET: + case ICMD_JSR: + assert(0); break; + + case ICMD_NOP: + assert(0); default: - graph_add_cfg(m, gd, b_index, b_index + 1 ); + graph_add_cfg(jd, gd, bptr, bptr + 1 ); break; - } /* switch (ip->opc)*/ - } /* if (m->basicblocks[blockIndex].icount) */ - } /* if (m->basicblocks[b_index].flags >= BBREACHED) */ - b_index++; - } /* while (b_index < m->basicblockcount ) */ - - /* add subroutines before exceptions! They "destroy" the CFG */ - graph_add_subs(m, gd, &sbr); - graph_add_exceptions(m, cd, gd); + } /* switch (iptr->opc)*/ + } /* if (bptr->icount) */ + } /* if (bptr->flags >= BBREACHED) */ + } /* for (bptr = ...; bptr != NULL; bptr = bptr->next) */ + + graph_add_exceptions(jd, gd); transform_CFG(jd, gd); + #ifdef GRAPH_DEBUG_VERBOSE if (compileverbose) graph_print(ls, gd); @@ -348,13 +343,19 @@ void graph_make_cfg(jitdata *jd,graphdata *gd) { /***************************************************************** add Edges from guarded Areas to Exception handlers in the CFG *****************************************************************/ -void graph_add_exceptions(methodinfo *m, codegendata *cd, graphdata *gd) { - int i; +void graph_add_exceptions(jitdata *jd, graphdata *gd) { +#if 0 + basicblock *bptr; + raw_exception_entry *ex; + codegendata *cd; + + cd = jd->cd; /* add cfg edges from all bb of a try block to the start of the according */ /* exception handler to ensure the right order after depthfirst search */ - exceptiontable *ex; + ex=jd->exceptiontable; + #ifdef GRAPH_DEBUG_VERBOSE if (compileverbose) printf("ExTable(%i): ", jd->exceptiontablelength); @@ -367,166 +368,49 @@ void graph_add_exceptions(methodinfo *m, codegendata *cd, graphdata *gd) { printf("[%i-%i]->%i ",ex->start->nr, ex->end->nr, ex->handler->nr); #endif - _GRAPH_ASSERT(ex->handler->nr < m->basicblockcount); - _GRAPH_ASSERT(m->basicblocks[ex->handler->nr].flags >= BBREACHED); + + _GRAPH_ASSERT(ex->handler->nr < jd->new_basicblockcount); + _GRAPH_ASSERT(ex->handler->flags >= BBREACHED); _GRAPH_ASSERT(ex->start->nr <= ex->end->nr); /* loop all valid Basic Blocks of the guarded area and add CFG edges */ /* to the appropriate handler */ - for (i=ex->start->nr; (i <= ex->end->nr) && - (i < m->basicblockcount); i++) - if (m->basicblocks[i].flags >= BBREACHED) - graph_add_cfg(m, gd, i, ex->handler->nr); + for (bptr = ex->start; (bptr != NULL) && (bptr != ex->end); bptr = bptr->next) + if (bptr->flags >= BBREACHED) + graph_add_cfg(jd, gd, bptr, ex->handler); + + _GRAPH_ASSERT((bptr != NULL) + && ((bptr->flags >=BBREACHED) || (bptr == ex->end))); } #ifdef GRAPH_DEBUG_VERBOSE if (compileverbose) printf("\n"); #endif -} - -/************************************************** -Add subroutines from ls->sbr list to CFG -**************************************************/ -void graph_add_subs(methodinfo *m, graphdata *gd, struct _sbr *sbr) { - struct _sbr *_sbr; - bool *visited; - int i; -#ifdef GRAPH_DEBUG_VERBOSE - graph_element *ret; -#endif - - visited = (bool *)DMNEW(int, m->basicblockcount + 1); - for (i=0; i <= m->basicblockcount; i++) visited[i] = false; - for (_sbr = sbr->next; _sbr != NULL; _sbr=_sbr->next) { -#ifdef GRAPH_DEBUG_VERBOSE - if (compileverbose) { - printf("Subroutine Header: %3i Return Adresses:",_sbr->header); - for (ret = _sbr->ret; ret != NULL; ret = ret->next) - printf(" %3i", ret->value); - printf("\n"); - } #endif - graph_add_sub( m, gd, _sbr->header, _sbr->ret, visited ); - - } } + /****************************************************************** Add the CFG Edge into next und succ ******************************************************************/ -void graph_add_cfg( methodinfo *m, graphdata *gd, int from, int to) { +void graph_add_cfg( jitdata *jd, graphdata *gd, basicblock *from, + basicblock *to) { /* ignore Empty, Deleted,... Basic Blocks as target */ /* TODO: Setup BasicBlock array before to avoid this */ /* best together with using the basicblock list, so lsra works */ /* with opt_loops, too */ - for (;(to < m->basicblockcount) && (m->basicblocks[to].flags < BBREACHED); - to++); - /* add one to from and to, so the to be inserted Basic Block 0 is */ - /* already regarded */ - graph_add_edge( gd, from + 1, to + 1); -} + for (; (to != NULL) && (to->flags < BBREACHED); to = to->next); -/******************************************************************* -Remember Subroutine "jumps" in ls->sbr and add the CFG Edge of the -"jump" into succ and pred -*******************************************************************/ -void graph_add_jsr( methodinfo *m, graphdata *gd, struct _sbr *sbr, int from, - int to) { - struct _sbr *_sbr, *n; - graph_element *ret; + _GRAPH_ASSERT(to != NULL); - /* ignore Empty, Deleted,... Basic Blocks as target */ - /* TODO: Setup BasicBlock array before to avoid this */ - /* best together with using the basicblock list, so lsra works */ - /* with opt_loops, too */ - for (; (to < m->basicblockcount) && (m->basicblocks[to].flags < BBREACHED); - to++); - _GRAPH_ASSERT( to != m->basicblockcount ); - - graph_add_cfg(m, gd, from, to); - - /* from + 1 ist the return Basic Block Index */ - for (from++; (from < m->basicblockcount) && - (m->basicblocks[from].flags < BBREACHED); from++); - _GRAPH_ASSERT(from != m->basicblockcount); - - /* add subroutine info in ls->sbr.next */ - - /* search for right place to insert */ - for (_sbr = sbr; (_sbr->next != NULL) && (_sbr->next->header < to); - _sbr=_sbr->next); - - if ((_sbr->next!= NULL) && (_sbr->next->header == to)) { - /* Entry for this sub already exist */ - _sbr = _sbr->next; - } else { - /* make new Entry and insert it in ls->sbr.next */ - n = DNEW( struct _sbr ); - n->header = to; - n->ret = NULL; - - n->next = _sbr->next; - _sbr->next = n; - - _sbr = n; - } - /* now insert return adress in sbr->ret */ - ret = DNEW(graph_element); - ret->value = from; - ret->next = _sbr->ret; - _sbr->ret = ret; + /* add one to from and to, so the to be inserted Basic Block 0 is */ + /* already regarded */ + graph_add_edge( gd, from->nr + 1, to->nr + 1); } -/************************************************** -Add a subroutine to CFG -**************************************************/ -void graph_add_sub(methodinfo *m, graphdata *gd, int b_index, - graph_element *ret, bool *visited ) { - graph_element *l; - instruction *ip; - bool next_block; - graphiterator i; - int s; - - /* break at virtual End Block */ - if (b_index != m->basicblockcount) { - visited[b_index] = true; - next_block = false; - - if (m->basicblocks[b_index].flags < BBREACHED) - next_block = true; - if (!next_block && !(m->basicblocks[b_index].icount)) - next_block = true; - - if (!next_block) { - ip = m->basicblocks[b_index].iinstr + - m->basicblocks[b_index].icount - 1; - - if (ip->opc == ICMD_JSR) /* nested Subroutines */ - next_block = true; - } - - if (!next_block) { - if (ip->opc == ICMD_RET) { - /* subroutine return found -> add return adresses to CFG */ - for (l = ret; l != NULL; l = l->next) - graph_add_cfg( m, gd, b_index, l->value); - } else { /* follow CFG */ - s = graph_get_first_successor(gd, b_index, &i); - for(; s != -1; s = graph_get_next(&i)) - if (!visited[s]) - graph_add_sub( m, gd, l->value, ret, visited); - } - } else { /* fall through to next block */ - if (b_index + 1 < m->basicblockcount) - if (!visited[b_index + 1]) - graph_add_sub(m, gd, b_index + 1, ret, visited); - } - } -} /***************************************************************** Sort Basic Blocks using Depth First search in reverse post order @@ -597,19 +481,20 @@ void graph_DFS(lsradata *ls, graphdata *gd) { } -void graph_init_basicblock( basicblock *bptr, int b_index) { +void graph_init_basicblock(jitdata *jd, basicblock *bptr, int b_index) { bptr->nr = b_index; bptr->icount = 0; bptr->iinstr = NULL; bptr->type = BBTYPE_STD; bptr->flags = BBFINISHED; - bptr->instack = NULL; - bptr->outstack = NULL; + bptr->invars = NULL; + bptr->outvars = NULL; bptr->indepth = 0; bptr->outdepth = 0; bptr->branchrefs = NULL; bptr->mpc = -1; bptr->next = NULL; + bptr->method = jd->m; } /*********************************************************************+ @@ -622,8 +507,8 @@ TODO: Do not insert blocks right now - just adopt the call graph! void transform_CFG(jitdata *jd, graphdata *gd) { int i, j, k, n, num_new_blocks; int **var_def; - basicblock *tmp; - stackptr in, out, new_stack; + basicblock *tmp, *bptr; + s4 *in, *out, *new_in_stack, *new_out_stack; graphiterator iter; int *num_succ; struct graph_element **successor; @@ -644,8 +529,8 @@ void transform_CFG(jitdata *jd, graphdata *gd) { /* multiple predecessor -> if found insert a new block between to split */ /* this edge. As first step count how many blocks have to be inserted. */ - num_new_blocks = 0; - for(i = 0; i< m->basicblockcount + 1; i++) { + num_new_blocks = 1; + for(i = 0; i< jd->basicblockcount + 1; i++) { if (graph_has_multiple_successors(gd, i)) { k = graph_get_first_successor(gd, i, &iter); for(; k != -1; k = graph_get_next(&iter)) { @@ -658,24 +543,33 @@ void transform_CFG(jitdata *jd, graphdata *gd) { } /* increase now basicblockcount accordingly. */ - ls->basicblockcount = m->basicblockcount + num_new_blocks + 1; + ls->basicblockcount = jd->basicblockcount + num_new_blocks; ls->basicblocks = DMNEW(basicblock *, ls->basicblockcount); + for(i = 0; i< ls->basicblockcount; i++) + ls->basicblocks[i] = NULL; + /* copy Basic Block References to ls->basicblocks */ - for(i = 0; i< m->basicblockcount; i++) { - ls->basicblocks[i+1] = &(m->basicblocks[i]); - ls->basicblocks[i+1]->nr = i+1; + + for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) { +/* if (bptr->flags >= BBREACHED) { */ + _GRAPH_ASSERT(bptr->nr < jd->basicblockcount); + ls->basicblocks[bptr->nr + 1] = bptr; + bptr->nr = bptr->nr+1; +/* } */ } - /* Create new Basic Blocks: 0, [m->basicblockcount..ls->basicblockcount[ */ - /* num_new_blocks + 1 have to be inserted*/ - tmp = DMNEW( basicblock, num_new_blocks + 1); + /* Create new Basic Blocks: + 0, [jd->new_basicblockcount..ls->basicblockcount[ */ + /* num_new_blocks have to be inserted*/ + + tmp = DMNEW( basicblock, num_new_blocks); ls->basicblocks[0] = tmp; - graph_init_basicblock( tmp, 0); + graph_init_basicblock( jd, tmp, 0); tmp++; ls->basicblocks[0]->next = ls->basicblocks[1]; - if (ls->basicblockcount > m->basicblockcount + 1) { + if (ls->basicblockcount > jd->basicblockcount + 1) { /* new Blocks have to be inserted */ num_succ = DMNEW(int, ls->basicblockcount); successor = DMNEW(graph_element *, ls->basicblockcount); @@ -683,19 +577,19 @@ void transform_CFG(jitdata *jd, graphdata *gd) { num_pred = DMNEW(int, ls->basicblockcount); predecessor = DMNEW(graph_element *, ls->basicblockcount); - /* regard the + 1 for the already regarded new BB 0 */ + /* regard the + 1 for the already inserted new BB 0 */ /* So recreate ls->var_def */ var_def = DMNEW(int *, ls->basicblockcount); - for(i = 0; i < m->basicblockcount + 1; i++) { + for(i = 0; i < jd->basicblockcount + 1; i++) { var_def[i] = ls->var_def[i]; num_succ[i] = gd->num_succ[i]; num_pred[i] = gd->num_pred[i]; successor[i] = gd->successor[i]; predecessor[i] = gd->predecessor[i]; } - for(i = m->basicblockcount + 1; i < ls->basicblockcount; i++) { - var_def[i] = bv_new(ls->max_vars); - graph_init_basicblock( tmp, i); + for(i = jd->basicblockcount + 1; i < ls->basicblockcount; i++) { + var_def[i] = bv_new(jd->varcount); + graph_init_basicblock( jd, tmp, i); ls->basicblocks[i] = tmp; tmp++; @@ -716,8 +610,8 @@ void transform_CFG(jitdata *jd, graphdata *gd) { } /* Now Split the edges */ - num_new_blocks = m->basicblockcount + 1; /* first free new block index */ - for(i = 0; i < m->basicblockcount + 1; i++) { + num_new_blocks = jd->basicblockcount + 1; /* first free new block index */ + for(i = 0; i < jd->basicblockcount + 1; i++) { if (graph_has_multiple_successors(gd, i)) {/* more than one successor */ j = graph_get_first_successor( gd, i, &iter); for(; j != -1; j = graph_get_next(&iter)) { @@ -734,48 +628,43 @@ void transform_CFG(jitdata *jd, graphdata *gd) { ls->basicblocks[num_new_blocks]->indepth = ls->basicblocks[i]->outdepth; - out = ls->basicblocks[i]->outstack; - ls->basicblocks[num_new_blocks]->instack = in = NULL; + out = ls->basicblocks[i]->outvars; + ls->basicblocks[num_new_blocks]->invars = in = NULL; if (ls->basicblocks[num_new_blocks]->indepth > 0) - new_stack = DMNEW( stackelement, + new_in_stack = DMNEW( s4, + ls->basicblocks[num_new_blocks]->indepth); + new_out_stack = DMNEW( s4, ls->basicblocks[num_new_blocks]->indepth); + for(n=0; nbasicblocks[num_new_blocks]->indepth; n++) { - if (in == NULL) { - in = new_stack++; - } else { - in->prev = new_stack++; - in = in->prev; - } - in->type = out->type; - in->varkind = STACKVAR; - in->varnum = 0; - in->regoff = 0; - in->flags = 0; - in->prev = NULL; - /* Add Definition */ - if (n == 0) - ls->basicblocks[num_new_blocks]->instack = in; - - out = out->prev; + new_in_stack[n] = out[n]; + new_out_stack[n] = out[n]; } + ls->basicblocks[num_new_blocks]->invars = new_in_stack; /* Create Outstack */ - ls->basicblocks[num_new_blocks]->outstack = - ls->basicblocks[num_new_blocks]->instack; + ls->basicblocks[num_new_blocks]->outvars = + new_out_stack; ls->basicblocks[num_new_blocks]->outdepth = ls->basicblocks[num_new_blocks]->indepth; _GRAPH_ASSERT(ls->basicblocks[num_new_blocks]->outdepth == - ls->basicblocks[j]->indepth ); + ls->basicblocks[j]->indepth ); + +#if 0 + /* !!!! There can't be inoutvar definitions in one of these */ + /* newly inserted basicblocks !!!! */ /* Add Definition */ /* decrease nr temporarly, because ssa_set_interface*/ /* adds 1 since it is called from stack.c, where there is */ /* no new BB 0 inserted like now */ + ls->basicblocks[num_new_blocks]->nr--; - ssa_set_interface(cd, ls, ls->basicblocks[num_new_blocks]); + ssa_set_interface(jd, ls->basicblocks[num_new_blocks]); ls->basicblocks[num_new_blocks]->nr++; +#endif num_new_blocks++; } } @@ -784,10 +673,10 @@ void transform_CFG(jitdata *jd, graphdata *gd) { } void transform_BB(jitdata *jd, graphdata *gd) { - int i, len; + int n, len; int pred, succ; basicblock *last_block; - instruction *ip; + instruction *iptr; graphiterator iter; methodinfo *m; lsradata *ls; @@ -797,130 +686,120 @@ void transform_BB(jitdata *jd, graphdata *gd) { /* the "real" last Block is always an empty block */ /* so take the one before, to insert new blocks after it */ - last_block = &(m->basicblocks[m->basicblockcount - 1]); + last_block = &(jd->basicblocks[jd->basicblockcount - 1]); _GRAPH_ASSERT(last_block->next->next == NULL); _GRAPH_ASSERT(last_block->next->flags <= BBREACHED); last_block->next->nr = ls->basicblockcount; /* look through new blocks */ - for(i = m->basicblockcount + 1; i < ls->basicblockcount ; i++) { + for(n = jd->basicblockcount + 1; n < ls->basicblockcount ; n++) { /* if a phi move happens at this block, we need this block */ /* if not, remove him from the CFG */ - if (ls->num_phi_moves[i] > 0) { + if (ls->num_phi_moves[n] > 0) { /* i can only have one predecessor and one successor! */ - _GRAPH_ASSERT( graph_has_multiple_predecessors(gd,i) == false); - _GRAPH_ASSERT( graph_has_multiple_successors(gd,i) == false); + _GRAPH_ASSERT( graph_has_multiple_predecessors(gd, n) == false); + _GRAPH_ASSERT( graph_has_multiple_successors(gd, n) == false); - succ = graph_get_first_successor(gd, i, &iter); - pred = graph_get_first_predecessor(gd, i, &iter); + succ = graph_get_first_successor(gd, n, &iter); + pred = graph_get_first_predecessor(gd, n, &iter); - /* set ip to last instruction */ + /* set iptr to last instruction */ len = ls->basicblocks[pred]->icount; - ip = ls->basicblocks[pred]->iinstr + len - 1; - while ((len>0) && (ip->opc == ICMD_NOP)) { + iptr = ls->basicblocks[pred]->iinstr + len - 1; + while ((len>0) && (iptr->opc == ICMD_NOP)) { len--; - ip--; + iptr--; } /* with JSR there can not be multiple successors */ - _GRAPH_ASSERT(ip->opc != ICMD_JSR); + _GRAPH_ASSERT(iptr->opc != ICMD_JSR); /* If the return Statment has more successors and */ /* one of these has more predecessor, we are in */ /* troubles - one would have to insert a new Block */ /* after the one which executes the ICMD_JSR */ /* !!TODO!! if subroutines will not be inlined */ - _GRAPH_ASSERT(ip->opc != ICMD_RET); + _GRAPH_ASSERT(iptr->opc != ICMD_RET); /* link new block into basicblocks list */ /* if edge to split is the "fallthrough" path of the */ /* conditional, then link the new block inbetween */ /* and generate no ICMD */ /* else if edge to split is the branch, generate a */ - /* ICMD_GOTO and add new BB at and of BB List */ + /* ICMD_GOTO and add new BB at the end of the BB List*/ if ((ls->basicblocks[pred]->next == ls->basicblocks[succ]) - && (ip->opc != ICMD_LOOKUPSWITCH) - && (ip->opc != ICMD_TABLESWITCH) - && (ip->opc != ICMD_GOTO)) { + && (iptr->opc != ICMD_LOOKUPSWITCH) + && (iptr->opc != ICMD_TABLESWITCH) + && (iptr->opc != ICMD_GOTO)) { /* GOTO, *SWITCH have no fallthrough path */ /* link into fallthrough path */ - ls->basicblocks[i]->next = + ls->basicblocks[n]->next = ls->basicblocks[pred]->next; ls->basicblocks[pred]->next = - ls->basicblocks[i]; + ls->basicblocks[n]; /* generate no instructions */ - ls->basicblocks[i]->icount = 1; - ls->basicblocks[i]->iinstr = NEW(instruction); - ls->basicblocks[i]->iinstr[0].opc = ICMD_NOP; + ls->basicblocks[n]->icount = 1; + ls->basicblocks[n]->iinstr = NEW(instruction); + ls->basicblocks[n]->iinstr[0].opc = ICMD_NOP; } else { - /* Block i is in the Branch path */ + /* Block n is in the Branch path */ /* link Block at the end */ - ls->basicblocks[i]->next =last_block->next; - last_block->next = ls->basicblocks[i]; - last_block = ls->basicblocks[i]; + ls->basicblocks[n]->next =last_block->next; + last_block->next = ls->basicblocks[n]; + last_block = ls->basicblocks[n]; /* change the Branch Target to BB i */ - switch(ip->opc) { + switch(iptr->opc) { case ICMD_LOOKUPSWITCH: { - s4 k, l, *s4ptr; - void **tptr; - - tptr = (void **) ip->target; - if ((basicblock*)tptr[0] == ls->basicblocks[succ]) { - /* target found -> change*/ - tptr[0] = ls->basicblocks[i]; - } + s4 i; + lookup_target_t *lookup; - s4ptr = ip->val.a; - l = s4ptr[0]; /* default */ - k = s4ptr[1]; /* count */ - - while (--k >= 0) { - s4ptr += 2; - ++tptr; + lookup = iptr->dst.lookup; - if ((basicblock*)tptr[0] == ls->basicblocks[succ]) - { + i = iptr->sx.s23.s2.lookupcount; + + while (--i >= 0) { + if (lookup->target.block == ls->basicblocks[succ]) /* target found -> change */ - tptr[0] = ls->basicblocks[i]; - } + lookup->target.block = ls->basicblocks[n]; + lookup++; } + + if (iptr->sx.s23.s3.lookupdefault.block == ls->basicblocks[succ]) + /* target found -> change */ + iptr->sx.s23.s3.lookupdefault.block = ls->basicblocks[n]; } break; case ICMD_TABLESWITCH: { - s4 k, l, *s4ptr; - void **tptr; + s4 i, l; + branch_target_t *table; - tptr = (void **) ip->target; - - s4ptr = ip->val.a; - l = s4ptr[1]; /* low */ - k = s4ptr[2]; /* high */ + table = iptr->dst.table; + + l = iptr->sx.s23.s2.tablelow; + i = iptr->sx.s23.s3.tablehigh; - k = k - l + 1; + i = i - l + 1; - if ((basicblock*)tptr[0] == ls->basicblocks[succ]) - { + if (table[0].block == ls->basicblocks[succ]) /* default target */ /* target found -> change*/ - tptr[0] = ls->basicblocks[i]; - } - tptr += k; - - while (--k >= 0) { - if ((basicblock*)tptr[0] == ls->basicblocks[succ]) - { - /* target found -> change*/ - tptr[0] = ls->basicblocks[i]; - } - --tptr; + table[0].block = ls->basicblocks[n]; + + table += i; + + while (--i >= 0) { + if (table->block == ls->basicblocks[succ]) + /* target found -> change */ + table->block = ls->basicblocks[n]; + --table; } } break; @@ -953,8 +832,8 @@ void transform_BB(jitdata *jd, graphdata *gd) { case ICMD_IF_ACMPEQ: case ICMD_IF_ACMPNE: case ICMD_GOTO: - _GRAPH_ASSERT(ip->target == ls->basicblocks[succ]); - ip->target = ls->basicblocks[i]; + _GRAPH_ASSERT(iptr->dst.block == ls->basicblocks[succ]); + iptr->dst.block = ls->basicblocks[n]; break; default: /* Exception Edge to split */ @@ -963,17 +842,14 @@ void transform_BB(jitdata *jd, graphdata *gd) { } /* Generate the ICMD_GOTO */ - ls->basicblocks[i]->icount = 1; - ls->basicblocks[i]->iinstr = + ls->basicblocks[n]->icount = 1; + ls->basicblocks[n]->iinstr = DNEW(instruction); - ls->basicblocks[i]->iinstr->opc = + ls->basicblocks[n]->iinstr->opc = ICMD_GOTO; - ls->basicblocks[i]->iinstr->target = + ls->basicblocks[n]->iinstr->dst.block = ls->basicblocks[succ]; - ls->basicblocks[i]->iinstr->op1 = succ; } - ls->basicblocks[i]->iinstr[0].dst = - ls->basicblocks[i]->outstack; } } } diff --git a/src/vm/jit/optimizing/graph.h b/src/vm/jit/optimizing/graph.h index ca62a998a..a887b4723 100644 --- a/src/vm/jit/optimizing/graph.h +++ b/src/vm/jit/optimizing/graph.h @@ -50,11 +50,13 @@ # define _GRAPH_ASSERT(a) #endif +#if 0 struct _sbr { int header; /* BB Index of subroutine start (SBR_HEADER) */ struct graph_element *ret; /* List of possible return BB indizes */ struct _sbr *next; }; +#endif struct graph_element { int value; diff --git a/src/vm/jit/optimizing/lifetimes.c b/src/vm/jit/optimizing/lifetimes.c index 3e15dd231..f2ac6d703 100644 --- a/src/vm/jit/optimizing/lifetimes.c +++ b/src/vm/jit/optimizing/lifetimes.c @@ -51,49 +51,51 @@ #include "vm/jit/optimizing/lifetimes.h" #ifdef LT_DEBUG_VERBOSE -#include "vm/options.h" +#include "vmcore/options.h" #endif #include #include /* function prototypes */ -void _scan_lifetimes(registerdata *rd, lsradata *ls, graphdata *gd, - basicblock *bptr); -void _lsra_new_stack( lsradata *, stackptr , int , int, int); -void _lsra_from_stack(lsradata *, stackptr , int , int, int); -void lsra_usage_local(lsradata *, s4 , int , int , int , int ); +void _lt_scanlifetimes(jitdata *jd, graphdata *gd, basicblock *bptr, int); +void lt_usage(jitdata *, s4 , int , int , int ); -void LifeOutAtBlock(lsradata *ls, graphdata *gd, int *M, int n, - struct lifetime *lt); -void LifeInAtStatement(lsradata *ls, graphdata *gd, int *M, int b_index, +void lt_lifeoutatblock(lsradata *ls, graphdata *gd, int *M, int b_index, + struct lifetime *lt, worklist *W); +void lt_lifeatstatement(lsradata *ls, graphdata *gd, int b_index, + int iindex, struct lifetime *lt, bool life_in, + worklist *W); +#if 0 +void lt_lifeinatstatement(lsradata *ls, graphdata *gd, int *M, int b_index, int iindex, struct lifetime *lt); -void LifeOutAtStatement(lsradata *ls, graphdata *gd, int *M, int b_index, +void lt_lifeoutatstatement(lsradata *ls, graphdata *gd, int *M, int b_index, int iindex, struct lifetime *lt); +#endif #ifdef USAGE_COUNT void lt_get_nesting(lsradata *ls, graphdata *gd, dominatordata *dd); #endif -void set_use_site(struct lifetime *lt, struct site *use_site) { +void lt_set_use_site(struct lifetime *lt, struct site *use_site) { } -struct site *get_first_use_site(struct lifetime *lt, lt_iterator *iter) { +struct site *lt_get_first_use_site(struct lifetime *lt, lt_iterator *iter) { return ((*iter) = lt->use); } -struct site *get_next_site(lt_iterator *iter) { +struct site *lt_get_next_site(lt_iterator *iter) { if ((*iter) == NULL) return NULL; else return ((*iter) = (*iter)->next); } -struct site *get_first_def_site(struct lifetime *lt, lt_iterator *iter) { +struct site *lt_get_first_def_site(struct lifetime *lt, lt_iterator *iter) { return ((*iter) = lt->def); } -bool v_is_defined_at_s(lsradata *ls, int b_index, int iindex, +bool lt_v_is_defined_at_s(lsradata *ls, int b_index, int iindex, struct lifetime * lt) { struct site *def_site; bool is_defined_at_s; @@ -107,11 +109,16 @@ bool v_is_defined_at_s(lsradata *ls, int b_index, int iindex, /**************************************************************************** Get Def & Use Sites ****************************************************************************/ -void scan_lifetimes(methodinfo *m, codegendata *cd, registerdata *rd, - lsradata *ls, graphdata *gd, dominatordata *dd) { - int i, p; +void lt_scanlifetimes(jitdata *jd, graphdata *gd, dominatordata *dd) { + int i, l, p; s4 t; - methoddesc *md = m->parseddesc; + methodinfo *m; + lsradata *ls; + methoddesc *md; + + ls = jd->ls; + m = jd->m; + md = m->parseddesc; graph_DFS(ls, gd); @@ -122,7 +129,12 @@ void scan_lifetimes(methodinfo *m, codegendata *cd, registerdata *rd, #if defined(LT_DEBUG_VERBOSE) if (compileverbose) { printf("Sorted: "); - for (i=0; i < ls->basicblockcount; i++) printf("%3i ", ls->sorted[i]); + for (i=0; i < ls->basicblockcount; i++) { + l = ls->sorted[i]; + if (l != -1) + l = ls->basicblocks[l]->nr; + printf("%3i(%3i) ", ls->sorted[i], l); + } printf("\n"); printf("Sorted_rev: "); for (i=0; i < ls->basicblockcount; i++) @@ -130,64 +142,53 @@ void scan_lifetimes(methodinfo *m, codegendata *cd, registerdata *rd, printf("\n"); } #endif - if (ls->max_interfaces != -1) { - /* init Interface Stackslot lifetimes -1.. */ - for (i = -1; i > -ls->interface_0[-ls->max_interfaces-1]-1; i--) { - ls->lifetime[-i-1].v_index = i; - ls->lifetime[-i-1].usagecount = 0; - ls->lifetime[-i-1].bb_last_use = -1; - ls->lifetime[-i-1].bb_first_def = -1; - ls->lifetime[-i-1].local_ss = NULL; - ls->lifetime[-i-1].savedvar = 0; - ls->lifetime[-i-1].flags = 0; - /* .type already set while ssa_Rename_, so we could save a */ - /* lookup table for the type information */ - } - ls->v_index = -ls->interface_0[-ls->max_interfaces-1]-1; - } for(i = ls->basicblockcount - 1; i>= 0; i--) if (ls->sorted[i] != -1) - _scan_lifetimes(rd, ls, gd, ls->basicblocks[ls->sorted[i]]); + _lt_scanlifetimes(jd, gd, ls->basicblocks[ls->sorted[i]], + ls->sorted[i]); /* Parameter initialisiation for locals [0 .. paramcount[ */ /* -> add local var write access at (bb=0,iindex=0) */ - for (p = 0; p < md->paramcount; p++) { + for (p = 0, l = 0; p < md->paramcount; p++) { t = md->paramtypes[p].type; - i = ls->local_0[p]; - _LT_ASSERT( i < jd->maxlocals); + i = jd->local_map[l * 5 + t]; + l++; + if (IS_2_WORD_TYPE(t)) /* increment local counter for 2 word types */ + l++; + if (i == UNUSED) + continue; + i = ls->var_0[i]; +/* _LT_ASSERT( i < jd->cd->maxlocals); */ #ifdef LT_DEBUG_VERBOSE if (compileverbose) printf("param %3i -> L %3i/%3i",p,i,t); #endif - if (rd->locals[i][t].type >= 0) { - /* Param to Local init happens before normal Code */ -#ifdef LT_DEBUG_VERBOSE - if (compileverbose) - printf(" ok\n"); -#endif - lsra_usage_local(ls, i, t, 0, 0, LSRA_STORE); - } + _LT_ASSERT(t == VAR(i)->type); + + /* Param to Local init happens before normal Code */ + #ifdef LT_DEBUG_VERBOSE - else - if (compileverbose) - printf(" .....\n"); + if (compileverbose) + printf(" ok\n"); #endif + lt_usage(jd, i, 0, 0, LT_DEF); } /* end for */ } -bool is_simple_lt(struct lifetime *lt) { +bool lt_is_simple_lt(struct lifetime *lt) { lt_iterator i_def, i_use; struct site *def, *use; bool all_in_same_block; - def = get_first_def_site(lt, &i_def); - use = get_first_use_site(lt, &i_use); + def = lt_get_first_def_site(lt, &i_def); + use = lt_get_first_use_site(lt, &i_use); all_in_same_block = true; - for (; (all_in_same_block && (use != NULL)); use = get_next_site(&i_use)) { + for (; (all_in_same_block && (use != NULL)); + use = lt_get_next_site(&i_use)) { all_in_same_block = (use->iindex >= 0) && (use->b_index == def->b_index); } @@ -224,262 +225,38 @@ void lt_set_simple_use(lsradata *ls, struct lifetime *lt) { lt_is_live(ls, lt, lt->def->b_index, lt->def->iindex); /* get last use */ - use = get_first_use_site(lt, &i_use); + use = lt_get_first_use_site(lt, &i_use); /* lt->bb_last_use = ls->sorted_rev[use->b_index]; */ /* lt->i_last_use = use->iindex; */ - for (; (use != NULL); use = get_next_site(&i_use)) + for (; (use != NULL); use = lt_get_next_site(&i_use)) lt_is_live(ls, lt, use->b_index, use->iindex); /* if (use->iindex > lt->i_last_use) */ /* lt->i_last_use = use->iindex; */ } -#if defined(JOIN_PHI_LT) -/****************************************************************************** -Set up data structures for a interference graphs of variables used in each phi -function -******************************************************************************/ -void lt_setup_phi_interference(lsradata *ls, graphdata *gd) { - int a, b, i, j, t; - int *stack, stack_top; - struct igraph_lookup **lookup; - struct igraph_lookup *tmp; - int lookup_top, igraph_top; - struct igraph_vars *new_var; - - lookup_top = igraph_top = 0; - lookup = DMNEW(struct igraph_lookup *, ls->max_vars_with_indices*2); - stack = DMNEW(int, ls->max_vars_with_indices); - for(b = 0; b < ls->basicblockcount; b++) { - for(a = 0; a < ls->max_vars; a++) { - if (ls->phi[b][a] != NULL) { - -#if defined(LT_DEBUG_VERBOSE) - if (compileverbose) { - printf("Phi(%3i, %3i): ", a, gd->num_pred[b]); - } -#endif - stack_top = 0; - /* loop for all vars in this phi function -> setup a interf graph */ - /* structure for it */ - for(j = 0; j < gd->num_pred[b] + 1; j++) { - if (ls->phi[b][a][j] != ls->max_vars_with_indices) { - /* used entry */ - stack[stack_top++] = ls->phi[b][a][j]; -#if defined(LT_DEBUG_VERBOSE) - if (compileverbose) { - printf("%3i ",ls->phi[b][a][j]); - } -#endif - } - } - _LT_ASSERT(stack_top <= ls->max_vars_with_indices); -#if defined(LT_DEBUG_VERBOSE) - if (compileverbose) { - printf("\n "); - } -#endif - /* sort (insertion)*/ - /* TODO: make unique sort proc (see lsra_insertion...) */ - for (i = 1; i <= stack_top - 1; i++) { - j = i; - t = stack[j]; - while ((j > 0) && (stack[j-1] > t)) { - stack[j] = stack[j-1]; - j--; - } - stack[j] = t; - } -#if defined(LT_DEBUG_VERBOSE) - if (compileverbose) { - printf("Sorted: "); - for(i=0; i < stack_top; i++) - printf("%3i ",stack[i]); - printf("\n"); - } -#endif - /* now remove duplicates */ - /* t ... new stack_top */ - /* i ... first of duplicate sequence */ - /* j ... next duplicate sequence */ - i = t = 0; - while (i < stack_top) { - stack[t] = stack[i]; - t++; - for(j = i + 1; (j < stack_top)&&(stack[i]==stack[j]); j++); - if (j == stack_top) { - /* last duplicate entries */ - stack_top = t; - break; - } - i = j; - } - _LT_ASSERT(stack_top <= ls->max_vars_with_indices); -#if defined(LSRA_DEBUG_VERBOSE) - if (compileverbose) { - printf("wo duplicates: "); - for(i=0; i < stack_top; i++) - printf("%3i ",stack[i]); - printf("\n"); - } -#endif - /* setup lookuptable for vars stack[0..stack_top[ to */ - /* interference graph number & interference graph structure */ - for(i = 0; i < stack_top; i++) { - _LT_ASSERT(lookup_top < ls->max_vars_with_indices*2); - lookup[lookup_top] = DNEW(struct igraph_lookup); - lookup[lookup_top]->var = stack[i]; /* var index */ - lookup[lookup_top]->igraph = igraph_top; /* igraph index */ - lookup_top++; - } - igraph_top++; - } - } - } - ls->igraph = DMNEW(struct igraph , igraph_top); - ls->igraph_top = igraph_top; - for(i = 0; i < igraph_top; i++) { - ls->igraph[i].inter = NULL; - ls->igraph[i].vars = NULL; - } - - /* sort lookup */ - - for (i = 1; i < lookup_top; i++) { - j = i; - t = lookup[j]->var; - tmp = lookup[j]; - while ((j > 0) && (lookup[j-1]->var > t)) { - lookup[j]=lookup[j-1]; - j--; - } - lookup[j] = tmp; - } - - /* join igraphs for multiple vars */ - /* TODO: make this more efficient! */ - for (i = 1; i < lookup_top; i++) { - if (lookup[i-1]->var == lookup[i]->var) { - for(j = 0; j < lookup_top; j++) - if (j != i) - if (lookup[j]->igraph == lookup[i]->igraph) - lookup[j]->igraph = lookup[i-1]->igraph; - lookup[i]->igraph = lookup[i-1]->igraph; - } - } - - ls->igraph_lookup_top = lookup_top; - ls->igraph_lookup = DMNEW(struct igraph_lookup *, lookup_top); - for(i = 0; i < lookup_top; i++) { - ls->igraph_lookup[i] = lookup[i]; - new_var = DNEW(struct igraph_vars); - new_var->v = lookup[i]->var; - new_var->next = ls->igraph[lookup[i]->igraph].vars; - ls->igraph[lookup[i]->igraph].vars = new_var; - } -#if defined(LT_DEBUG_VERBOSE) - if (compileverbose) { - printf("IGraph(%3i): ",igraph_top); - for(i = 0; i < igraph_top; i++) { - printf("%3i(",i); - for(new_var = ls->igraph[i].vars; new_var != NULL; new_var = new_var->next) - printf("%3i,",new_var->v); - printf(") "); - } - printf("\n"); - for(i=0; i < lookup_top; i++) - printf("(%3i->%3i) ",ls->igraph_lookup[i]->var, ls->igraph_lookup[i]->igraph); - printf("\n"); - } -#endif -} - -int get_igraph_index(lsradata *ls, int var) { - int i, i_max, i_min; - - if (ls->igraph_lookup == NULL) - return -1; - - i_min = 0; - i_max = ls->igraph_lookup_top; - - while (true) { - i = (i_min + i_max)/2; - if (ls->igraph_lookup[i]->var == var) - return ls->igraph_lookup[i]->igraph; - if ((i_max - i_min <= 1)) - return -1; - if (var < ls->igraph_lookup[i]->var) { - i_max = i; - } else { - i_min = i; - } - } - /* prevent compiler warning */ - return -1; -} - -void build_interference(lsradata *ls, int b_index, int iindex, - struct lifetime *lt) { - int igraph_index; - struct igraph_vars *v; - struct igraph_interference *i; - struct lifetime *lt_i; - - if ((igraph_index = get_igraph_index(ls, lt->v_index)) == -1) - return; - - _LT_ASSERT(ls->igraph[igraph_index].vars != NULL); - - for(v = ls->igraph[igraph_index].vars; v != NULL; v = v->next) { - /* ignore interference with var itself */ - if (v->v != lt->v_index) { - /* get lifetime of v->v */ - if (v->v >= 0) { - lt_i = &(ls->lifetime[ls->maxlifetimes + v->v]); - } else { - lt_i = &(ls->lifetime[-v->v - 1]); - } - _LT_ASSERT(lt_i->v_index == v->v); - - if (v_is_defined_at_s(ls, b_index, iindex, lt_i)) { - /* search if entry already exists */ - for(i = ls->igraph[igraph_index].inter; i != NULL; i = i->next) - { - if ((i->v1 == min(v->v, lt->v_index)) && - (i->v2 == max(v->v, lt->v_index))) - break; - } - if (i == NULL) { - i = DNEW(struct igraph_interference); - i->v1 = min(v->v, lt->v_index); - i->v2 = max(v->v, lt->v_index); - i->next = ls->igraph[igraph_index].inter; - ls->igraph[igraph_index].inter = i; - } - } - } - } - -} -#endif - -void LifenessAnalysis(methodinfo *m, lsradata *ls, graphdata *gd) { - int *M; /* bit_vecor of visited blocks */ - int *use; /* bit_vecor of blocks with use sites visited */ +void lt_lifeness_analysis(jitdata *jd, graphdata *gd) { + int *M; /* bit_vecor of visited blocks */ + int *use; /* bit_vecor of blocks with use sites visited */ + worklist *W; /* Worklist of Basic Blocks, where lt is life-out */ struct site *use_site, *u_site; lt_iterator iter, iter1; graphiterator pred_iter; - int lt_index, i, pred, iindex, iindex1; + int lt_index, i, pred, iindex, iindex1, b_index; struct lifetime *lt; int *phi; +/* #define MEASURE_RT */ +#ifdef MEASURE_RT struct timespec time_start,time_end; -#if 0 - bool measure = false; #endif -/* #define MEASURE_RT */ + lsradata *ls; + methodinfo *m; + + ls = jd->ls; + m = jd->m; + #ifdef MEASURE_RT if (clock_gettime(CLOCK_THREAD_CPUTIME_ID,&(time_start)) != 0) { @@ -487,19 +264,10 @@ void LifenessAnalysis(methodinfo *m, lsradata *ls, graphdata *gd) { abort(); } #endif -#if 0 - if ((strcmp(m->class->name->text, "java/lang/Object")==0) && - (strcmp(m->name->text,"equals")==0)) { - printf("----------------\n"); -/* measure = false; */ - } -#endif -#if defined(JOIN_PHI_LT) - lt_setup_phi_interference(ls, gd); -#endif - M = bv_new(ls->basicblockcount); + M = bv_new(ls->basicblockcount); use = bv_new(ls->basicblockcount); + W = wl_new(ls->basicblockcount); #ifdef LT_DEBUG_VERBOSE if (compileverbose) @@ -514,45 +282,57 @@ void LifenessAnalysis(methodinfo *m, lsradata *ls, graphdata *gd) { printf("LT: %3i:", lt_index); #endif -#if 0 - if (measure) - if (clock_gettime(CLOCK_THREAD_CPUTIME_ID,&(time_start)) != 0) { - fprintf(stderr,"could not get time: %s\n",strerror(errno)); - abort(); - } -#endif - lt->savedvar = 0; _LT_ASSERT(lt->def != NULL); _LT_ASSERT(lt->def->next == NULL); /* SSA! */ - _LT_ASSERT(lt->use != NULL); +/* _LT_ASSERT(lt->use != NULL); */ lt->bb_last_use = -1; lt->bb_first_def = ls->basicblockcount; bv_reset(M, ls->basicblockcount); bv_reset(use, ls->basicblockcount); + wl_reset(W, ls->basicblockcount); - use_site = get_first_use_site(lt, &iter); - for (;use_site != NULL; use_site = get_next_site(&iter)) { + use_site = lt_get_first_use_site(lt, &iter); + + /* Make unused Vars life at their Def Site */ + + if (use_site == NULL) { + lt_is_live(ls, lt, lt->def->b_index, lt->def->iindex); + if (lt->def->iindex < 0) { + + /* def only in phi function */ + + lt_is_live(ls, lt, lt->def->b_index, 0); + } + } + for (;use_site != NULL; use_site = lt_get_next_site(&iter)) { iindex = use_site->iindex; if ((lt->def->b_index == use_site->b_index) && (iindex < 0) && (iindex <= lt->def->iindex)) { - if (iindex == lt->def->iindex) /* check this */ - continue; + +/* bv_set_bit(use, use_site->b_index); */ /* do normal analysis */ /* there is a use in a phi function before def site */ - } else if (bv_get_bit(use, use_site->b_index)) { + + } + else if (bv_get_bit(use, use_site->b_index)) { continue; - } else { + } + else { bv_set_bit(use, use_site->b_index); + /* use sites of this basic block not visited till now */ - /* get use site of this bb with highest iindex (lower than def site)*/ + /* get use site of this bb with highest iindex lower than */ + /* def site */ + iindex1 = -1; u_site = use_site; - for(iter1= iter; u_site != NULL; u_site = get_next_site(&iter1)) { + for(iter1= iter; u_site != NULL; + u_site = lt_get_next_site(&iter1)) { if ((u_site->b_index == use_site->b_index) && (lt->def->b_index == use_site->b_index) && (u_site->iindex >= 0) && @@ -568,12 +348,14 @@ void LifenessAnalysis(methodinfo *m, lsradata *ls, graphdata *gd) { if (iindex1 != -1) iindex = iindex1; } + #ifdef LT_DEBUG_VERBOSE if (compileverbose) printf("(%3i,%3i)", use_site->b_index, iindex); #endif if (iindex < 0) { + /* use in phi function */ /* ls->phi[use_site->b_index][-use_site->iindex-1]*/ @@ -581,50 +363,38 @@ void LifenessAnalysis(methodinfo *m, lsradata *ls, graphdata *gd) { phi = ls->phi[use_site->b_index][-iindex-1]; _LT_ASSERT(phi != NULL); - - if (lt->v_index != phi[0]) { /* check this */ - /* ignore "Self use/def" in phi function */ - pred = graph_get_first_predecessor(gd, use_site->b_index, &pred_iter); for(i = 1; (pred != -1); i++,pred = graph_get_next(&pred_iter)) - if (lt->v_index == phi[i]) - LifeOutAtBlock(ls, gd, M, pred, lt); - } - } else - LifeInAtStatement(ls, gd, M, use_site->b_index, - iindex, lt); + if (lt->v_index == phi[i]) { + + /* Add "Life out Basic Blocks to Worklist */ + + wl_add(W, pred); + } + } + else /* lt is live-in at this statement */ + lt_lifeatstatement(ls, gd, use_site->b_index, + iindex, lt, true, W); + } /* for (;use_site != NULL; use_site = lt_get_next_site(&iter)) */ + + /* process Worklist */ + + while (!wl_is_empty(W)) { + b_index = wl_get(W); + lt_lifeoutatblock(ls, gd, M, b_index, lt, W); } + + #ifdef LT_DEBUG_VERBOSE - if (compileverbose) + if (compileverbose) printf("\n"); #endif -#if 0 - if (measure) { - if (clock_gettime(CLOCK_THREAD_CPUTIME_ID,&(time_end)) != 0) { - fprintf(stderr,"could not get time: %s\n",strerror(errno)); - abort(); - } - - { - long diff; - time_t atime; + } /* for(lt_index = 0; lt_index < ls->lifetimecount; lt_index++) */ - diff = (time_end.tv_nsec - time_start.tv_nsec) / 1000; - atime = time_start.tv_sec; - while (atime < time_end.tv_sec) { - atime++; - diff += 1000000; - } - printf("%8li %3i %s.%s.%s\n",diff, lt_index, m->class->name->text, m->name->text, - m->descriptor->text); - } - } -#endif - } #ifdef MEASURE_RT if (clock_gettime(CLOCK_THREAD_CPUTIME_ID,&(time_end)) != 0) { fprintf(stderr,"could not get time: %s\n",strerror(errno)); @@ -645,423 +415,167 @@ void LifenessAnalysis(methodinfo *m, lsradata *ls, graphdata *gd) { m->descriptor->text); } #endif +} -#if defined(JOIN_PHI_LT) -#if defined(LT_DEBUG_VERBOSE) - if (compileverbose) { - struct igraph_interference *inter; - printf("Interferences: "); - for(i = 0; i < ls->igraph_top; i++) { - if (ls->igraph[i].inter != NULL) { - for(inter = ls->igraph[i].inter; inter != NULL; inter = inter->next) - printf("%3i(%3i,%3i) ",i,inter->v1,inter->v2); - } - } - printf("\n"); - } -#endif +/******************************************************************************* +lt_lifeatstatement - { - struct igraph_vars *var, *var1; - struct igraph_interference *inter; - struct lifetime *lt1, *lt2; - struct stackslot *ss; - struct site *s; - int j, k, l; - instruction *iptr; + +IN: lsradata *ls pointer to worklist created with wl_new + graphdata *gd + int b_index Basic block index of instruction + int iindex index of instruction in Basic Block + struct lifetime *lt Pointer to lifetime structure + bool life_in TRUE lifetime lt is life 'into' that instruction + FALSE lifetime lt is life 'out' of that instruction + +IN/OUT: worklist *W Worklist of Basic Blocks, where lt is life-out +*******************************************************************************/ +void lt_lifeatstatement(lsradata *ls, graphdata *gd, int b_index, + int iindex, struct lifetime *lt, bool life_in, + worklist *W) { + + int prev_iindex; /* Statement before iindex */ int pred; - graphiterator iter; + graphiterator pred_iter; + instruction *iptr; - /* join phi arguments that do not interfere */ - printf("this should not be seen \n"); - for(i = 0; i < ls->igraph_top; i++) { - if (ls->igraph[i].inter == NULL) { - lt1 = lt2 = NULL; - for(var = ls->igraph[i].vars; var != NULL; var = var->next) { - if (lt1 == NULL) { - if (var->v >= 0) { - lt1 = &(ls->lifetime[ls->maxlifetimes + var->v]); - } else { - lt1 = &(ls->lifetime[-var->v - 1]); - } - _LT_ASSERT(lt1->v_index == var->v); - continue; - } else { - if (var->v >= 0) { - lt2 = &(ls->lifetime[ls->maxlifetimes + var->v]); - } else { - lt2 = &(ls->lifetime[-var->v - 1]); - } - _LT_ASSERT(lt2->v_index == var->v); - } + while (true) { + if (!life_in) { +#ifdef LT_DEBUG_VERBOSE + if ((compileverbose) && (iindex >= 0)) + printf("LO@ST: vi %3i bi %3i ii %3i\n", + lt->v_index, b_index, iindex); +#endif - if ((lt1->v_index < 0) && (lt2->v_index >=0)) { - /* swap lt1 and lt2 - cannot join Stackslotlifetime */ - /* into Localvar lifetimes */ + /* lt->v_index is life-out at statement at (b_index,iindex) */ - lt = lt1; - lt1 = lt2; - lt2 = lt; - } + /* Once a interference graph is needed, add here an edge (v,w) */ + /* to the ig, for each variable w defined at this instruction */ + /* except v=lt->v_index */ - if ((lt1->v_index >=0) && (lt2->v_index >=0)) { - for(s = lt2->def; s != NULL; s = s->next) { - if ((s->b_index == 0) && (s->iindex ==0)) { - /* swap lt1 and lt2 - lt2 is initialized by a param*/ + if (!lt_v_is_defined_at_s(ls, b_index, iindex, lt)) { - _LT_ASSERT((lt1->def->b_index != 0) - || (lt1->def->iindex !=0)); - lt = lt1; - lt1 = lt2; - lt2 = lt; - break; - } - } - } + /* v is life in at out of statement -> check if the SAVEDVAR */ + /* flag is needed to be set */ - /* already joined */ - if ((lt2->type == -1) || (lt1 == lt2)) - continue; -#if defined(LT_DEBUG_VERBOSE) - if (compileverbose) { - printf("Joining %3i into %3i\n",lt2->v_index, lt1->v_index); - } -#endif + if ((iindex >= 0) && (b_index != 0)) { - /* copy local_ss from lt2 to lt1 & rename local_ss->s->varnum */ - while (lt2->local_ss != NULL) { - if (lt1->v_index >= 0) { - lt2->local_ss->s->varkind = LOCALVAR; - } - /* other direction not possible! (LOCALVAR->TEMPVAR) */ - /* see 'if' above */ - lt2->local_ss->s->varnum = lt1->v_index; - - ss = lt1->local_ss; - lt1->local_ss = lt2->local_ss; - lt2->local_ss = lt2->local_ss->next; - lt1->local_ss->next = ss; - } + /* real ICMD, no phi-function, no param initialisation */ - /* look at the use sites */ - for(s = lt2->use; s != NULL; s = s->next) { - if (s->iindex < 0) { - /* use in phi function -> change */ - pred=graph_get_first_predecessor(gd, s->b_index, &iter); - for (j = 1; pred != -1; j++, - pred = graph_get_next(&iter)) { - if (ls->phi[s->b_index][-s->iindex-1][j] == - lt2->v_index) { - ls->phi[s->b_index][-s->iindex-1][j] - = lt1->v_index; - /* change in appropriate phi_move, too */ - for(k=0; knum_phi_moves[pred]; k++) { - if (ls->phi_moves[pred][k][1] == - lt2->v_index) { - ls->phi_moves[pred][k][1]=lt1->v_index; - } -/* if (ls->phi_moves[pred][k][0] == */ -/* lt2->v_index) { */ -/* ls->phi_moves[pred][k][0]=lt1->v_index; */ -/* } */ - } - } - } - /* change in appropriate phi_move, too */ - } else { - if (lt2->v_index >= 0) { - /* lt1&<2 are LOCALVAR, XSTORE,IINC and XLOAD */ - /* have to be changed */ - iptr = ls->basicblocks[s->b_index]->iinstr + - s->iindex; - if (iptr != NULL) { - /* no edge splitting block from SSA */ - switch(iptr->opc) { - case ICMD_ILOAD: - case ICMD_LLOAD: - case ICMD_FLOAD: - case ICMD_DLOAD: - case ICMD_ALOAD:/* iptr->op1 == USE */ - case ICMD_ISTORE: - case ICMD_LSTORE: - case ICMD_FSTORE: - case ICMD_DSTORE: - case ICMD_ASTORE: - case ICMD_IINC: /* iptr->op1 == USE */ - if (iptr->op1 == lt2->v_index) - iptr->op1 = lt1->v_index; - break; - /* default: */ - /* could be in another than the top stackslot */ - /* too! */ - /* _LT_ASSERT((iptr-1)->dst->varnum == */ - /* lt1->v_index); */ - } - } - } - /* uses in stackslots are already changed above by */ - /* renameing and copying of local_ss */ - } - } /* for(s = lt2->use; s != NULL; s = s->next) */ - if (lt2->v_index >= 0) { - /* change def site */ - _LT_ASSERT(lt2->def != NULL); - /* no SSA Anymore -> cyle through all def sites */ - /* _LT_ASSERT(lt2->def->next == NULL); */ - - for(s = lt2->def; s != NULL; s = s->next) { - if (s->iindex < 0) { - /* change phi */ - if (ls->phi[s->b_index][-s->iindex-1][0] == lt2->v_index) - ls->phi[s->b_index][-s->iindex-1][0] = lt1->v_index; - pred=graph_get_first_predecessor(gd, s->b_index, &iter); - for (; pred != -1; pred = graph_get_next(&iter)) { - /* change in appropriate phi_move, too */ - for(k=0; knum_phi_moves[pred]; k++) { - if (ls->phi_moves[pred][k][0] == - lt2->v_index) { - ls->phi_moves[pred][k][0]=lt1->v_index; - } - } - } - } else { - /* change ICMD */ - - iptr = ls->basicblocks[s->b_index]->iinstr - + s->iindex; - switch(iptr->opc) { - case ICMD_ILOAD: - case ICMD_LLOAD: - case ICMD_FLOAD: - case ICMD_DLOAD: - case ICMD_ALOAD: - case ICMD_ISTORE: - case ICMD_LSTORE: - case ICMD_FSTORE: - case ICMD_DSTORE: - case ICMD_ASTORE: /* iptr->op1 == DEF */ - if(iptr->op1 == lt2->v_index) - iptr->op1 = lt1->v_index; - break; - case ICMD_IINC: /* iptr->val._i.op1_t == DEF */ - if (iptr->val._i.op1_t == lt2->v_index) - iptr->val._i.op1_t = lt1->v_index; - break; - /* default: */ - /* could be in another than the top stackslot */ - /* too! */ - /* _LT_ASSERT((iptr->dst->varnum == lt1->v_index)); */ - } - } - } - } - - /* combine def sites (SSA is dead now)*/ - _LT_ASSERT(lt2->def != NULL); - for(s = lt2->def; s->next != NULL; s = s->next); - s->next = lt1->def; - lt1->def = lt2->def; - - /* combine use sites */ - _LT_ASSERT(lt2->use != NULL); - for(s = lt2->use; s->next != NULL; s = s->next); - s->next = lt1->use; - lt1->use = lt2->use; - - /* combine first_def and last_use */ - if (lt1->bb_first_def == lt2->bb_first_def) { - lt1->i_first_def = min(lt1->i_first_def, lt2->i_first_def); - } else if (lt1->bb_first_def > lt2->bb_first_def) { - lt1->bb_first_def = lt2->bb_first_def; - lt1->i_first_def = lt2->i_first_def; - } - if (lt1->bb_last_use == lt2->bb_last_use) { - lt1->i_last_use = max(lt1->i_last_use, lt2->i_last_use); - } else if (lt1->bb_last_use < lt2->bb_last_use) { - lt1->bb_last_use = lt2->bb_last_use; - lt1->i_last_use = lt2->i_last_use; + _LT_ASSERT(ls->basicblocks[b_index]->iinstr != NULL); + iptr = ls->basicblocks[b_index]->iinstr + iindex; + if (icmd_table[iptr->opc].flags & ICMDTABLE_CALLS) + lt->savedvar = SAVEDVAR; } - /* combine savedvar flags */ - lt1->savedvar |= lt2->savedvar; - _LT_ASSERT(lt1->type == lt2->type); - lt2->type = -1; - /* change the var in all future references of ls->igraph */ - /* TODO: do something against this!! */ -/* for(j = i + 1; j < ls->igraph_top; j++) { */ -/* if (ls->igraph[j].inter == NULL) { */ -/* for(var1 = ls->igraph[j].vars; var1 != NULL; */ -/* var1 = var1->next) { */ -/* if (var1->v == lt2->v_index) */ -/* var1->v = lt1->v_index; */ -/* } */ -/* } */ -#if 0 - /* not needed by now, since only for phi functions */ - /* with absolutely no interference is checked */ - else { - inter = ls->igraph[j].inter; - for(;inter != NULL; inter = inter->next) { - if (inter->v1 == lt2->v_index) - inter->v1 = lt1->v_index; - if (inter->v2 == lt2->v_index) - inter->v2 = lt1->v_index; - } - } -#endif -/* } */ - - /* look through all phi functions */ - for(j = 0; j < ls->basicblockcount; j++) { - for(k = 0; k < ls->max_vars; k++) { - if (ls->phi[j][k] != NULL) { - if (ls->phi[j][k][0] == lt2->v_index) - ls->phi[j][k][0] = lt1->v_index; - for (l = 1; l < graph_get_num_predecessor(gd, j); l++) { - if (ls->phi[j][k][l] == lt2->v_index) - ls->phi[j][k][l] = lt1->v_index; - } - } - } - /* change in phi move, too */ - for(k = 0; k < ls->num_phi_moves[j]; k++) { - if (ls->phi_moves[j][k][1] == lt2->v_index) - ls->phi_moves[j][k][1] = lt1->v_index; - if (ls->phi_moves[j][k][0] == lt2->v_index) - ls->phi_moves[j][k][0] = lt1->v_index; - } - } - } /* for(var = ls->igraph[i].vars; var != NULL; var = var->next) */ - } /* if (ls->igraph[i].inter == NULL) */ - } /* for(i = 0; i < ls->igraph_top; i++) */ - } + /* lt stays life-in at statement */ + + life_in = true; + } else { + + /* print LO verbose message only for phi functions, which */ + /* define this var */ + +#ifdef LT_DEBUG_VERBOSE + if ((compileverbose) && (iindex < 0)) + printf("LO@ST: vi %3i bi %3i ii %3i\n", + lt->v_index, b_index, iindex); + if ((compileverbose)) + printf("--> definition\n"); #endif -} -void LifeOutAtBlock(lsradata *ls, graphdata *gd, int *M, int n, - struct lifetime *lt) { - /* lt->v_index is life at Block n */ - if (!bv_get_bit(M,n)) { /* n no Element of M */ - bv_set_bit(M,n); + lt_is_live(ls, lt, b_index, iindex); - /* lt->v_index is life at last Statement of n */ - if (n != 0) { - int i; - i = ls->basicblocks[n]->icount - 1; - for (;((i>0) && (ls->basicblocks[n]->iinstr+i == ICMD_NOP)); i--); - LifeOutAtStatement(ls, gd, M, n, i,lt); + /* Stop - lt is defined and not life before this instruction */ + + break; + } } - else - LifeOutAtStatement(ls, gd, M, n, 0, lt); - } -} -void LifeInAtStatement(lsradata *ls, graphdata *gd, int *M, int b_index, - int iindex, struct lifetime *lt) { - /* lt->v_index is live-in at s */ - int prev_iindex; /* Statement before iindex */ - int pred; - graphiterator pred_iter; + if (life_in) { + + /* lt->v_index is live-in at statement (b_index,iindex) */ - lt_is_live(ls, lt, b_index, iindex); - - prev_iindex = iindex - 1; - if (prev_iindex < 0) - /* look through phi functions */ - for(; prev_iindex > -ls->max_vars-1; - prev_iindex--) - if (ls->phi[b_index][-prev_iindex-1] != NULL) - break; +#ifdef LT_DEBUG_VERBOSE + if ((compileverbose) && (iindex >= 0)) + printf("LI@ST: vi %3i bi %3i ii %3i\n", + lt->v_index, b_index, iindex); +#endif - if (iindex == -ls->max_vars-1) { - /* iindex is the first statement of b_index */ - /* Statements -ls->max_vars-1 .. -1 are possible phi functions */ - /* lt->v_index is live-in at b_index */ - - pred = graph_get_first_predecessor(gd, b_index, &pred_iter); - for(; pred != -1; pred = graph_get_next(&pred_iter)) - LifeOutAtBlock(ls, gd, M, pred, lt); - } else - LifeOutAtStatement(ls, gd, M, b_index, prev_iindex, lt); -} + lt_is_live(ls, lt, b_index, iindex); -void LifeOutAtStatement(lsradata *ls, graphdata *gd, int *M, int b_index, - int iindex, struct lifetime *lt) { - instruction *iptr; - int igraph_index; - int var; - /* lt->v_index is life-out at s */ - /* for each variable w defined at s except v=lt->v_index, add a edge */ - /* (v,w) to the interference graph, once one is needed */ + if (iindex == -ls->varcount-1) { -#if defined(JOIN_PHI_LT) - /* Build interference Graph for variables involved in phi functions */ - /* it is essential, that these variables get merged, if possible! */ - build_interference(ls, b_index, iindex, lt); +#ifdef LT_DEBUG_VERBOSE + if ((compileverbose)) + printf("LI@ST: vi %3i bi %3i ii %3i\n", + lt->v_index, b_index, iindex); #endif - if (!v_is_defined_at_s(ls, b_index, iindex, lt)) { - /* v is life in at out of statement -> check if the SAVEDVAR */ - /* flag is needed to be set */ - if ((iindex >= 0) && (b_index != 0)) { - /* real ICMD */ - _LT_ASSERT(ls->basicblocks[b_index]->iinstr != NULL); - iptr = ls->basicblocks[b_index]->iinstr + iindex; - if (icmd_table[iptr->opc].flags & ICMDTABLE_CALLS) - lt->savedvar = SAVEDVAR; - } - LifeInAtStatement(ls, gd, M, b_index, iindex, lt); - } else - lt_is_live(ls, lt, b_index, iindex); -} + /* iindex is the first statement of b_index */ + /* Statements -ls->max_vars-1 .. -1 are possible phi functions*/ + /* lt->v_index is live-in at b_index */ + + pred = graph_get_first_predecessor(gd, b_index, &pred_iter); -struct stackslot *lsra_make_ss(stackptr s, int bb_index) -{ - struct stackslot *ss; + /* Add "Life out Basic Blocks to Worklist */ - ss=DNEW(struct stackslot); - ss->bb=bb_index; - ss->s=s; - return ss; -} + for(; pred != -1; pred = graph_get_next(&pred_iter)) + wl_add(W, pred); -void lsra_add_ss(struct lifetime *lt, stackptr s) { - struct stackslot *ss; - bool insert_s; - /* Stackslot noch nicht eingetragen? */ + /* Stop here - beginning of Basic Block reached */ - insert_s = true; + break; + } else { - for (ss = lt->local_ss; (!insert_s) && (ss != NULL); ss = ss->next) - insert_s = (ss->s == s); - + prev_iindex = iindex - 1; + if (prev_iindex < 0) - /* local_ss == NULL -> stack lt was set in ssa -> create Stack entry */ - if ((lt->local_ss == NULL) || (insert_s)) { - ss = DNEW(struct stackslot); - ss->s = s; - ss->s->varnum = lt->v_index; - ss->next = lt->local_ss; - lt->local_ss = ss; - if (s != NULL) lt->savedvar |= s->flags & SAVEDVAR; - if (s != NULL) lt->type = s->type; - } + /* look through phi functions */ + + for(; prev_iindex > -ls->varcount-1; prev_iindex--) + if (ls->phi[b_index][-prev_iindex-1] != NULL) + break; + + /* lt is live out at instruction prev_iindex */ + + iindex = prev_iindex; + life_in = false; + } + } + } } -void move_stackslots(struct lifetime *from, struct lifetime *to) { - struct stackslot *ss; - - if (from->local_ss == NULL) - /* nothing to move */ - return; - for(ss = from->local_ss; ss->next != NULL; ss = ss->next); +void lt_lifeoutatblock(lsradata *ls, graphdata *gd, int *M, int b_index, + struct lifetime *lt, worklist *W) { + +#if defined(LT_DEBUG_VERBOSE) + if (compileverbose) { + printf("V %3i LO at BB %3i\n",lt->v_index, b_index); + } +#endif + + /* lt->v_index is life out of Block b_index */ + if (!bv_get_bit(M, b_index)) { /* BB b_index not visited till now */ + bv_set_bit(M, b_index); - ss->next = to->local_ss; - to->local_ss = from->local_ss; - from->local_ss = NULL; + /* lt->v_index is life out of last Statement of b_index */ + + if (b_index != 0) { + int i; + i = ls->basicblocks[b_index]->icount - 1; + for (;((i>0) && (ls->basicblocks[b_index]->iinstr+i == ICMD_NOP)); + i--); + lt_lifeatstatement(ls, gd, b_index, i, lt, false, W); + } + else + lt_lifeatstatement(ls, gd, b_index, 0, lt, false, W); + } } -void move_use_sites(struct lifetime *from, struct lifetime *to) { + +void lt_move_use_sites(struct lifetime *from, struct lifetime *to) { struct site *s; _LT_ASSERT(from->use != NULL); @@ -1074,7 +588,7 @@ void move_use_sites(struct lifetime *from, struct lifetime *to) { from->use = NULL; } -void add_use_site(struct lifetime *lt, int block, int iindex) { +void lt_add_use_site(struct lifetime *lt, int block, int iindex) { struct site *n; n = DNEW(struct site); @@ -1085,22 +599,28 @@ void add_use_site(struct lifetime *lt, int block, int iindex) { /* CFG is analysed from the end to the start -> so first found use site */ /* is the last use of the Local Var */ + if (lt->last_use == NULL) lt->last_use = n; } -void remove_use_site(struct lifetime *lt, int block, int iindex) { +void lt_remove_use_site(struct lifetime *lt, int block, int iindex) { struct site *n; /* check lt->use itself */ + if ((lt->use->b_index == block) && (lt->use->iindex == iindex)) { /* found */ lt->use = lt->use->next; } else { + /* look through list */ + for (n = lt->use; (n->next != NULL) && ((n->next->b_index != block) || (n->next->iindex != iindex)); n = n->next); + /* assert, that lt was found */ + _LT_ASSERT(n->next != NULL); _LT_ASSERT(n->next->b_index == block); _LT_ASSERT(n->next->iindex == iindex); @@ -1109,10 +629,11 @@ void remove_use_site(struct lifetime *lt, int block, int iindex) { } } -void add_def_site(struct lifetime *lt, int block, int iindex) { +void lt_add_def_site(struct lifetime *lt, int block, int iindex) { struct site *n; /* SSA <-> only one definition per lifetime! */ + _LT_ASSERT(lt->def == NULL); n = DNEW(struct site); n->b_index = block; @@ -1121,101 +642,22 @@ void add_def_site(struct lifetime *lt, int block, int iindex) { lt->def = n; } -struct lifetime *get_ss_lifetime(lsradata *ls, stackptr s) { - struct lifetime *n; - - if (s->varnum >= 0) { /* new stackslot lifetime */ - if (-ls->v_index - 1 >= ls->maxlifetimes) { - printf("%i %i\n", -ls->v_index - 1, ls->maxlifetimes); - } - _LT_ASSERT(-ls->v_index - 1 < ls->maxlifetimes); - - n = &(ls->lifetime[-ls->v_index - 1]); - n->type = s->type; - n->v_index = ls->v_index--; - n->usagecount = 0; - - n->bb_last_use = -1; - n->bb_first_def = -1; - n->local_ss = NULL; - n->savedvar = 0; - n->flags = 0; - - n->use = NULL; - n->def = NULL; - n->last_use = NULL; - } else { - _LT_ASSERT(-s->varnum - 1 < ls->maxlifetimes); - n = &(ls->lifetime[-s->varnum - 1]); - } - - lsra_add_ss( n, s); - return n; -} - -#define lsra_new_stack(ls, s, block, instr) \ - if ((s)->varkind != ARGVAR) _lsra_new_stack(ls, s, block, instr, LSRA_STORE) -void _lsra_new_stack(lsradata *ls, stackptr s, int block, int instr, int store) -{ - struct lifetime *n; - - if (s->varkind == LOCALVAR) { -/* _LT_ASSERT(0); */ - lsra_usage_local(ls, s->varnum, s->type, block, instr, LSRA_LOAD); - } else { - - - n=get_ss_lifetime( ls, s ); - if (store == LSRA_STORE) { - /* for LSRA_BB_[IN|OUT] do not add a def site, just add s to */ - /* local_ss */ - add_def_site(n, block, instr); - } - } -} - -#define lsra_from_stack(ls, s, block, instr) \ - if ((s)->varkind != ARGVAR) _lsra_from_stack(ls, s, block, instr, LSRA_LOAD) -#define lsra_pop_from_stack(ls, s, block, instr) \ - if ((s)->varkind != ARGVAR) _lsra_from_stack(ls, s, block, instr, LSRA_POP) -void _lsra_from_stack(lsradata *ls, stackptr s, int block, int instr, int store) -{ - struct lifetime *n; - - if (s->varkind == LOCALVAR) { -/* _LT_ASSERT(0); */ - lsra_usage_local(ls, s->varnum, s->type, block, instr, LSRA_LOAD); - } else /* if (s->varkind != ARGVAR) */ { - if (s->varkind == STACKVAR ) { -/* _LT_ASSERT(0); */ - printf("---------STACKVAR left over! \n"); - /* No STACKVARS possible with lsra! */ - s->varkind = TEMPVAR; - } - } - - n=get_ss_lifetime( ls, s ); - - /* LSRA_POP -> invalidate Stackslot ?! */ -#ifdef USAGE_COUNT - n->usagecount += ls->nesting[block]; -#endif - - add_use_site(n, block, instr); - -} - -void lsra_usage_local(lsradata *ls, s4 v_index, int type, int block, int instr, +void lt_usage(jitdata *jd,s4 v_index, int block, int instr, int store) { struct lifetime *n; + lsradata *ls; + + ls = jd->ls; - n = &(ls->lifetime[ls->maxlifetimes + v_index]); + n = ls->lifetime + v_index; if (n->type == -1) { /* new local lifetime */ - n->local_ss=NULL; + _LT_ASSERT(0); n->v_index=v_index; - n->type=type; + n->type=VAR(v_index)->type; + /* TODO: check!!!! */ + /* All var are SAVEDVARS or this gets reset afterwards???? */ n->savedvar = SAVEDVAR; n->flags = 0; n->usagecount = 0; @@ -1227,20 +669,21 @@ void lsra_usage_local(lsradata *ls, s4 v_index, int type, int block, int instr, n->def = NULL; n->last_use = NULL; } - _LT_ASSERT(type == n->type); + _LT_ASSERT(VAR(v_index)->type == n->type); /* add access at (block, instr) to instruction list */ /* remember last USE, so only write, if USE Field is undefined (==-1) */ /* count store as use, too -> defined and not used vars would overwrite */ /* other vars */ - if (store == LSRA_LOAD) { + + if (store == LT_USE) { #ifdef USAGE_COUNT n->usagecount += ls->nesting[block]; #endif - add_use_site(n, block, instr); + lt_add_use_site(n, block, instr); } - if (store == LSRA_STORE) { - add_def_site(n, block, instr); + if (store == LT_DEF) { + lt_add_def_site(n, block, instr); } } @@ -1248,124 +691,67 @@ void lsra_usage_local(lsradata *ls, s4 v_index, int type, int block, int instr, use sites: dead code elemination, LifenessAnalysis def sites: dead code elemination ***************************************************************************/ -void _scan_lifetimes(registerdata *rd, lsradata *ls, graphdata *gd, - basicblock *bptr) +void _lt_scanlifetimes(jitdata *jd, graphdata *gd, basicblock *bptr, + int b_index) { /* methodinfo *lm; */ builtintable_entry *bte; methoddesc *md; int i, j, t, v; - int opcode; - int iindex, b_index; - stackptr src; - stackptr dst; + int iindex/*, b_index*/; instruction *iptr; - - struct lifetime *lt; + s4 *argp; + + lsradata *ls; + + ls = jd->ls; +#ifdef LT_DEBUG_VERBOSE + if (compileverbose) + printf("_lt_scanlifetimes: BB %3i flags %3i\n", b_index, bptr->flags); +#endif if (bptr->flags >= BBREACHED) { - b_index = bptr->nr; +/* b_index = bptr->nr; */ /* get instruction count for BB */ + iindex = bptr->icount - 1; - /* regard not setup new BB with maybee just in and outstack */ - if (iindex < 0) iindex = 0; + + /* regard not setup new BB with maybe just in and outstack */ + + if (iindex < 0) + iindex = 0; /* Regard phi_functions (Definition of target, Use of source) */ - for(i = 0; i < ls->max_vars; i++) { + + for(i = 0; i < ls->ssavarcount; i++) { if (ls->phi[b_index][i] != NULL) { /* Phi Function for var i at b_index exists */ v = ls->phi[b_index][i][0]; - _LT_ASSERT( v != ls->max_vars_with_indices); - if (v >= 0) { - /* Local Var */ - for(t = 0;(t < 5) && (rd->locals[v][t].type==-1); t++); - _LT_ASSERT(t != 5); - /* Add definition of target add - phi index -1*/ - lsra_usage_local(ls, v, t, b_index, -i-1, - LSRA_STORE); - /* Add Use of sources */ - for (j = 1; j <= graph_get_num_predecessor(gd, b_index); - j++) { - if (ls->phi[b_index][i][j] != ls->max_vars_with_indices) - lsra_usage_local(ls, ls->phi[b_index][i][j], t, - b_index, -i-1, LSRA_LOAD); - } - } else { - /* Interface Stackslot */ - /* Add definition of target */ - lt = &(ls->lifetime[-v-1]); - add_def_site(lt, b_index, -i-1); - /* add use of sources */ - for (j = 1; j <= graph_get_num_predecessor(gd, b_index); - j++) { - if (ls->phi[b_index][i][j] != ls->max_vars_with_indices) - { - lt = &(ls->lifetime[-ls->phi[b_index][i][j]-1]); - add_use_site(lt, b_index, -i-1); - } - } + _LT_ASSERT( v != ls->varcount_with_indices); + t = VAR(i)->type; + + /* Add definition of target add - phi index -1*/ +#ifdef LT_DEBUG_VERBOSE + if (compileverbose) + printf("_lt_scanlifetimes: phi_def: v: %3i\n i: %3i\n", + v, -i-1); +#endif + lt_usage(jd, v, b_index, -i-1, LT_DEF); + + /* Add Use of sources */ + + for (j = 1; j <= graph_get_num_predecessor(gd, b_index); j++) { + if (ls->phi[b_index][i][j] != ls->varcount_with_indices) + if (ls->phi[b_index][i][j] != UNUSED) + lt_usage(jd, ls->phi[b_index][i][j], b_index, + -i-1, LT_USE); } } } - src = bptr->instack; - if (bptr->type != BBTYPE_STD) { -#ifdef LT_DEBUG_CHECK - if (src == NULL) { - log_text("No Incoming Stackslot for Exception/Subroutine BB\n"); - _LT_ASSERT(0); - } -#endif - _LT_ASSERT(src != NULL); - lsra_new_stack(ls, src, b_index, 0); - if (src->varkind == STACKVAR) - src->varkind = TEMPVAR; - src = src->prev; - } - for (;src != NULL; src=src->prev) { - /* no ARGVAR possible at BB Boundaries with LSRA! */ - /* -> change to TEMPVAR */ - - if (src->varkind == ARGVAR ) { - src->varkind = TEMPVAR; - /* On Architectures with own return registers a return */ - /* stackslot is marked as varkind=ARGVAR with varnum=-1 */ - /* but for lsra a varkind==TEMPVAR, varnum=-1 would mean, */ - /* that already a lifetime was allocated! */ - if (src->varnum < 0) src->varnum = 0; - } - else if (src->varkind == LOCALVAR ) - /* only allowed for topmost ss at sbr or exh entries! */ - { log_text("LOCALVAR at basicblock instack\n"); exit(1); } - else { - /* no Interfaces (STACKVAR) at BB Boundaries with LSRA! */ - /* -> change to TEMPVAR */ - if (src->varkind == STACKVAR ) - src->varkind = TEMPVAR; -/* _lsra_new_stack(ls, src, b_index, 0, LSRA_BB_IN); */ - _lsra_from_stack(ls, src, b_index, 0, LSRA_BB_OUT); - } - } - /* Should not be necessary to check out stackslots, too */ - /* either they are identical to the instacks or handled */ - /* by their phi functions */ - src = bptr->outstack; - for (;src != NULL; src=src->prev) { - if (src->varkind == ARGVAR ) - { log_text("ARGVAR at basicblock outstack\n"); exit(1); } - else if (src->varkind == LOCALVAR ) - { log_text("LOCALVAR at basicblock outstack\n"); exit(1); } - else { - /* no Interfaces at BB Boundaries with LSRA! */ - /* -> change to TEMPVAR */ - if (src->varkind == STACKVAR ) - src->varkind = TEMPVAR; -/* _lsra_from_stack(ls, src, b_index, iindex, LSRA_BB_OUT); */ - } - } if (bptr->iinstr != NULL) { /* set iptr to last instruction of BB */ @@ -1374,531 +760,66 @@ void _scan_lifetimes(registerdata *rd, lsradata *ls, graphdata *gd, iindex = -1; for (;iindex >= 0; iindex--, iptr--) { - /* Get source and destination Stack for the current */ - /* instruction. Destination stack is available as iptr->dst */ - dst = iptr->dst; - /* source stack is either the destination stack of the previos*/ - /* instruction, or the basicblock instack for the */ - /* first instruction */ - if (iindex) /* != 0 is > 0 here, since iindex ist always >= 0 */ - src=(iptr-1)->dst; - else - src=bptr->instack; - - opcode = iptr->opc; - switch (opcode) { - - /* pop 0 push 0 */ - case ICMD_RET: - /* local read (return adress) */ - lsra_usage_local(ls, iptr->op1, TYPE_ADR, b_index, iindex, - LSRA_LOAD); - break; - case ICMD_NOP: -/* case ICMD_ELSE_ICONST: */ - case ICMD_CHECKNULL: - case ICMD_JSR: - case ICMD_RETURN: - case ICMD_GOTO: - case ICMD_PUTSTATICCONST: - case ICMD_INLINE_START: - case ICMD_INLINE_END: - case ICMD_INLINE_GOTO: - break; - - case ICMD_IINC: - /* local = local+ */ - lsra_usage_local(ls, iptr->op1, TYPE_INT, b_index, iindex, - LSRA_LOAD); - lsra_usage_local(ls, iptr->val._i.op1_t, TYPE_INT, b_index, - iindex, LSRA_STORE); - break; + i = UNUSED; + v = UNUSED; - /* pop 0 push 1 const: const->stack */ - case ICMD_ICONST: - case ICMD_LCONST: - case ICMD_FCONST: - case ICMD_DCONST: - case ICMD_ACONST: - /* new stack slot */ - lsra_new_stack(ls, dst, b_index, iindex); - break; - - /* pop 0 push 1 load: local->stack */ - case ICMD_ILOAD: - case ICMD_LLOAD: - case ICMD_FLOAD: - case ICMD_DLOAD: - case ICMD_ALOAD: - if (dst->varkind != LOCALVAR) { - /* local->value on stack */ - lsra_usage_local(ls, iptr->op1, opcode - ICMD_ILOAD, - b_index, iindex, LSRA_LOAD); - lsra_new_stack(ls, dst, b_index, iindex); - } else /* if (dst->varnum != iptr->op1) */ { - /* local -> local */ - lsra_usage_local(ls, iptr->op1, opcode - ICMD_ILOAD, - b_index, iindex,LSRA_LOAD); - lsra_usage_local(ls, dst->varnum, opcode - ICMD_ILOAD, - b_index, iindex, LSRA_STORE); - } - - break; - - /* pop 2 push 1 */ - /* Stack(arrayref,index)->stack */ - case ICMD_IALOAD: - case ICMD_LALOAD: - case ICMD_FALOAD: - case ICMD_DALOAD: - case ICMD_AALOAD: - - case ICMD_BALOAD: - case ICMD_CALOAD: - case ICMD_SALOAD: - /* stack->index */ - lsra_from_stack(ls, src, b_index, iindex); - /* stack->arrayref */ - lsra_from_stack(ls, src->prev, b_index, iindex); - /* arrayref[index]->stack */ - lsra_new_stack(ls, dst, b_index, iindex); - break; - - /* pop 3 push 0 */ - /* stack(arrayref,index,value)->arrayref[index]=value */ - case ICMD_IASTORE: - case ICMD_LASTORE: - case ICMD_FASTORE: - case ICMD_DASTORE: - case ICMD_AASTORE: - - case ICMD_BASTORE: - case ICMD_CASTORE: - case ICMD_SASTORE: - - lsra_from_stack(ls, src,b_index, iindex); - lsra_from_stack(ls, src->prev, b_index, iindex); - lsra_from_stack(ls, src->prev->prev, b_index, iindex); - break; - - /* pop 1 push 0 store: stack -> local */ - case ICMD_ISTORE: - case ICMD_LSTORE: - case ICMD_FSTORE: - case ICMD_DSTORE: - case ICMD_ASTORE: - if (src->varkind != LOCALVAR) { - lsra_from_stack(ls, src, b_index, iindex); - lsra_usage_local(ls, iptr->op1, opcode-ICMD_ISTORE, - b_index, iindex, LSRA_STORE); - } else /* if (src->varnum != iptr->op1) */ { - lsra_usage_local(ls, iptr->op1, opcode-ICMD_ISTORE, - b_index, iindex, LSRA_STORE); - lsra_usage_local(ls, src->varnum, opcode-ICMD_ISTORE, - b_index, iindex, LSRA_LOAD); - } - break; + if (icmd_table[iptr->opc].dataflow >= DF_DST_BASE) + v = iptr->dst.varindex; - /* pop 1 push 0 */ - case ICMD_POP: /* throw away a stackslot */ - /* TODO: check if used anyway (DUP...) and change codegen */ - /* to ignore this stackslot */ -#if 0 - lsra_pop_from_stack(ls, src, b_index, iindex); -#endif - break; - - /* pop 1 push 0 */ - case ICMD_IRETURN: - case ICMD_LRETURN: - case ICMD_FRETURN: - case ICMD_DRETURN: - case ICMD_ARETURN: /* stack(value) -> [empty] */ - - case ICMD_ATHROW: /* stack(objref) -> undefined */ - - case ICMD_PUTSTATIC: /* stack(value) -> static_field */ - case ICMD_PUTFIELDCONST: - - /* pop 1 push 0 branch */ - case ICMD_IFNULL: /* stack(value) -> branch? */ - case ICMD_IFNONNULL: - - case ICMD_IFEQ: - case ICMD_IFNE: - case ICMD_IFLT: - case ICMD_IFGE: - case ICMD_IFGT: - case ICMD_IFLE: - - case ICMD_IF_LEQ: - case ICMD_IF_LNE: - case ICMD_IF_LLT: - case ICMD_IF_LGE: - case ICMD_IF_LGT: - case ICMD_IF_LLE: - - /* pop 1 push 0 table branch */ - case ICMD_TABLESWITCH: - case ICMD_LOOKUPSWITCH: - - case ICMD_MONITORENTER: - case ICMD_MONITOREXIT: - lsra_from_stack(ls, src, b_index, iindex); - break; - - /* pop 2 push 0 */ - case ICMD_POP2: /* throw away 2 stackslots */ -#if 0 - /* TODO: check if used anyway (DUP...) and change codegen */ - /* to ignore this stackslot */ - lsra_pop_from_stack(ls, src, b_index, iindex); - lsra_pop_from_stack(ls, src->prev, b_index, iindex); -#endif - break; - - /* pop 2 push 0 branch */ - - case ICMD_IF_ICMPEQ: /* stack (v1,v2) -> branch(v1,v2) */ - case ICMD_IF_ICMPNE: - case ICMD_IF_ICMPLT: - case ICMD_IF_ICMPGE: - case ICMD_IF_ICMPGT: - case ICMD_IF_ICMPLE: - - case ICMD_IF_LCMPEQ: - case ICMD_IF_LCMPNE: - case ICMD_IF_LCMPLT: - case ICMD_IF_LCMPGE: - case ICMD_IF_LCMPGT: - case ICMD_IF_LCMPLE: - - case ICMD_IF_ACMPEQ: - case ICMD_IF_ACMPNE: - - /* pop 2 push 0 */ - case ICMD_PUTFIELD: /* stack(objref,value) -> objref = value */ - - case ICMD_IASTORECONST: - case ICMD_LASTORECONST: - case ICMD_AASTORECONST: - case ICMD_BASTORECONST: - case ICMD_CASTORECONST: - case ICMD_SASTORECONST: - lsra_from_stack(ls, src, b_index, iindex); - lsra_from_stack(ls, src->prev, b_index, iindex); - break; + /* check for use (s1, s2, s3 or special (argp) ) */ + /* and definitions (dst) */ + switch(icmd_table[iptr->opc].dataflow) { + case DF_3_TO_0: + case DF_3_TO_1: /* icmd has s1, s2 and s3 */ + lt_usage(jd, iptr->sx.s23.s3.varindex, b_index, iindex, LT_USE); - /* pop 0 push 1 dup */ - case ICMD_DUP: - /* src == dst->prev */ - /* ---------------- */ - /* src -> dst */ + /* now "fall through" for handling of s2 and s1 */ - /* Add the use site for src==dst */ - lsra_from_stack(ls, src, b_index, iindex); + case DF_2_TO_0: + case DF_2_TO_1: /* icmd has s1 and s2 */ + lt_usage(jd, iptr->sx.s23.s2.varindex, b_index, iindex, LT_USE); - lsra_new_stack(ls, dst, b_index, iindex); + /* now "fall through" for handling of s1 */ + case DF_1_TO_0: + case DF_1_TO_1: + case DF_MOVE: + case DF_COPY: /* icmd has s1 */ + lt_usage(jd, iptr->s1.varindex, b_index, iindex, LT_USE); break; - /* pop 0 push 2 dup */ - case ICMD_DUP2: - /* src == dst->prev->prev */ - /* src->prev == dst->prev->prev->prev */ - /* ---------------- */ - /* src -> dst */ - /* src->prev -> dst->prev */ - /* src & src->prev "continue" living -> so no conflicts */ - /* with dst and dst->prec possible */ - - /* add the use site for src == dst->prev->prev */ - lsra_from_stack(ls, src, b_index, iindex); - /* add the use site for src->prev == dst->prev->prev->prev */ - lsra_from_stack(ls, src->prev, b_index, iindex); - - - lsra_new_stack(ls, dst->prev, b_index, iindex); - lsra_new_stack(ls, dst, b_index, iindex); - - break; - - /* pop 2 push 3 dup */ - case ICMD_DUP_X1: - /* src -> dst */ - /* src->prev -> dst->prev */ - /* src -> dst->prev->prev */ - /* !!!!!!!!!!!!!!!!!!!!!!!!!!!! */ - /* Copy Conflicts possible! */ - /* -> instack [ t1 t0 ] */ - /* -> outstack[ t0 t1 t3 ] */ - /* -> t1->t0, t0->t1, t1->t3 !! */ - /* -> Remove src->prev on iindex+1 instead of iindex! */ - lsra_from_stack(ls, src, b_index, iindex); - lsra_from_stack(ls, src->prev, b_index, iindex); - lsra_new_stack(ls, dst->prev->prev, b_index, iindex); - lsra_new_stack(ls, dst->prev, b_index, iindex); - lsra_new_stack(ls, dst, b_index, iindex); - - break; - - /* pop 3 push 4 dup */ - case ICMD_DUP_X2: - /* src -> dst */ - /* src -> dst->prev->prev->prev */ - /* src->prev -> dst->prev */ - /* src->prev->prev -> dst->prev->prev */ - /* Conflicts possible! -> remove srces at iindex + 1 */ - lsra_from_stack(ls, src,b_index, iindex); - lsra_from_stack(ls, src->prev, b_index, iindex); - lsra_from_stack(ls, src->prev->prev, b_index, iindex); - lsra_new_stack(ls, dst->prev->prev->prev, b_index, iindex); - lsra_new_stack(ls, dst->prev->prev, b_index, iindex); - lsra_new_stack(ls, dst->prev, b_index, iindex); - lsra_new_stack(ls, dst, b_index, iindex); - - break; - - /* pop 3 push 5 dup */ - case ICMD_DUP2_X1: - /* src -> dst */ - /* src -> dst->prev->prev->prev */ - /* src->prev -> dst->prev->prev->prev->prev */ - /* src->prev -> dst->prev */ - /* src->prev->prev -> dst->prev->prev */ - /* Conflicts possible! -> remove srces at iindex + 1 */ - lsra_from_stack(ls, src, b_index, iindex); - lsra_from_stack(ls, src->prev, b_index, iindex); - lsra_from_stack(ls, src->prev->prev, b_index, iindex); - lsra_new_stack(ls, dst->prev->prev->prev->prev, b_index, - iindex); - lsra_new_stack(ls, dst->prev->prev->prev, b_index, iindex); - lsra_new_stack(ls, dst->prev->prev, b_index, iindex); - lsra_new_stack(ls, dst->prev, b_index, iindex); - lsra_new_stack(ls, dst, b_index, iindex); - - - break; - - /* pop 4 push 6 dup */ - case ICMD_DUP2_X2: - /* src -> dst */ - /* src -> dst->prev->prev->prev->prev */ - /* src->prev -> dst->prev->prev->prev->prev->prev */ - /* src->prev -> dst->prev */ - /* src->prev->prev -> dst->prev->prev */ - /* src->prev->prev->prev -> dst->prev->prev->prev */ - /* Conflicts possible! -> remove srcs at iindex + 1 */ - lsra_from_stack(ls, src, b_index, iindex); - lsra_from_stack(ls, src->prev, b_index, iindex); - lsra_from_stack(ls, src->prev->prev, b_index, iindex); - lsra_from_stack(ls, src->prev->prev->prev, b_index, iindex); - lsra_new_stack(ls, dst->prev->prev->prev->prev->prev, - b_index, iindex); - lsra_new_stack(ls, dst->prev->prev->prev->prev, b_index, - iindex); - lsra_new_stack(ls, dst->prev->prev->prev, b_index, iindex); - lsra_new_stack(ls, dst->prev->prev, b_index, iindex); - lsra_new_stack(ls, dst->prev, b_index, iindex); - lsra_new_stack(ls, dst, b_index, iindex); - - break; - - /* pop 2 push 2 swap */ - case ICMD_SWAP: - /* src -> dst->prev */ - /* src->prev -> dst */ - /* Conflicts possible -> remove src at iindex + 1 */ - lsra_from_stack(ls, src, b_index, iindex); - lsra_from_stack(ls, src->prev, b_index, iindex); - lsra_new_stack(ls, dst->prev, b_index, iindex); - lsra_new_stack(ls, dst, b_index, iindex); - break; - - /* pop 2 push 1 */ - - case ICMD_LADD: - case ICMD_LSUB: - case ICMD_LMUL: - - case ICMD_LOR: - case ICMD_LAND: - case ICMD_LXOR: - - case ICMD_LSHL: - case ICMD_LSHR: - case ICMD_LUSHR: - - case ICMD_IADD: - case ICMD_IMUL: - - case ICMD_ISHL: - case ICMD_ISHR: - case ICMD_IUSHR: - case ICMD_IAND: - case ICMD_IOR: - case ICMD_IXOR: - - - case ICMD_FADD: - case ICMD_FSUB: - case ICMD_FMUL: - - case ICMD_DADD: - case ICMD_DSUB: - case ICMD_DMUL: - case ICMD_DDIV: - case ICMD_DREM: - lsra_from_stack(ls, src, b_index, iindex); - lsra_from_stack(ls, src->prev, b_index, iindex); - lsra_new_stack(ls, dst, b_index, iindex); - break; - - case ICMD_ISUB: - lsra_from_stack(ls, src, b_index, iindex); - lsra_from_stack(ls, src->prev,b_index,iindex); - lsra_new_stack(ls, dst, b_index, iindex); - break; - - case ICMD_LDIV: - case ICMD_LREM: - - case ICMD_IDIV: - case ICMD_IREM: - - case ICMD_FDIV: - case ICMD_FREM: - - case ICMD_LCMP: - case ICMD_FCMPL: - case ICMD_FCMPG: - case ICMD_DCMPL: - case ICMD_DCMPG: - lsra_from_stack(ls, src, b_index, iindex); - lsra_from_stack(ls, src->prev, b_index, iindex); - lsra_new_stack(ls, dst, b_index, iindex); - break; - - /* pop 1 push 1 */ - case ICMD_LADDCONST: - case ICMD_LSUBCONST: - case ICMD_LMULCONST: - case ICMD_LMULPOW2: - case ICMD_LDIVPOW2: - case ICMD_LREMPOW2: - case ICMD_LANDCONST: - case ICMD_LORCONST: - case ICMD_LXORCONST: - case ICMD_LSHLCONST: - case ICMD_LSHRCONST: - case ICMD_LUSHRCONST: - - case ICMD_IADDCONST: - case ICMD_ISUBCONST: - case ICMD_IMULCONST: - case ICMD_IMULPOW2: - case ICMD_IDIVPOW2: - case ICMD_IREMPOW2: - case ICMD_IANDCONST: - case ICMD_IORCONST: - case ICMD_IXORCONST: - case ICMD_ISHLCONST: - case ICMD_ISHRCONST: - case ICMD_IUSHRCONST: - -/* case ICMD_IFEQ_ICONST: */ -/* case ICMD_IFNE_ICONST: */ -/* case ICMD_IFLT_ICONST: */ -/* case ICMD_IFGE_ICONST: */ -/* case ICMD_IFGT_ICONST: */ -/* case ICMD_IFLE_ICONST: */ - - case ICMD_INEG: - case ICMD_INT2BYTE: - case ICMD_INT2CHAR: - case ICMD_INT2SHORT: - case ICMD_LNEG: - case ICMD_FNEG: - case ICMD_DNEG: - - case ICMD_I2L: - case ICMD_I2F: - case ICMD_I2D: - case ICMD_L2I: - case ICMD_L2F: - case ICMD_L2D: - case ICMD_F2I: - case ICMD_F2L: - case ICMD_F2D: - case ICMD_D2I: - case ICMD_D2L: - case ICMD_D2F: - - case ICMD_CHECKCAST: - lsra_from_stack(ls, src, b_index, iindex); - lsra_new_stack(ls, dst, b_index, iindex); - break; - - case ICMD_ARRAYLENGTH: - case ICMD_INSTANCEOF: - - case ICMD_NEWARRAY: - case ICMD_ANEWARRAY: - - case ICMD_GETFIELD: - lsra_from_stack(ls, src, b_index, iindex); - lsra_new_stack(ls, dst, b_index, iindex); - break; - - /* pop 0 push 1 */ - case ICMD_GETSTATIC: - - case ICMD_NEW: - lsra_new_stack(ls, dst, b_index, iindex); - break; - - /* pop many push any */ - - case ICMD_INVOKESTATIC: - case ICMD_INVOKESPECIAL: - case ICMD_INVOKEVIRTUAL: - case ICMD_INVOKEINTERFACE: + case DF_INVOKE: INSTRUCTION_GET_METHODDESC(iptr,md); i = md->paramcount; - while (--i >= 0) { - lsra_from_stack(ls, src, b_index, iindex); - src = src->prev; - } - if (md->returntype.type != TYPE_VOID) - lsra_new_stack(ls, dst, b_index, iindex); + if (md->returntype.type == TYPE_VOID) + v = UNUSED; break; - case ICMD_BUILTIN: - bte = iptr->val.a; + case DF_BUILTIN: + bte = iptr->sx.s23.s3.bte; md = bte->md; i = md->paramcount; - while (--i >= 0) { - lsra_from_stack(ls, src, b_index, iindex); - src = src->prev; - } - if (md->returntype.type != TYPE_VOID) - lsra_new_stack(ls, dst, b_index, iindex); + if (md->returntype.type == TYPE_VOID) + v = UNUSED; + break; + + case DF_N_TO_1: + i = iptr->s1.argcount; break; - case ICMD_MULTIANEWARRAY: - i = iptr->op1; + } + + if (i != UNUSED) { + argp = iptr->sx.s23.s2.args; while (--i >= 0) { - lsra_from_stack(ls, src, b_index, iindex); - src = src->prev; + lt_usage(jd, *argp, b_index, iindex, LT_USE); + argp++; } - lsra_new_stack(ls, dst, b_index, iindex); - break; + } - default: -/* assert(0); */ - throw_cacao_exception_exit(string_java_lang_InternalError, - "Unknown ICMD %d during register allocation", iptr->opc); - } /* switch */ + if (v != UNUSED) { + lt_usage(jd, v, b_index, iindex, LT_DEF); + } } /* for (;iindex >= 0; iindex--, iptr--) */ } /* if (bptr->flags >= BBREACHED) */ } /* scan_lifetimes */ diff --git a/src/vm/jit/optimizing/lifetimes.h b/src/vm/jit/optimizing/lifetimes.h index 068d88393..e6776ea49 100644 --- a/src/vm/jit/optimizing/lifetimes.h +++ b/src/vm/jit/optimizing/lifetimes.h @@ -39,7 +39,7 @@ #if !defined(NDEBUG) # include # define LT_DEBUG_CHECK -# define LT_DEBUG_VERBOSE +/* # define LT_DEBUG_VERBOSE */ #endif #ifdef LT_DEBUG_CHECK @@ -50,20 +50,17 @@ # define _LT_ASSERT(a) #endif -#define LSRA_BB_IN 3 -#define LSRA_BB_OUT 2 -#define LSRA_STORE 1 -#define LSRA_LOAD 0 -#define LSRA_POP -1 +#define LT_BB_IN 3 +#define LT_BB_OUT 2 +#define LT_DEF 1 +#define LT_USE 0 typedef struct site *lt_iterator; -void scan_lifetimes(methodinfo *m, codegendata *cd, registerdata *rd, - lsradata *ls, graphdata *gd, dominatordata *dd); -void lsra_add_ss(struct lifetime *, stackptr ); -void remove_use_site(struct lifetime *lt, int block, int iindex); -void move_use_sites(struct lifetime *from, struct lifetime *to); -void move_stackslots(struct lifetime *from, struct lifetime *to); -void LifenessAnalysis(methodinfo *m, lsradata *ls, graphdata *gd); +void lt_scanlifetimes(jitdata *, graphdata *, dominatordata *); +void lt_add_ss(struct lifetime *, stackptr ); +void lt_remove_use_site(struct lifetime *lt, int block, int iindex); +void lt_move_use_sites(struct lifetime *from, struct lifetime *to); +void lt_lifeness_analysis(jitdata *, graphdata *); #endif /* _LIFETIMES_H */ /* diff --git a/src/vm/jit/optimizing/lsra.c b/src/vm/jit/optimizing/lsra.c index 2ec31e7e0..693798e5d 100644 --- a/src/vm/jit/optimizing/lsra.c +++ b/src/vm/jit/optimizing/lsra.c @@ -41,8 +41,9 @@ #include "toolbox/bitvector.h" -#include "vm/statistics.h" -#include "vm/options.h" +#include "vmcore/statistics.h" +#include "vmcore/options.h" +#include "vmcore/method.h" #include "vm/jit/abi.h" #include "vm/jit/reg.h" @@ -92,7 +93,6 @@ void lsra_alloc(jitdata *, int *, int, int *); int lsra_getmem(struct lifetime *, struct freemem *, int *); struct freemem *lsra_getnewmem(int *); -void lsra_setflags(int *, int); void lsra(jitdata *jd) { methodinfo *m; @@ -100,14 +100,16 @@ void lsra(jitdata *jd) { registerdata *rd; lsradata *ls; graphdata *gd; -#if defined(STATISTICS) +#if defined(ENABLE_STATISTICS) int locals_start; int i,j; #endif #if defined(LSRA_DEBUG_CHECK) +#if 0 int b_index; stackptr in,out; int ind, outd; +#endif #endif m = jd->m; @@ -116,10 +118,11 @@ void lsra(jitdata *jd) { ls = jd->ls; #if defined(LSRA_DEBUG_CHECK) +#if 0 b_index = 0; - while (b_index < m->basicblockcount ) { + while (b_index < jd->basicblockcount ) { - if (m->basicblocks[b_index].flags >= BBREACHED) { + if (jd->basicblocks[b_index].flags >= BBREACHED) { in=m->basicblocks[b_index].instack; ind=m->basicblocks[b_index].indepth; @@ -145,6 +148,7 @@ void lsra(jitdata *jd) { b_index++; } #endif +#endif #if defined(LSRA_DEBUG_CHECK) || defined(LSRA_DEBUG_VERBOSE) #if defined(LSRA_DEBUG_VERBOSE) @@ -166,8 +170,6 @@ void lsra(jitdata *jd) { #endif lsra_init(jd); - - gd = lsra_setup(jd); #if defined(ENABLE_STATISTICS) @@ -204,8 +206,6 @@ void lsra_init(jitdata *jd) /* allocate lifetimes for all Basicblocks */ ls->v_index = -1; - - } graphdata *lsra_setup(jitdata *jd) @@ -237,12 +237,10 @@ graphdata *lsra_setup(jitdata *jd) /* Generate the Control Flow Graph */ /* Add one for a Basic Block 0 to be inserted, so lateron */ /* with SSA Parameter initialization is handled right */ - gd = graph_init(m->basicblockcount + 1); + gd = graph_init(jd->basicblockcount + 1); graph_make_cfg(jd, gd); - ssa(jd, gd); - - LifenessAnalysis(m, ls, gd); + lt_lifeness_analysis(jd, gd); #ifdef LSRA_DEBUG_VERBOSE if (compileverbose) { @@ -313,18 +311,18 @@ void lsra_reg_setup(jitdata *jd, #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS) if (IS_2_WORD_TYPE(md->paramtypes[i].type)) { int_reg->sav_reg[--int_sav_top] = - rd->argintregs[GET_HIGH_REG(md->params[i].regoff)]; + GET_HIGH_REG(md->params[i].regoff); intarg_used[GET_HIGH_REG(md->params[i].regoff)]=true; /*used -> don't copy later on */ int_reg->sav_reg[--int_sav_top] = - rd->argintregs[GET_LOW_REG(md->params[i].regoff)]; + GET_LOW_REG(md->params[i].regoff); intarg_used[GET_LOW_REG(md->params[i].regoff)]=true; /*used -> don't copy later on */ } else #endif { /* !IS_2_WORD_TYPE(md->paramtypes[i].type */ int_reg->sav_reg[--int_sav_top] = - rd->argintregs[md->params[i].regoff]; + md->params[i].regoff; intarg_used[md->params[i].regoff]=true; /*used -> don't copy later on */ } @@ -335,7 +333,7 @@ void lsra_reg_setup(jitdata *jd, /* still be used in the method! */ else { /* IS_FLT_DBL_TYPE(md->paramtypes[i].type */ flt_reg->sav_reg[--flt_sav_top] = - rd->argfltregs[md->params[i].regoff]; + md->params[i].regoff; fltarg_used[md->params[i].regoff]=true; } #endif @@ -347,10 +345,10 @@ void lsra_reg_setup(jitdata *jd, /* int_reg->sav_reg; */ for (i=0; i < INT_ARG_CNT; i++) if (!intarg_used[i]) - int_reg->sav_reg[--int_sav_top]=rd->argintregs[i]; + int_reg->sav_reg[--int_sav_top]=i; for (i=0; i < FLT_ARG_CNT; i++) if (!fltarg_used[i]) - flt_reg->sav_reg[--flt_sav_top]=rd->argfltregs[i]; + flt_reg->sav_reg[--flt_sav_top]=i; /* copy temp registers to flt_reg->sav_reg and int_reg->sav_reg */ for (i=0; i < INT_TMP_CNT; i++) @@ -368,6 +366,7 @@ void lsra_reg_setup(jitdata *jd, /* with Locals as non SAVEDVAR, the used arg[int|flt] as in params */ /* of the method itself have to be regarded, or mismatch before */ /* block 0 with parameter copy could happen! */ + argintreguse = max(rd->argintreguse, md->argintreguse); argfltreguse = max(rd->argfltreguse, md->argfltreguse); @@ -385,14 +384,23 @@ void lsra_reg_setup(jitdata *jd, /* copy temp and unused argument registers to flt_reg->tmp_reg and */ /* int_reg->tmp_reg */ + for (i=0; i < INT_TMP_CNT; i++) int_reg->tmp_reg[i]=rd->tmpintregs[i]; + + /* quick and dirty patch for the drop of rd->argxxxreg[] - but will */ + /* work anyhow on i386, !! has to be made "real" for other archs */ + for (j = argintreguse; j < INT_ARG_CNT; j++, i++) - int_reg->tmp_reg[i]=rd->argintregs[j]; + int_reg->tmp_reg[i]=j; for (i=0; i < FLT_TMP_CNT; i++) flt_reg->tmp_reg[i]=rd->tmpfltregs[i]; + + /* quick and dirty patch for the drop of rd->argxxxreg[] - but will */ + /* work anyhow on i386, !! has to be made "real" for other archs */ + for (j = argfltreguse; j < FLT_ARG_CNT; j++, i++) - flt_reg->tmp_reg[i]=rd->argfltregs[j]; + flt_reg->tmp_reg[i]=j; } /* now copy saved registers to flt_reg->sav_reg and int_reg->sav_reg */ @@ -561,6 +569,8 @@ void lsra_main(jitdata *jd) printf("Rest RA complete \n"); printf("Lifetimes after leftt:\n"); print_lifetimes(jd, ls->lt_mem, ls->lt_mem_count); + + printf("jd->varcount: %i jd->vartop %i\n", jd->varcount, jd->vartop); } #endif } @@ -570,7 +580,6 @@ void lsra_alloc(jitdata *jd, int *lifet, int lifetimecount, int *mem_use) int flags,regoff; struct lifetime *lt; struct freemem *fmem; - struct stackslot *n; int lt_index; #ifdef HAS_4BYTE_STACKSLOT struct freemem *fmem_2; @@ -593,51 +602,29 @@ void lsra_alloc(jitdata *jd, int *lifet, int lifetimecount, int *mem_use) #endif for (lt_index = 0; lt_index < lifetimecount; lt_index ++) { - lt = &(ls->lifetime[lifet[lt_index]]); + lt = ls->lifetime + lifet[lt_index]; #ifdef LSRA_MEMORY lt->reg=-1; #endif - if (lt->reg==-1) { - flags=INMEMORY; + if (lt->regoff == -1) { + flags = INMEMORY; #ifdef HAS_4BYTE_STACKSLOT if (IS_2_WORD_TYPE(lt->type)) - regoff=lsra_getmem(lt, fmem_2, mem_use); + regoff = lsra_getmem(lt, fmem_2, mem_use); else #endif - regoff=lsra_getmem(lt, fmem, mem_use); + regoff = lsra_getmem(lt, fmem, mem_use); } else { - flags=lt->savedvar; - regoff=lt->reg; - } - - for (n=lt->local_ss; n!=NULL; n=n->next) { - lsra_setflags( &(n->s->flags), flags); - n->s->regoff=regoff; - } - if (lt->v_index >= 0) { - if (rd->locals[lt->v_index][lt->type].type>=0) { - rd->locals[lt->v_index][lt->type].flags= flags; - rd->locals[lt->v_index][lt->type].regoff=regoff; - } else { log_text("Type Data mismatch 1\n"); exit(1); } + flags = lt->savedvar; + regoff = lt->regoff; } - lt->reg = regoff; + lt->regoff = regoff; + VAR(lt->v_index)->vv.regoff = regoff; + VAR(lt->v_index)->flags = flags; } } -void lsra_setflags(int *flags, int newflags) -{ - if ( newflags & INMEMORY) - *flags |= INMEMORY; - else - *flags &= ~INMEMORY; - - if (newflags & SAVEDVAR) - *flags |= SAVEDVAR; - else - *flags &= ~SAVEDVAR; -} - int lsra_getmem(struct lifetime *lt, struct freemem *fmem, int *mem_use) { struct freemem *fm, *p; @@ -701,7 +688,7 @@ void _lsra_main( jitdata *jd, int *lifet, int lifetimecount, /* no registers available */ for (lt_index = 0; lt_index < lifetimecount; lt_index++) - ls->lifetime[lifet[lt_index]].reg = -1; + ls->lifetime[lifet[lt_index]].regoff = -1; return; } @@ -759,7 +746,7 @@ void _lsra_main( jitdata *jd, int *lifet, int lifetimecount, if (reg_index == -1) /* no reg is available anymore... -> spill */ spill_at_intervall(jd, lt); else { - lt->reg = reg_index; + lt->regoff = reg_index; if (temp) lsra_add_active(lt, ls->active_tmp, &(ls->active_tmp_top)); else { @@ -813,7 +800,7 @@ void _lsra_expire_old_intervalls(jitdata *jd, struct lifetime *lt, reg->sav_reg[reg->sav_top++] = GET_HIGH_REG(active[i]->reg); } else #endif - reg->sav_reg[reg->sav_top++] = active[i]->reg; + reg->sav_reg[reg->sav_top++] = active[i]->regoff; } else { /* no leafmethod -> distinguish between temp and saved register */ #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS) @@ -829,10 +816,10 @@ void _lsra_expire_old_intervalls(jitdata *jd, struct lifetime *lt, } } else #endif - if ( reg->nregdesc[active[i]->reg] == REG_SAV) { - reg->sav_reg[reg->sav_top++] = active[i]->reg; + if ( reg->nregdesc[active[i]->regoff] == REG_SAV) { + reg->sav_reg[reg->sav_top++] = active[i]->regoff; } else { - reg->tmp_reg[reg->tmp_top++] = active[i]->reg; + reg->tmp_reg[reg->tmp_top++] = active[i]->regoff; } } } @@ -856,7 +843,7 @@ void spill_at_intervall(jitdata *jd, struct lifetime *lt ) _spill_at_intervall(lt, ls->active_sav, &(ls->active_sav_top)); } else { _spill_at_intervall(lt, ls->active_tmp, &(ls->active_tmp_top)); - if (lt->reg == -1) { /* kein tmp mehr frei gewesen */ + if (lt->regoff == -1) { /* kein tmp mehr frei gewesen */ _spill_at_intervall(lt, ls->active_sav, &(ls->active_sav_top)); } } @@ -873,7 +860,7 @@ void _spill_at_intervall(struct lifetime *lt, struct lifetime **active, #endif /* 0 */ if (*active_top == 0) { - lt->reg=-1; + lt->regoff = -1; return; } @@ -907,8 +894,8 @@ void _spill_at_intervall(struct lifetime *lt, struct lifetime **active, return; #endif - lt->reg=active[i]->reg; - active[i]->reg=-1; + lt->regoff = active[i]->regoff; + active[i]->regoff = -1; (*active_top)--; for (j = i; j < *active_top; j++) @@ -916,7 +903,7 @@ void _spill_at_intervall(struct lifetime *lt, struct lifetime **active, lsra_add_active(lt, active, active_top); } else { - lt->reg=-1; + lt->regoff = -1; } } @@ -931,7 +918,6 @@ void lsra_calc_lifetime_length(jitdata *jd) /* 1 INTREG -> ls->lt_int */ /* 2 FLTREG -> ls->lt_flt */ - instruction *iptr; lsradata *ls; ls = jd->ls; @@ -941,7 +927,7 @@ void lsra_calc_lifetime_length(jitdata *jd) for (i=1; i < ls->basicblockcount; i++) { if (ls->sorted[i-1] != -1) icount += ls->basicblocks[ls->sorted[i-1]]->icount + 1 + - ls->max_vars_with_indices; + ls->varcount_with_indices; if (ls->sorted[i] != -1) icount_block[i] = icount; } @@ -966,25 +952,9 @@ void lsra_calc_lifetime_length(jitdata *jd) /* i_last_use */ _LSRA_ASSERT(lt->def != NULL); - _LSRA_ASSERT(lt->use != NULL); - - /* there are conflicts possible between in and outstacks of */ - /* DUP* ICMDs. So extend lifetime of outstacks by one */ - if (lt->i_first_def >= 0 && (lt->bb_first_def != 0)) { - iptr = ls->basicblocks[ls->sorted[lt->bb_first_def]]->iinstr + - lt->i_first_def; - switch (iptr->opc) { -/* case ICMD_DUP: */ - case ICMD_DUP2: - case ICMD_DUP_X1: - case ICMD_DUP_X2: - case ICMD_DUP2_X1: - case ICMD_DUP2_X2: - case ICMD_SWAP: -/* _LSRA_ASSERT(lt->i_first_def != 0); */ - lt->i_first_def--; - } - } + /* _LSRA_ASSERT(lt->use != NULL);*/ + if (lt->use == NULL) + lt->use = lt->def; #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS) /* prevent conflicts between lifetimes of type long by increasing */ @@ -1000,7 +970,7 @@ void lsra_calc_lifetime_length(jitdata *jd) /* distribute lifetimes to lt_int, lt_flt and lt_mem */ - lt->reg = -1; + lt->regoff = -1; switch (lt->type) { case TYPE_LNG: @@ -1052,7 +1022,15 @@ void lsra_calc_lifetime_length(jitdata *jd) lt->i_start = icount_block[lt->bb_first_def] + lt->i_first_def; if (lt->bb_last_use == -1) { - printf("--------- Warning: variable not used! --------------------vi: %i start: %i end: %i\n", lt->v_index, lt->i_start, lt->i_end); + /* unused Vars are not regarded by lifeness_analysis! */ + _LSRA_ASSERT(lt->def != NULL) + _LSRA_ASSERT(lt->def->next == NULL) + + if (compileverbose) { + printf("--------- Warning: variable not used! ---------"); + printf("vi: %i start: %i end: %i\n", lt->v_index, + lt->i_start, lt->i_end); + } lt->bb_last_use = lt->bb_first_def; lt->i_last_use = lt->i_first_def; } @@ -1078,7 +1056,6 @@ void print_lifetimes(jitdata *jd, int *lt, int lifetimecount) { struct lifetime *n; int lt_index; - int type,flags,regoff,varkind; lsradata *ls; registerdata *rd; @@ -1086,22 +1063,8 @@ void print_lifetimes(jitdata *jd, int *lt, int lifetimecount) ls = jd->ls; for (lt_index = 0; lt_index < lifetimecount; lt_index++) { - n = &(ls->lifetime[lt[lt_index]]); - if (n->v_index < 0) { /* stackslot */ - type = n->local_ss->s->type; - flags=n->local_ss->s->flags; - regoff=n->local_ss->s->regoff; - varkind=n->local_ss->s->varkind; - } else { /* local var */ - if (rd->locals[n->v_index][n->type].type>=0) { - type = rd->locals[n->v_index][n->type].type; - flags=rd->locals[n->v_index][n->type].flags; - regoff=rd->locals[n->v_index][n->type].regoff; - varkind=-1; - } else - { log_text("Type Data mismatch 3\n"); assert(0); } - } - printf("i_Start: %3i(%3i,%3i) i_stop: %3i(%3i,%3i) reg: %3i VI: %3i type: %3i flags: %3i varkind: %3i usage: %3li ltflags: %xi \n",n->i_start, ls->sorted[n->bb_first_def], n->i_first_def,n->i_end, ls->sorted[n->bb_last_use], n->i_last_use,regoff,n->v_index,type,flags, varkind, n->usagecount, n->flags); + n = ls->lifetime + lt[lt_index]; + printf("i_Start: %3i(%3i,%3i) i_stop: %3i(%3i,%3i) reg: %3i VI: %3i type: %3i flags: %3i usage: %3li ltflags: %xi \n",n->i_start, ls->sorted[n->bb_first_def], n->i_first_def,n->i_end, ls->sorted[n->bb_last_use], n->i_last_use,n->regoff,n->v_index,n->type,n->flags, n->usagecount, n->flags); } printf( "%3i Lifetimes printed \n",lt_index); } @@ -1110,7 +1073,6 @@ void print_all_lifetimes(jitdata *jd) { struct lifetime *n; int lt_index; - int type,flags,regoff,varkind; lsradata *ls; registerdata *rd; @@ -1120,21 +1082,7 @@ void print_all_lifetimes(jitdata *jd) for (lt_index = 0; lt_index < ls->lifetimecount; lt_index++) { n = &(ls->lifetime[lt_index]); if (n->type != -1) { - if (n->v_index < 0) { /* stackslot */ - type = n->local_ss->s->type; - flags=n->local_ss->s->flags; - regoff=n->local_ss->s->regoff; - varkind=n->local_ss->s->varkind; - } else { /* local var */ - if (rd->locals[n->v_index][n->type].type>=0) { - type = rd->locals[n->v_index][n->type].type; - flags=rd->locals[n->v_index][n->type].flags; - regoff=rd->locals[n->v_index][n->type].regoff; - varkind=-1; - } else - { log_text("Type Data mismatch 3\n"); assert(0); } - } - printf("i_Start: %3i(%3i,%3i) i_stop: %3i(%3i,%3i) VI: %3i type: %3i flags: %3i varkind: %3i usage: %3li ltflags: %xi \n",n->i_start, ls->sorted[n->bb_first_def], n->i_first_def,n->i_end, ls->sorted[n->bb_last_use], n->i_last_use,n->v_index,type,flags, varkind, n->usagecount, n->flags); + printf("i_Start: %3i(%3i,%3i) i_stop: %3i(%3i,%3i) VI: %3i type: %3i flags: %3i usage: %3li ltflags: %xi \n",n->i_start, ls->sorted[n->bb_first_def], n->i_first_def,n->i_end, ls->sorted[n->bb_last_use], n->i_last_use,n->v_index,n->type,n->flags, n->usagecount, n->flags); } } printf( "%3i Lifetimes printed \n",lt_index); diff --git a/src/vm/jit/optimizing/lsra.h b/src/vm/jit/optimizing/lsra.h index 834ce9f87..d758139f1 100644 --- a/src/vm/jit/optimizing/lsra.h +++ b/src/vm/jit/optimizing/lsra.h @@ -36,6 +36,7 @@ #include "toolbox/bitvector.h" + #if !defined(NDEBUG) # include # define LSRA_DEBUG_CHECK @@ -86,10 +87,10 @@ struct lifetime { int v_index; /* local variable index or negative for stackslots */ int type; /* TYPE_XXX or -1 for unused lifetime */ long usagecount; /* number of references*/ - int reg; /* regoffset allocated by lsra*/ + int regoff; /* regoffset allocated by lsra*/ int savedvar; int flags; - struct stackslot *local_ss; /* Stackslots for this Lifetime or NULL ( == */ + /* struct stackslot *local_ss; */ /* Stackslots for this Lifetime or NULL ( == */ /* "pure" Local Var) */ int bb_last_use; int i_last_use; @@ -107,11 +108,13 @@ struct l_loop { int nesting; }; +/* struct stackslot { stackptr s; int bb; struct stackslot *next; }; +*/ struct lsra_register { int *sav_reg; @@ -149,6 +152,26 @@ struct igraph { struct lsradata { + /* int *var; */ /* unused entries are set to UNUSED */ + /* maps to jd->vars array */ + int varcount; /* size of vars array */ + int ssavarcount; /* ls->vars[0..ssavarcount[ are all locals and iovars */ + /* they are regarded for ssa renaming */ + /* the rest (ls->vars[ssavarcount..varcount[ are */ + /* TEMP or PREALLOC vars with just on definition and */ + /* use within one basicblock -> not of interest for */ + /* ssa renaming procedures */ + int vartop; /* next free var */ + int varcount_with_indices; + int *new_varindex; /* new_varindex[0..jd->varcount[ points to the new */ + /* unique index of ls->vars(maps jd->vars to ls->vars)*/ + + int *var_0; /* [0..ls->varcount] */ + /* var_0[a] with a in [0..ls->varcount[ holds the */ + /* index of La,0 */ + /* var_0[ls->varcount] holds the number of vars with */ + /*indices */ + int *sorted; /* BB sorted in reverse post order */ int *sorted_rev; /* BB reverse lookup of sorted */ @@ -157,9 +180,6 @@ struct lsradata { long *nesting; /* Nesting level of BB*/ - int maxlifetimes; /* copy from methodinfo to prevent passing methodinfo */ - /* as parameter */ - struct lifetime *lifetime; /* array of lifetimes */ int lifetimecount; /* number of lifetimes */ int *lt_used; /* index to lifetimearray for used lifetimes */ @@ -180,7 +200,7 @@ struct lsradata { /* SSA fields */ bitvector *var_def; /* LocalVar Definition Bitvector [0..ls->bbcount] */ - /* Bitvector holds ls->max_vars Bits */ + /* Bitvector holds ls->max_vars Bits */ bitvector *use_sites; /* LocalVar Use Bitvector[0..ls->maxvars] */ int **num_var_use; /* count of var_use[bb][var_index] */ int **var; /* [0..cd->maxlocal+cd->maxstack[[0..4] */ diff --git a/src/vm/jit/optimizing/ssa.c b/src/vm/jit/optimizing/ssa.c index e92defb38..a842537c1 100644 --- a/src/vm/jit/optimizing/ssa.c +++ b/src/vm/jit/optimizing/ssa.c @@ -37,6 +37,10 @@ #include "toolbox/bitvector.h" #include "toolbox/worklist.h" +#include "vm/builtin.h" + +#include "vm/jit/jit.h" /* icmd_table */ + #include "vm/jit/optimizing/dominators.h" #include "vm/jit/optimizing/graph.h" #include "vm/jit/optimizing/lifetimes.h" @@ -45,366 +49,538 @@ #include "vm/jit/optimizing/ssa.h" #if defined(SSA_DEBUG_VERBOSE) -#include "vm/options.h" /* compileverbose */ -#include "vm/jit/jit.h" /* icmd_table */ +#include "vmcore/options.h" /* compileverbose */ #endif /* function prototypes */ -void dead_code_elimination(methodinfo *m, registerdata *rd, lsradata *ls, - graphdata *gd); -void copy_propagation(methodinfo *m,registerdata *rd, lsradata *ls, - graphdata *gd); -void replace_use_sites( lsradata *ls, graphdata *gd, struct lifetime *lt, - int new_v_index, worklist *W); -void ssa_place_phi_functions(codegendata *cd, lsradata *ls, graphdata *gd, - dominatordata *dd); -void ssa_Rename_init(methodinfo *m, codegendata *cd, lsradata *ls, - graphdata *gd); -void ssa_Rename(methodinfo *m, codegendata *cd, registerdata *rd, lsradata *ls, - graphdata *gd, dominatordata *dd); -void ssa_Rename_(codegendata *cd, lsradata *ls, graphdata *gd, - dominatordata *dd, int n); +void ssa_set_local_def(lsradata *, int , int); +void ssa_set_interface(jitdata *, basicblock *, s4 *); + +void dead_code_elimination(jitdata *jd, graphdata *gd); +void copy_propagation(jitdata *jd, graphdata *gd); +void ssa_replace_use_sites(jitdata *, graphdata *, struct lifetime *, + int , worklist *); +void ssa_place_phi_functions(jitdata *jd, graphdata *gd, dominatordata *dd); +void ssa_rename_init(jitdata *jd, graphdata *gd); +void ssa_rename(jitdata *jd, graphdata *gd, dominatordata *dd); +void ssa_rename_(jitdata *jd, graphdata *gd, dominatordata *dd, int n); + +void ssa_set_def(lsradata *, int , int ); +void ssa_set_local_def(lsradata *, int , int ); +void ssa_set_iovar(lsradata *, s4 , int , s4 *); +void ssa_set_interface(jitdata *, basicblock *, s4 *); + +void ssa_generate_phi_moves(jitdata *, graphdata *); +int ssa_rename_def_(lsradata *ls, int a); #ifdef SSA_DEBUG_VERBOSE -void ssa_print_trees(methodinfo *m, codegendata *cd, lsradata *ls, - graphdata *gd, dominatordata *dd); +void ssa_print_trees(jitdata *jd, graphdata *gd, dominatordata *dd); void ssa_print_lt(lsradata *ls); +void ssa_show_variable(jitdata *jd, int index, varinfo *v, int stage); +void ssa_print_phi(lsradata *, graphdata *); #endif -/********************************************************* -Data Collection (Use/Definition) while analyze_stack: -Basic Block indices of definition are needed for generation -of the phi Functions. - -ssa_set_local_def -ssa_set_interface -ssa_set_use - -These two functions use the internal Helpers: -ssa_set_def -ssa_set_interface_ -*********************************************************/ -void ssa_set_use(lsradata *ls, int b_index, int local_index, int type) { - /* just count uses to determine the needed max size for use def */ - /* data structures */ - ls->uses++; -} -void ssa_set_def(lsradata *ls, int b_index, int var_index) { +/* ssa ************************************************************************ - /* b_index + 1 to leave space for the param init block 0 */ - bv_set_bit(ls->var_def[b_index + 1], var_index); - /* count number of defs for every var since SSA */ - /* will create a new var for every definition */ - ls->num_defs[var_index]++; -} +SSA main procedure: -void ssa_set_local_def(lsradata *ls, int b_index, int local_index, int type) { +******************************************************************************/ - if (ls->var[local_index][type] == -1) { - /* New Local Variable encountered -> create a new unique index */ - ls->var[local_index][type] = ls->max_vars; - ls->var_to_index[ls->max_vars] = ls->max_locals++; - ls->max_vars++; -#ifdef SSA_DEBUG_VERBOSE - if (compileverbose) - printf("Local %3i,%3i -> Var %3i\n",local_index,type,ls->max_vars-1); -#endif - } +void ssa(jitdata *jd, graphdata *gd) { + struct dominatordata *dd; + lsradata *ls; - ssa_set_def(ls, b_index, ls->var[local_index][type]); -} + ls = jd->ls; -void ssa_set_interface_(codegendata *cd, lsradata *ls, basicblock *bptr, - stackptr s, int depth) { - int var_index; + dd = compute_Dominators(gd, ls->basicblockcount); + computeDF(gd, dd, ls->basicblockcount, 0); - var_index = depth + jd->maxlocals; - if (ls->var[var_index][s->type] == -1) { - /* New Interface Stackslot encountered -> create a new unique index */ - ls->var[var_index][s->type] = ls->max_vars; - ls->var_to_index[ls->max_vars] = ls->max_interfaces--; - ls->max_vars++; + ssa_place_phi_functions(jd, gd, dd); + ssa_rename(jd, gd, dd); #ifdef SSA_DEBUG_VERBOSE - if (compileverbose) - printf("Interface SS %3i,%3i -> Var %3i\n",bptr->nr+1,depth,ls->max_vars-1); + if (compileverbose) { + printf("Phi before Cleanup\n"); + ssa_print_phi(ls, gd); + ssa_print_lt(ls); + } #endif + lt_scanlifetimes(jd, gd, dd); +#ifdef SSA_DEBUG_VERBOSE + if (compileverbose) { + ssa_print_lt(ls); } - ssa_set_def(ls, bptr->nr, ls->var[var_index][s->type]); -} +#endif +/* dead_code_elimination(jd, gd); */ +#ifdef SSA_DEBUG_VERBOSE + if (compileverbose) { + printf("Phi after dead code elemination\n"); + ssa_print_phi(ls, gd); + ssa_print_lt(ls); + } +#endif +/* copy_propagation(jd, gd); */ +#ifdef SSA_DEBUG_VERBOSE + if (compileverbose) { + printf("Phi after copy propagation\n"); + ssa_print_phi(ls, gd); + ssa_print_lt(ls); + } +#endif -void ssa_set_interface(codegendata *cd, lsradata *ls, basicblock *bptr) { - stackptr out, in; - int in_d, out_d; + ssa_generate_phi_moves(jd, gd); + transform_BB(jd, gd); - out = bptr->outstack; - in = bptr->instack; - in_d = bptr->indepth; - out_d = bptr->outdepth; - /* ignore top Stackelement of instack in case of EXH or SBR blocks */ - /* These are no Interface stackslots! */ - if ((bptr->type == BBTYPE_EXH) || - (bptr->type == BBTYPE_SBR)) { - in_d--; - in = in->prev; - } +#ifdef SSA_DEBUG_CHECK + { + int i, j, pred, in_d, out_d; + graphiterator iter_pred; + s4 *in, *out; + bool phi_define; + methodinfo *m; - for(;(in_d > out_d); in_d--, in = in->prev); + m = jd->m; - while((out != NULL)) { - if (in_d == out_d) { - if (in != out) { - /* out interface stackslot is defined in this basic block */ - ssa_set_interface_(cd, ls, bptr, out, out_d - 1); + for(i = 0; i < ls->basicblockcount; i++) { + if (ls->basicblocks[i]->indepth != 0) { + pred = graph_get_first_predecessor(gd, i, &iter_pred); + for (; (pred != -1); pred = graph_get_next(&iter_pred)) { + in_d = ls->basicblocks[i]->indepth - 1; + in = ls->basicblocks[i]->invars; + for (; in_d >= 0; in_d--) { + phi_define = false; + for (j = 0; (!phi_define) && (jssavarcount); j++) { + if (ls->phi[i][j] != NULL) + if (ls->phi[i][j][0] == in[in_d]) + phi_define = true; + } + if (!phi_define) { + /* in not defined in phi function -> check with */ + /* outstack(s) of predecessor(s) */ + out_d = ls->basicblocks[pred]->outdepth - 1; + out = ls->basicblocks[pred]->outvars; + _SSA_ASSERT(out_d >= in_d); + for(; out_d > in_d; out_d--); + if ((in[in_d] != out[out_d]) || + (VAR(in[in_d])->flags != VAR(out[out_d])->flags)) { + printf("Method: %s %s\n", + m->class->name->text, m->name->text); + printf("Error: Stack Varnum Mismatch BBin %3i BBout %3i Stackdepth %3i\n", i, pred, in_d); + if (compileverbose) + printf("Error: Stack Varnum Mismatch BBin %3i BBout %3i Stackdepth %3i\n", i, pred, in_d); +/* else */ +/* _SSA_ASSERT(0); */ + } + } + } + } } - out = out->prev; - out_d--; - in = in->prev; - in_d--; - } else if (in_d < out_d ) { - /* out interface stackslot is defined in this basic block */ - ssa_set_interface_(cd, ls, bptr, out, out_d - 1); - out = out->prev; - out_d--; } } + +#endif + + +#ifdef SSA_DEBUG_VERBOSE + if (compileverbose) + ssa_print_trees(jd, gd, dd); +#endif } -/********************************************************************* -Initialise needed Data structures -*********************************************************************/ +/* ssa_init ******************************************************************* + +Initialise data structures for ssa + +IOVARS of same stackdepth and same type are coalesced: +interface_map[ 5 * stackdepth + type ] = new_varindex with +0 <= new_varindex < ls->ssavarcount + +TODO: check if coalescing of IOVARS of same stackdepth and type only of adjacent +basic blocks could decrease the number of phi functions and so improve ssa +analysis performance! + +All LOCALVARS and IOVARS get a new unique varindex: +ls->new_varindex[0..jd->varcount[ = new_varindex with +0 <= new_varindex < ls->ssavarcount + +The jd->varcount bits long bitvectors ls->var_def[0..jd->basicblockindex+1[ + are set to the definitions of LOCALVARS and IOVARS. (So the only the first +ls->ssavarcount bits of each of these vectors contain valid data, but +ls->ssavarcount is computed at the same time as the definitons are stored.) + +The basic block number used as index for the bitvector array ls->var_def is +already shifted by one to make space for the new basic block 0 for parameter +initialization. + +******************************************************************************/ void ssa_init(jitdata *jd) { - int p, t; - methoddesc *md; - int i, b_index, len; - int lifetimes; - stackptr src, dst, tmp; + int p, t, v; + methoddesc *md; + int i, l, b_index, len; instruction *iptr; basicblock *bptr; + s4 *interface_map; /* holds an new unique index for every used */ + /* basic block inoutvar described by a dupel */ + /*(depth,type). Used to coalesce the inoutvars*/ + methodinfo *m; + lsradata *ls; + builtintable_entry *bte; - methodinfo *m; - codegendata *cd; - registerdata *rd; - lsradata *ls; - - m = jd->m; - cd = jd->cd; - rd = jd->rd; ls = jd->ls; + m = jd->m; md = m->parseddesc; + #if defined(SSA_DEBUG_CHECK) || defined(SSA_DEBUG_VERBOSE) -#if defined(SSA_DEBUG_VERBOSE) +# if defined(SSA_DEBUG_VERBOSE) if (compileverbose) { printf("%s %s ",m->class->name->text, m->name->text); if (jd->isleafmethod) printf("**Leafmethod**"); printf("\n"); } -#endif - if (strcmp(m->class->name->text,"java/util/Properties")==0) - if (strcmp(m->name->text,"load")==0) -#if defined(SSA_DEBUG_VERBOSE) +# endif + if (strcmp(m->class->name->text,"spec/benchmarks/_213_javac/Parser")==0) + if (strcmp(m->name->text,"parseTerm")==0) +# if defined(SSA_DEBUG_VERBOSE) if (compileverbose) printf("12-------------------12\n"); -#else +# else { int dummy=1; dummy++; } -#endif +# endif #endif #ifdef SSA_DEBUG_VERBOSE if (compileverbose) - printf("ssa_init: basicblockcount %3i maxlocals %3i\n", - m->basicblockcount, jd->maxlocals); + printf("ssa_init: basicblockcount %3i localcount %3i\n", + jd->basicblockcount, jd->localcount); #endif - ls->num_defs = DMNEW(int, jd->maxlocals * 5 + cd->maxstack * 5); - ls->var_to_index = DMNEW(int, jd->maxlocals * 5 + cd->maxstack * 5); - ls->var = DMNEW(int *, jd->maxlocals + cd->maxstack); - t = 0; - for(p = 0; p < jd->maxlocals + cd->maxstack; p++) { - ls->var[p] = DMNEW(int, 5); - for(i = 0; i < 5; i++) { - ls->var[p][i] = -1; - ls->num_defs[t++] = 0; - } + + /* As first step all definitions of local variables and in/out vars are */ + /* gathered. in/outvars are coalesced for same type and depth */ + /* "normal" tempvars (just living within one basicblock are) ignored */ + + /* ls->var holds the index to jd->vars */ + + ls->num_defs = DMNEW(int, jd->varcount); + ls->new_varindex = DMNEW(int , jd->varcount); + + for(p = 0; p < jd->varcount; p++) { + ls->num_defs[p] = 0; + ls->new_varindex[p] = UNUSED; } + /* init Var Definition bitvectors */ - ls->var_def = DMNEW(int *, m->basicblockcount + 1); - for(i = 0; i <= m->basicblockcount; i++) { - ls->var_def[i] = bv_new(jd->maxlocals * 5 + cd->maxstack * 5); + + ls->var_def = DMNEW(int *, jd->basicblockcount + 1); + for(i = 0; i < jd->basicblockcount + 1; i++) { + ls->var_def[i] = bv_new(jd->varcount); } - ls->uses = 0; - ls->max_vars = 0; /* no Vars seen till now */ - /* A new Var Index will be created by SSA */ - /* since locals[Index][Type] is a quite sparse array */ - /* and locals will be renamed anyway by SSA */ - ls->max_locals = 0; /* unique index for every local_var/type pair*/ - ls->max_interfaces = -1; /* unique index for every interface/type pair*/ - /* interfaces are < 0, locals > 0 */ + + ls->ssavarcount = 0; + /* Add parameters first in right order, so the new local indices */ /* 0..p will correspond to "their" parameters */ /* They get defined at the artificial Block 0, the real method bbs will be*/ /* moved to start at block 1 */ - for (p = 0, i = 0; p < md->paramcount; p++) { - t = md->paramtypes[p].type; - ssa_set_local_def(ls, -1, i, t); - i++; + /* don't look at already eliminated (not used) parameters (locals) */ + + for (p = 0, l = 0; p < md->paramcount; p++) { + t = md->paramtypes[p].type; + i = jd->local_map[l * 5 + t]; + l++; if (IS_2_WORD_TYPE(t)) /* increment local counter a second time */ - i++; /* for 2 word types */ + l++; /* for 2 word types */ + if (i == UNUSED) + continue; + ssa_set_local_def(ls, -1, i); } - lifetimes = 0; - bptr = m->basicblocks; + _SSA_ASSERT(ls->ssavarcount < jd->varcount); + + /* coalesce bb in/out vars */ + + interface_map = DMNEW(s4, jd->stackcount * 5); + for(i = 0; i < jd->stackcount * 5; i++) + interface_map[i] = UNUSED; + + bptr = jd->basicblocks; for(; bptr != NULL; bptr = bptr->next) { +#ifdef SSA_DEBUG_VERBOSE + if (compileverbose) + printf("ssa_init: BB %3i flags %3x\n",bptr->nr, bptr->flags); +#endif if (bptr->flags >= BBREACHED) { + /* 'valid' Basic Block */ + b_index = bptr->nr; - /* Scan Number of Stack Lifetimes */ - lifetimes += m->basicblocks[b_index].indepth; + len = bptr->icount; + iptr = bptr->iinstr; + ssa_set_interface(jd, bptr, interface_map); - dst = m->basicblocks[b_index].instack; - len = m->basicblocks[b_index].icount; - iptr = m->basicblocks[b_index].iinstr; - for (;len>0; len--, iptr++) { - src = dst; - dst = iptr->dst; - - /* Reset "leftover" LOCALVAR stackslots */ - switch(iptr->opc) { - case ICMD_DUP: - lifetimes +=1; - if (dst->varkind != ARGVAR) - dst->varkind = TEMPVAR; - case ICMD_SWAP: - case ICMD_DUP2: - lifetimes += 2; - for(i=0, tmp = dst; i < 2; i++, tmp = tmp->prev) - if (tmp->varkind != ARGVAR) - tmp->varkind = TEMPVAR; - break; - case ICMD_DUP_X1: - lifetimes += 3; - for(i=0, tmp = dst; i < 3; i++, tmp = tmp->prev) - if (tmp->varkind != ARGVAR) - tmp->varkind = TEMPVAR; - break; - case ICMD_DUP2_X1: - lifetimes += 5; - for(i=0, tmp = dst; i < 5; i++, tmp = tmp->prev) - if (tmp->varkind != ARGVAR) - tmp->varkind = TEMPVAR; - break; - case ICMD_DUP_X2: - lifetimes += 4; - for(i=0, tmp = dst; i < 4; i++, tmp = tmp->prev) - if (tmp->varkind != ARGVAR) - tmp->varkind = TEMPVAR; - break; - case ICMD_DUP2_X2: - lifetimes += 6; - for(i=0, tmp = dst; i < 6; i++, tmp = tmp->prev) - if (tmp->varkind != ARGVAR) - tmp->varkind = TEMPVAR; - break; + /* !!!!!!!!! not true for now !!!!!!!!! */ + /* All baseline optimizations from stack.c are turned off for */ + /* SSA! */ - case ICMD_ILOAD: - case ICMD_LLOAD: - case ICMD_FLOAD: - case ICMD_DLOAD: - case ICMD_ALOAD: - if (( dst != NULL) && (src != dst)) - lifetimes++; - dst->varkind = TEMPVAR; - if (dst->varnum < 0) - dst->varnum = 0; - ssa_set_use(ls, b_index, iptr->op1, - iptr->opc - ICMD_ILOAD); - break; - - case ICMD_IINC: - if (( dst != NULL) && (src != dst)) - lifetimes++; - /* For SSA IINC has to be handled as a seperate LOAD */ - /* and STORE. The target local index is held in */ - /* val._i.op1_t, The immediate val.i is held in */ - /* val._i.i */ - { - int v; - v = iptr->val.i; - iptr->val._i.op1_t = iptr->op1; - iptr->val._i.i = v; - } + for (; len > 0; len--, iptr++) { - ssa_set_use(ls, b_index, iptr->op1,TYPE_INT); - ssa_set_local_def(ls, b_index, - iptr->val._i.op1_t, TYPE_INT); - break; + /* Look for definitions (iptr->dst). INVOKE and BUILTIN have */ + /* an optional dst - so they to be checked first */ - case ICMD_ISTORE: - case ICMD_LSTORE: - case ICMD_FSTORE: - case ICMD_DSTORE: - case ICMD_ASTORE: - src->varkind = TEMPVAR; - if (src->varnum < 0) - src->varnum =0; - ssa_set_local_def(ls, b_index, iptr->op1, - iptr->opc - ICMD_ISTORE); - break; + v = UNUSED; + if (icmd_table[iptr->opc].dataflow == DF_INVOKE) { + INSTRUCTION_GET_METHODDESC(iptr,md); + if (md->returntype.type != TYPE_VOID) + v = iptr->dst.varindex; + } + else if (icmd_table[iptr->opc].dataflow == DF_BUILTIN) { + bte = iptr->sx.s23.s3.bte; + md = bte->md; + if (md->returntype.type != TYPE_VOID) + v = iptr->dst.varindex; + } + else if (icmd_table[iptr->opc].dataflow >= DF_DST_BASE) { + v = iptr->dst.varindex; + } + if (v != UNUSED) { + if (( v < jd->localcount) || ( VAR(v)->flags & INOUT )) { + /* !IS_TEMPVAR && !IS_PREALLOC == (IS_LOCALVAR || IS_INOUT) */ + +/* _SSA_ASSERT(ls->new_varindex[v] != UNUSED); */ + ssa_set_local_def(ls, b_index, v); + } + } + } + } + } + _SSA_ASSERT(ls->ssavarcount < jd->varcount); +#ifdef SSA_DEBUG_VERBOSE + if (compileverbose) { - default: - if (( dst != NULL) && (src != dst)) - lifetimes++; + printf("ssa_init: Vars: Orig:%3i SSAVar: %3i\n", jd->varcount, + ls->ssavarcount); + for(i = 0; i < jd->varcount; i++) { + if ((i < jd->localcount) || ( VAR(i)->flags & INOUT)) { + printf("%3i(%3i,%3x) ",i,VAR(i)->type, VAR(i)->flags); + ssa_show_variable(jd, i, VAR(i),0); + if (i < ls->ssavarcount) { + printf(" -> %3i", ls->new_varindex[i]); } + printf("\n"); } - ssa_set_interface(cd, ls, &(m->basicblocks[b_index])); } } - ls->maxlifetimes = lifetimes; - ls->lifetimecount = lifetimes + jd->maxlocals * (TYPE_ADR+1); +#endif +} + +/* ssa_set_def **************************************************************** + +Helper for ssa_set_local_def and ssa_set_interface + +The definition of a var is stored in the bitvector array ls->var_def. + +The number of definitons of each var is counted, so the number of new vars with +SSA is known. + +******************************************************************************/ + +void ssa_set_def(lsradata *ls, int b_index, int varindex) { + + /* b_index + 1 to leave space for the param init block 0 */ + + bv_set_bit(ls->var_def[b_index + 1], varindex); + + /* count number of defs for every var since SSA */ + /* will create a new var for every definition */ + + ls->num_defs[varindex]++; +} + +/* ssa_set_local_def ********************************************************** + +Helper for ssa_init + +Assigns a new unique index for the local var varindex (if not already done so) +and then calls ssa_set_def to remember the definition in the bitvector array +ls->var_def + +******************************************************************************/ + +void ssa_set_local_def(lsradata *ls, int b_index, int varindex) { + + if (ls->new_varindex[varindex] == UNUSED) { + ls->new_varindex[varindex] = ls->ssavarcount++; + } + + ssa_set_def(ls, b_index, ls->new_varindex[varindex]); +} + +/* ssa_set_local_def ********************************************************** + +Helper for ssa_set_interface + +IN: ls pointer to lsradata structure + iovar varindex of INOUTVAR to process + map_index stackdepth * 5 + type, used for coalescing IOVARS. + +IN/OUT + interface_map used for coalescing IOVARS. interface_map[map_index] == + UNUSED, if this map_index (==stackdepth,type tupel) did not + occur till now. Then interface_map[map_index] will be set + to a new unique index. + ls->new_varindex will be set to this new unique index to map the old + varindizes to the new ones. + +Assigns a new unique index for the local var varindex (if not already done so) +and then calls ssa_set_def to remember the definition in the bitvector array +ls->var_def + +******************************************************************************/ + +void ssa_set_iovar(lsradata *ls, s4 iovar, int map_index, s4 *interface_map) { + if (interface_map[map_index] == UNUSED) + interface_map[map_index] = ls->ssavarcount++; + + ls->new_varindex[iovar] = interface_map[map_index]; +} + + +/* ssa_set_interface *********************************************************** + +Helper for ssa_init + +IN: ls pointer to lsradata structure + *bptr pointer to the basic block to be processed + +IN/OUT + interface_map used for coalescing IOVARS. interface_map[map_index] == + UNUSED, if this map_index (==stackdepth,type tupel) did not + occur till now. Then interface_map[map_index] will be set + to a new unique index. (see ssa_set_iovar) + +Searches the basic block given by *bptr for IN and OUTVARS and coalesces them +for each unique stackdepth,type dupel. For each OUTVAR with a different or no +INVAR at the same stackdepth the definition of this OUTVAR in this basic block +is remembered in ls->var_def. (see ssa_set_def) + +******************************************************************************/ + +void ssa_set_interface(jitdata *jd, basicblock *bptr, s4 *interface_map) { + s4 *out, *in; + int in_d, out_d; + int o_map_index, i_map_index; + lsradata *ls; + + ls = jd->ls; + + out = bptr->outvars; + in = bptr->invars; + in_d = bptr->indepth - 1; + out_d = bptr->outdepth - 1; + + /* ignore top Stackelement of instack in case of EXH or SBR blocks */ + /* These are no Interface stackslots! */ + if ((bptr->type == BBTYPE_EXH) || + (bptr->type == BBTYPE_SBR)) { + in_d--; + } + + /* invars with no corresponding outvars are not defined here */ + /* just set up the interface_map */ + + for(;(in_d > out_d); in_d--) { + i_map_index = in_d * 5 + VAR(in[in_d])->type; + ssa_set_iovar(ls, in[in_d], i_map_index, interface_map); + } + + while((out_d >= 0)) { + /* set up interface_map */ + + o_map_index = out_d * 5 + VAR(out[out_d])->type; + if (in_d >= 0) { + i_map_index = in_d * 5 + VAR(in[in_d])->type; + ssa_set_iovar(ls, in[in_d], i_map_index, interface_map); + } + ssa_set_iovar(ls, out[out_d], o_map_index, interface_map); + if (in_d == out_d) { + if (in[in_d] != out[out_d]) { + + /* out interface stackslot is defined in this basic block */ + +/* ssa_set_def(ls, bptr->nr + 1, ls->new_varindex[out[out_d]]); */ + } + out_d--; + in_d--; + } + else { + /* in_d < out_d */ + /* out interface stackslot is defined in this basic block */ + +/* ssa_set_def(ls, bptr->nr + 1, ls->new_varindex[out[out_d]]); */ + out_d--; + } + } } +/* ssa_place_phi_functions ***************************************************** + +ls->phi[n][a][p] is created and populated. + +For each basicblock Y in the dominance frontier of a basicblock n (0 <= n < +ls->basicblockcount)in which a variable (0 <= a < ls->ssavarcount) is defined an +entry in ls->phi[Y][a] is created. +This entry is an array with the number of predecessors of Y elements + 1 elements. +This elements are all set to the variable a and represent the phi function which +will get ai = phi(ai1, ai2, ..., aip) after ssa_rename. + +*******************************************************************************/ + -void ssa_place_phi_functions(codegendata *cd, lsradata *ls, graphdata *gd, - dominatordata *dd) +void ssa_place_phi_functions(jitdata *jd, graphdata *gd, dominatordata *dd) { int a,i,j,n,Y; bitvector *def_sites; - bitvector *A_phi; /* [0..ls->basicblockcount[ of ls->max_vars Bit */ + bitvector *A_phi; /* [0..ls->basicblockcount[ of ls->ssavarcount Bit */ worklist *W; int num_pred; - bool add_phi; - stackptr s; + + lsradata *ls; + + ls = jd->ls; W = wl_new(ls->basicblockcount); - def_sites = DMNEW(bitvector, ls->max_vars); - for(a = 0; a < ls->max_vars; a++) + def_sites = DMNEW(bitvector, ls->ssavarcount); + for(a = 0; a < ls->ssavarcount; a++) def_sites[a] = bv_new(ls->basicblockcount); ls->phi = DMNEW(int **, ls->basicblockcount); A_phi = DMNEW(bitvector, ls->basicblockcount); for(i = 0; i < ls->basicblockcount; i++) { - ls->phi[i] = DMNEW(int *, ls->max_vars); - for(j = 0; j < ls->max_vars; j++) + ls->phi[i] = DMNEW(int *, ls->ssavarcount); + for(j = 0; j < ls->ssavarcount; j++) ls->phi[i][j] = NULL; - A_phi[i] = bv_new(ls->max_vars); + A_phi[i] = bv_new(ls->ssavarcount); } - for(n = 0; n < ls->basicblockcount; n++) - for(a = 0; a < ls->max_vars; a++) + /* copy var_def to def_sites */ + /* var_def is valid for 0.. jd->basicblockcount (bb 0 for param init) */ + + for(n = 0; n <= jd->basicblockcount; n++) + for(a = 0; a < ls->ssavarcount; a++) if (bv_get_bit(ls->var_def[n], a)) bv_set_bit(def_sites[a], n); #ifdef SSA_DEBUG_VERBOSE if (compileverbose) { printf("var Definitions:\n"); - for(i = 0; i < ls->max_vars; i++) { + for(i = 0; i < ls->ssavarcount; i++) { printf("def_sites[%3i]=%p:",i,(void *)def_sites[i]); for(j = 0; j < ls->basicblockcount; j++) { if ((j % 5) == 0) printf(" "); @@ -420,8 +596,10 @@ void ssa_place_phi_functions(codegendata *cd, lsradata *ls, graphdata *gd, } #endif - for(a = 0; a < ls->max_vars; a++) { + for(a = 0; a < ls->ssavarcount; a++) { + /* W<-def_sites(a) */ + for(n = 0; n < ls->basicblockcount; n++) if (bv_get_bit(def_sites[a],n)) { wl_add(W, n); @@ -439,57 +617,31 @@ void ssa_place_phi_functions(codegendata *cd, lsradata *ls, graphdata *gd, /* a is not a Element of A_phi[Y] */ /* a <- phi(a,a...,a) to be inserted at top of Block Y */ /* phi has as many arguments, as Y has predecessors */ - +#if 0 #if 0 /* do not add a phi function for interface stackslots */ /* if a predecessor is not a def site of a <==> */ /* the block does not have the corresponding inslot*/ - if ((ls->var_to_index[a] >= 0) || - (bv_get_bit(def_sites[a], - graph_get_first_predecessor(gd, Y, &iter)))) + +/* if ((ls->var_to_index[a] >= 0) || */ +/* (bv_get_bit(def_sites[a], */ +/* graph_get_first_predecessor(gd, Y, &iter)))) */ + #endif /* for interface stackslots add a phi function only */ /* if the basicblock has the corresponding incoming */ /* stackslot -> it could be, that the stackslot is */ /* not live anymore at Y */ -#ifdef SSA_DEBUG_VERBOSE - if (compileverbose) - if (ls->var_to_index[a] < 0) - printf("SS CHeck BB %3i ID %3i V2I %3i A %3i ML %3i\n",Y, - ls->basicblocks[Y]->indepth, - ls->var_to_index[a], a, jd->maxlocals); -#endif - /* Add Locals in any case */ - add_phi = (ls->var_to_index[a] >= 0); - if (!add_phi) { - /* Stackslot */ - s = ls->basicblocks[Y]->instack; - for(i = ls->basicblocks[Y]->indepth-1; i>=0; i--, s = s->prev) { - _SSA_ASSERT(s != 0); -#ifdef SSA_DEBUG_VERBOSE - if (compileverbose) - if (ls->var_to_index[a] < 0) - printf(" Depth %3i Var %3i\n",i, - ls->var[i + jd->maxlocals][s->type]); #endif - if (ls->var[i + jd->maxlocals][s->type] == a) { - add_phi=true; - break; - } - } - } - if (add_phi) - { - num_pred = graph_get_num_predecessor(gd, Y); - ls->phi[Y][a] = DMNEW(int, num_pred + 1); - for (j = 0; j < num_pred + 1; j++) - ls->phi[Y][a][j] = a; - /* increment the number of definitions of a by one */ - /* for this phi function */ - ls->num_defs[a]++; - } - + num_pred = graph_get_num_predecessor(gd, Y); + ls->phi[Y][a] = DMNEW(int, num_pred + 1); + for (j = 0; j < num_pred + 1; j++) + ls->phi[Y][a][j] = a; + /* increment the number of definitions of a by one */ + /* for this phi function */ + ls->num_defs[a]++; + bv_set_bit(A_phi[Y], a); if (bv_get_bit(ls->var_def[Y],a)==0) { /* Iterated Dominance Frontier Criterion:*/ @@ -504,80 +656,286 @@ void ssa_place_phi_functions(codegendata *cd, lsradata *ls, graphdata *gd, } } -void ssa_Rename_init(methodinfo *m, codegendata *cd, lsradata *ls, graphdata *gd) +/* ssa_rename ****************************************************************** + +Rename the variables a (0 <= a < ls->ssavarcount) so that each new variable +has only one definition (SSA form). + +ls->def_count[0..ls->ssavarcount[ holds the number of definitions of each var. +ls->var_0[0..ls->ssavarcount[ will be set to the new index of the first + definition of each old var. +ls->varcount_with_indices will be se to the new maximum varcount of LOCAL + and IOVARS. + +All other vars (TEMPVAR and PREALLOC) will get a new unique index above +ls->varcount_with_indices. + +jd->var and jd->varcount will be set for this renamed vars. + +*******************************************************************************/ + +void ssa_rename(jitdata *jd, graphdata *gd, dominatordata *dd) { + int i, mi, l, j, p, t; + int type, flags; + methoddesc *md = jd->m->parseddesc; + + varinfo *new_vars; + lsradata *ls; + + ls = jd->ls; + + ssa_rename_init(jd, gd); + + /* Consider definition of Local Vars initialized with Arguments */ + /* in Block 0 */ + /* init is regarded as use too-> ssa_rename_use ->bullshit!!*/ + for (p = 0, l= 0; p < md->paramcount; p++) { + t = md->paramtypes[p].type; + mi = l * 5 + t; + i = jd->local_map[mi]; + l++; + if (IS_2_WORD_TYPE(t)) + l++; + if (i == UNUSED) + continue; + /* !!!!! locals are now numbered as the parameters !!!! */ + /* !!!!! no additional increment for 2 word types !!!!! */ + /* this happens later on! here we still need the increment */ + /* index of var can be in the range from 0 up to not including */ + /* CD->maxlocals */ + + /* ignore return value, since first definition gives 0 -> */ + /* no rename necessary */ - int a, i, t, p; - int i_l, i_i; + i = ls->new_varindex[i]; + j = ssa_rename_def_(ls, i); + _SSA_ASSERT(j == 0); + jd->local_map[mi] = i; + } + ssa_rename_(jd, gd, dd, 0); + +#if 0 + /* DO _NOT_ DO THIS! Look at java.util.stringtokenizer.counttokens! */ + /* if there is no use of the defined Var itself by the phi function */ + /* for a loop path, in which this var is not used, it will not be life */ + /* in this path and overwritten! */ + + /* Invalidate all xij from phi(xi0)=xi1,xi2,xi3,..,xin with xij == xi0 */ + /* this happens if the phi function is the first definition of x or in a */ + /* path with a backedge xi has no definition */ + /* a phi(xij) = ...,xij,... with the only use and definition of xij by */ + /* this phi function would otherwise "deadlock" the dead code elemination */ + /* invalidate means set it to ls->max_vars_with_indices */ + /* a phi function phi(xi0)=xi1,xi2,...xin wiht xij == xi0 for all j in */ + /* [1,n] can be removed */ + + for(i = 0; i < ls->ssavarcount; i++) { + for(t = 0; t < ls->basicblockcount; t++) { + if (ls->phi[t][i] != 0) { + remove_phi = true; + for(p = 1; p <= graph_get_num_predecessor(gd, t); p++) { + if (ls->phi[t][i][0] == ls->phi[t][i][p]) + ls->phi[t][i][p] = ls->varcount_with_indices; + else + remove_phi = false; + } + } + if (remove_phi) + ls->phi[t][i] = NULL; + } + } +#endif + +#if defined(SSA_DEBUG_CHECK) || defined(SSA_DEBUG_VERBOSE) +# if defined(SSA_DEBUG_VERBOSE) + if (compileverbose) { + printf("%s %s ",jd->m->class->name->text, jd->m->name->text); + if (jd->isleafmethod) + printf("**Leafmethod**"); + printf("\n"); + } +# endif + if (strcmp(jd->m->class->name->text,"fp")==0) + if (strcmp(jd->m->name->text,"testfloat")==0) +# if defined(SSA_DEBUG_VERBOSE) + if (compileverbose) + printf("12-------------------12\n"); +# else + { int dummy=1; dummy++; } +# endif +#endif + /* recreate rd->locals[][] */ + /* now only one (local_index/type) pair exists anymore */ + /* all var[t][i] with var_to_index[var[t][i]] >= 0 are locals */ + /* max local index after SSA indexing is in ls->local_0[ls->max_locals] */ + + new_vars = DMNEW(varinfo, ls->vartop); + for(i = 0; i < ls->vartop ; i++) + new_vars[i].type = UNUSED; + for(i = 0; i < jd->varcount; i++) { + p = ls->new_varindex[i]; + if (p != UNUSED) { + if (p < ls->ssavarcount) + p = ls->var_0[p]; + new_vars[p].type = VAR(i)->type; + new_vars[p].flags = VAR(i)->flags; + ls->lifetime[p].v_index = p; + ls->lifetime[p].type = VAR(i)->type; + } + } + + /* take care of newly indexed local & in/out vars */ + + for(i = 0; i < ls->ssavarcount; i++) { + j = ls->var_0[i]; + type = new_vars[j].type; + flags = new_vars[j].flags; + j++; + for (; j < ls->var_0[i + 1]; j++) { + new_vars[j].type = type; + new_vars[j].flags = flags; + ls->lifetime[j].v_index = j; + ls->lifetime[j].type = type; + } + } + +#ifdef SSA_DEBUG_VERBOSE + if (compileverbose) { + + printf("ssa_rename: Vars: Orig:%3i SSAVar: %3i\n", jd->varcount, + ls->ssavarcount); + for(i = 0; i < jd->varcount; i++) { + printf("%3i(%3i,%3x) ",i,VAR(i)->type, VAR(i)->flags); + ssa_show_variable(jd, i, VAR(i),0); + j = ls->new_varindex[i]; + if ((j != UNUSED) && (j < ls->ssavarcount)) + printf(" -> %3i ... %3i", ls->var_0[j], ls->var_0[j + 1] - 1); + else + printf(" -> %3i", j); + printf("\n"); + } + } +#endif + + jd->var = new_vars; + jd->varcount = ls->vartop; + jd->vartop = ls->vartop; + +#ifdef SSA_DEBUG_VERBOSE + if (compileverbose) { + printf("ssa_rename: Vars: Orig:%3i SSAVar: %3i\n", jd->varcount, + ls->ssavarcount); + for(i = 0; i < jd->varcount; i++) { + printf("%3i(%3i,%3x) ",i,VAR(i)->type, VAR(i)->flags); + ssa_show_variable(jd, i, VAR(i),0); + printf("\n"); + } + } +#endif +} + +/* ssa_rename_init ************************************************************* + +Setup the data structure for ssa_rename + +ls->def_count[0..ls->ssavarcount[ holds the number of definitions of each var. +ls->var_0[0..ls->ssavarcount[ will be set to the new index of the first + definition of each old var. +ls->varcount_with_indices will be se to the new maximum varcount of LOCAL + and IOVARS. + +All other vars (TEMPVAR and PREALLOC) will get a new unique index above +ls->varcount_with_indices. + +jd->var and jd->varcount will be set for this renamed vars. + +*******************************************************************************/ + +void ssa_rename_init(jitdata *jd, graphdata *gd) +{ + int a, i, p; + lsradata *ls; + + ls = jd->ls; /* set up new locals */ - /* ls->var[index][type] holds the new unique index */ - /* in the range of [0..ls-max_vars[ */ + /* ls->new_varindex[0..jd->varcount[ holds the new unique index */ + /* for locals and iovars */ + /* ls->num_defs[index] gives the number of indizes which will be created */ /* from SSA */ - /* -> vars will be numbered in this sequence: L0(0)..L0(i) L1(0)..L1(j).*/ - /* ls->var[index][type] will point to each LX(0) */ - - /* as first step cummulate the num_defs array */ - /* for locals */ - /* last element is the maximum local count */ - ls->local_0 = DMNEW(int, ls->max_locals + 1); - ls->interface_0 = DMNEW(int, -ls->max_interfaces); - ls->local_0[0] = 0; - ls->interface_0[0] = 0; - ls->max_vars_with_indices = 0; - for(i = 0, i_i = 1, i_l = 1; i < ls->max_vars; i++) { - ls->max_vars_with_indices += ls->num_defs[i]; - if (ls->var_to_index[i] >= 0) { - /* local var */ - ls->local_0[i_l] = ls->local_0[i_l-1] + ls->num_defs[i]; - ls->var_to_index[i] = ls->local_0[i_l-1]; - i_l++; - } else { - /* interface stackslot */ - ls->interface_0[i_i] = ls->interface_0[i_i-1] + ls->num_defs[i]; - ls->var_to_index[i] = -ls->interface_0[i_i-1] - 1; - i_i++; - } + + /* -> vars will be numbered in this sequence: L0(0)..L0(i) L1(0)..L1(j) ..*/ + /* ls->var_0[X] will point to each LX(0) */ + /* ls->var_0[ls->ssavarcount] will hold ls->varcount_with_indices */ + + /* as first step cummulate the num_defs array for locals and iovars */ + /* last element is the maximum var count */ + + ls->var_0 = DMNEW(int, max(1, ls->ssavarcount + 1)); + ls->var_0[0] = 0; + ls->varcount_with_indices = 0; + for(i = 0; i < ls->ssavarcount; i++) { + ls->varcount_with_indices += ls->num_defs[i]; + ls->var_0[i+1] = ls->var_0[i] + ls->num_defs[i]; } +#if 0 /* Change the var indices in phi from La to La(0) */ + for(i = 0; i < ls->basicblockcount; i++) - for (t = 0; t < ls->max_vars; t++) - if (ls->phi[i][t] != NULL) + for (a = 0; a < ls->ssavarcount; a++) + if (ls->phi[i][a] != NULL) for(p = 0; p < graph_get_num_predecessor(gd, i) + 1; p++) - ls->phi[i][t][p] = ls->var_to_index[t]; + ls->phi[i][a][p] = ls->var_0[a]; +#endif /* Initialization */ - ls->count = DMNEW(int, ls->max_vars); - ls->stack = DMNEW(int *, ls->max_vars); - ls->stack_top = DMNEW(int, ls->max_vars); - for(a = 0; a < ls->max_vars; a++) { + + ls->count = DMNEW(int, max(1, ls->ssavarcount)); + ls->stack = DMNEW(int *, max(1, ls->ssavarcount)); + ls->stack_top = DMNEW(int, max(1, ls->ssavarcount)); + for(a = 0; a < ls->ssavarcount; a++) { ls->count[a] = 0; ls->stack_top[a] = 0; + /* stack a has to hold number of defs of a Elements + 1 */ + ls->stack[a] = DMNEW(int, ls->num_defs[a] + 1); ls->stack[a][ls->stack_top[a]++] = 0; } - if (ls->max_locals > 0) { + + if (ls->ssavarcount > 0) { + /* Create the num_var_use Array */ + ls->num_var_use = DMNEW(int *, ls->basicblockcount); for(i = 0; i < ls->basicblockcount; i++) { - ls->num_var_use[i] =DMNEW(int, max(1, ls->local_0[ls->max_locals])); - for(a = 0; a < ls->local_0[ls->max_locals]; a++) + ls->num_var_use[i] =DMNEW(int, max(1, ls->varcount_with_indices)); + for(a = 0; a < ls->varcount_with_indices; a++) ls->num_var_use[i][a] = 0; } + /* Create the use_sites Array of Bitvectors*/ /* use max(1,..), to ensure that the array is created! */ - ls->use_sites = DMNEW(bitvector, max(1, ls->local_0[ls->max_locals])); - for(a = 0; a < ls->local_0[ls->max_locals]; a++) + + ls->use_sites = DMNEW(bitvector, max(1, ls->varcount_with_indices)); + for(a = 0; a < ls->varcount_with_indices; a++) ls->use_sites[a] = bv_new(ls->basicblockcount); } + /* init lifetimes */ + /* count number of TEMPVARs */ + + ls->lifetimecount = 0; + for(i = 0; i < jd->varcount; i++) + if ((i >= jd->localcount) || (!(jd->var[i].flags & (INOUT | PREALLOC)))) + ls->lifetimecount++; - ls->maxlifetimes = /*m*/ ls->maxlifetimes + ls->basicblockcount * m->maxstack; - ls->lifetimecount = ls->maxlifetimes + ls->local_0[ls->max_locals] - + cd->maxstack * 5; + ls->varcount = ls->varcount_with_indices + ls->lifetimecount; + + ls->lifetimecount = ls->varcount; ls->lifetime = DMNEW(struct lifetime, ls->lifetimecount); ls->lt_used = DMNEW(int, ls->lifetimecount); ls->lt_int = DMNEW(int, ls->lifetimecount); @@ -586,14 +944,45 @@ void ssa_Rename_init(methodinfo *m, codegendata *cd, lsradata *ls, graphdata *gd ls->lt_flt_count = 0; ls->lt_mem = DMNEW(int, ls->lifetimecount); ls->lt_mem_count = 0; - for (i=0; i < ls->lifetimecount; i++) ls->lifetime[i].type = -1; + for (i=0; i < ls->lifetimecount; i++) { + ls->lifetime[i].type = UNUSED; + ls->lifetime[i].savedvar = 0; + ls->lifetime[i].flags = 0; + ls->lifetime[i].usagecount = 0; + ls->lifetime[i].bb_last_use = -1; + ls->lifetime[i].bb_first_def = -1; + ls->lifetime[i].use = NULL; + ls->lifetime[i].def = NULL; + ls->lifetime[i].last_use = NULL; + } + /* for giving TEMP and PREALLOC vars a new unique index */ + + ls->vartop = ls->varcount_with_indices; + +#ifdef SSA_DEBUG_VERBOSE + if (compileverbose) { + printf("ssa_rename_init: Vars: Orig:%3i SSAVar: %3i\n", jd->varcount, + ls->ssavarcount); + for(i = 0; i < jd->varcount; i++) { + if ((i < jd->localcount) || ( VAR(i)->flags & INOUT)) { + printf("%3i(%3i,%3x) ",i,VAR(i)->type, VAR(i)->flags); + ssa_show_variable(jd, i, VAR(i),0); + if ((i < ls->ssavarcount) || (VAR(i)->flags & INOUT)) { + printf(" -> %3i", ls->new_varindex[i]); + } + printf("\n"); + } + } + ssa_print_phi(ls, gd); + } +#endif } -int ssa_Rename_def(lsradata *ls, int n, int a) { +int ssa_rename_def_(lsradata *ls, int a) { int i; - _SSA_CHECK_BOUNDS(a,0,ls->max_vars); + _SSA_CHECK_BOUNDS(a,0,ls->ssavarcount); ls->count[a]++; i = ls->count[a] - 1; /* push i on stack[a] */ @@ -602,393 +991,375 @@ int ssa_Rename_def(lsradata *ls, int n, int a) { return i; } -void ssa_Rename_use(lsradata *ls, int n, int a) { - if (ls->max_locals > 0) { +int ssa_rename_def(jitdata *jd, int *def_count, int a) { + int i, a1, ret; + lsradata *ls; + + ls = jd->ls; + + a1 = ls->new_varindex[a]; + _SSA_CHECK_BOUNDS(a1, UNUSED, ls->varcount); + if ((a1 != UNUSED) && (a1 < ls->ssavarcount)) { + /* local or inoutvar -> normal ssa renaming */ + _SSA_ASSERT((a < jd->localcount) || (VAR(a)->flags & INOUT)); + /* !IS_TEMPVAR && !IS_PREALLOC == (IS_LOCALVAR || IS_INOUT) */ + + def_count[a1]++; + i = ssa_rename_def_(ls, a1); + ret = ls->var_0[a1] + i; + } + else { + /* TEMP or PREALLOC var */ + if (a1 == UNUSED) { + ls->new_varindex[a] = ls->vartop; + ret = ls->vartop; + ls->vartop++; + _SSA_ASSERT( ls->vartop < ls->varcount); + } + else + ret = a1; + } + return ret; +} + +void ssa_rename_use_(lsradata *ls, int n, int a) { + _SSA_CHECK_BOUNDS(a, 0, ls->varcount_with_indices); + if (ls->ssavarcount > 0) { bv_set_bit(ls->use_sites[a], n); ls->num_var_use[n][a]++; } } -void ssa_Rename_(codegendata *cd, lsradata *ls, graphdata *gd, - dominatordata *dd, int n) { - int a, i, j, k, iindex, Y; +int ssa_rename_use(lsradata *ls, int n, int a) { + int a1, i; + int ret; + + a1 = ls->new_varindex[a]; + _SSA_CHECK_BOUNDS(a1, UNUSED, ls->varcount); + if ((a1 != UNUSED) && (a1 < ls->ssavarcount)) { + /* local or inoutvar -> normal ssa renaming */ + /* i <- top(stack[a]) */ + + _SSA_CHECK_BOUNDS(ls->stack_top[a1]-1, 0, ls->num_defs[a1]+1); + i = ls->stack[a1][ls->stack_top[a1] - 1]; + _SSA_CHECK_BOUNDS(i, 0, ls->num_defs[a1]); + + ret = ls->var_0[a1] + i; + } + else { + /* TEMP or PREALLOC var */ + if (a1 == UNUSED) { + ls->new_varindex[a] = ls->vartop; + ret = ls->vartop; + ls->vartop++; + _SSA_ASSERT( ls->vartop < ls->varcount); + } + else + ret = a1; + } + + return ret; +} + +#ifdef SSA_DEBUG_VERBOSE +void ssa_rename_print(instruction *iptr, char *op, int from, int to) { + if (compileverbose) { + printf("ssa_rename_: "); + if (iptr != NULL) + printf("%s ", opcode_names[iptr->opc]); + else + printf(" "); + + printf("%s: %3i->%3i\n", op, from, to); + } +} +#endif + +void ssa_rename_(jitdata *jd, graphdata *gd, dominatordata *dd, int n) { + int a, i, j, k, iindex, Y, v; int in_d, out_d; - instruction *iptr; - int *def_count; - /* [0..ls->max_vars[ Number of Definitions of this var in this */ + int *def_count; + /* [0..ls->varcount[ Number of Definitions of this var in this */ /* Basic Block. Used to remove the entries off the stack at the */ /* end of the function */ - - stackptr in, out; + instruction *iptr; + s4 *in, *out, *argp; graphiterator iter_succ, iter_pred; struct lifetime *lt; + methoddesc *md; + methodinfo *m; + builtintable_entry *bte; + lsradata *ls; + + ls = jd->ls; + m = jd->m; + +#ifdef SSA_DEBUG_VERBOSE + if (compileverbose) + printf("ssa_rename_: BB %i\n",n); +#endif + _SSA_CHECK_BOUNDS(n, 0, ls->basicblockcount); - def_count = DMNEW(int, ls->max_vars); - for(i = 0; i < ls->max_vars; i++) + def_count = DMNEW(int, max(1, ls->ssavarcount)); + for(i = 0; i < ls->ssavarcount; i++) def_count[i] = 0; - /* change Store of possible phi functions from a0 to ai*/ - for(a = 0; a < ls->max_vars; a++) + /* change Store of possible phi functions from a to ai*/ + + for(a = 0; a < ls->ssavarcount; a++) if (ls->phi[n][a] != NULL) { def_count[a]++; /* do not mark this store as use - maybee this phi function */ /* can be removed for unused Vars*/ - if (ls->var_to_index[a] >= 0) - /* local var */ - ls->phi[n][a][0] += ssa_Rename_def(ls, n, a); - else - /* interface */ - ls->phi[n][a][0] -= ssa_Rename_def(ls, n, a); + j = ls->var_0[a] + ssa_rename_def_(ls, a); +#ifdef SSA_DEBUG_VERBOSE + ssa_rename_print( NULL, "phi-st", ls->phi[n][a][0], j); +#endif + ls->phi[n][a][0] = j; } - in = ls->basicblocks[n]->instack; - in_d = ls->basicblocks[n]->indepth; + in = ls->basicblocks[n]->invars; + in_d = ls->basicblocks[n]->indepth - 1; + /* change use of instack Interface stackslots except top SBR and EXH */ /* stackslots */ + if ((ls->basicblocks[n]->type == BBTYPE_EXH) || (ls->basicblocks[n]->type == BBTYPE_SBR)) { in_d--; - in = in->prev; } - out = ls->basicblocks[n]->outstack; - out_d = ls->basicblocks[n]->outdepth; +/* out = ls->basicblocks[n]->outvars; */ +/* out_d = ls->basicblocks[n]->outdepth - 1; */ + +/* for(; out_d > in_d; out_d--); */ - for(;out_d > in_d; out = out->prev, out_d--); + for (; in_d >= 0; in_d--) { + /* Possible Use of ls->new_varindex[jd->var[in_d]] */ + _SSA_ASSERT(ls->new_varindex[in[in_d]] != UNUSED); + + a = ls->new_varindex[in[in_d]]; + _SSA_CHECK_BOUNDS(a, 0, ls->ssavarcount); - for (;in != NULL; in = in->prev, in_d--) { - /* Possible Use of */ - /* ls->var[in_d - 1 + jd->maxlocals][in->type] */ - _SSA_CHECK_BOUNDS(in_d - 1 + jd->maxlocals, 0, jd->maxlocals + cd->maxstack); - a = ls->var[in_d - 1 + jd->maxlocals][in->type]; - _SSA_CHECK_BOUNDS(a, 0, ls->max_vars); /* i <- top(stack[a]) */ + _SSA_CHECK_BOUNDS(ls->stack_top[a]-1, 0, ls->num_defs[a]+1); i = ls->stack[a][ls->stack_top[a]-1]; _SSA_CHECK_BOUNDS(i, 0, ls->num_defs[a]); + /* Replace use of x with xi */ + #ifdef SSA_DEBUG_VERBOSE - if (compileverbose) - printf("Ren Use:BB %3i: stackslot: depth %3i old val: %3i Var,0: %3i varind: %3i\n", n, in_d, in->varnum, ls->var_to_index[a], ls->var_to_index[a]-i); + ssa_rename_print( NULL, "invar", in[in_d], ls->var_0[a]+i); #endif - in->varnum = ls->var_to_index[a] - i; - lt = &(ls->lifetime[-in->varnum-1]); - lt->v_index = in->varnum; + in[in_d] = ls->var_0[a] + i; + lt = ls->lifetime + in[in_d]; + + lt->v_index = in[in_d]; lt->bb_last_use = -1; - lsra_add_ss(lt, in); - in->varkind = TEMPVAR; } - in = ls->basicblocks[n]->instack; - + iptr = ls->basicblocks[n]->iinstr; + for(iindex = 0; iindex < ls->basicblocks[n]->icount; iindex++, iptr++) { - switch(iptr->opc) { - case ICMD_ILOAD: - case ICMD_LLOAD: - case ICMD_FLOAD: - case ICMD_DLOAD: - case ICMD_ALOAD: - _SSA_CHECK_BOUNDS(iptr->op1, 0, jd->maxlocals); - a = ls->var[iptr->op1][iptr->opc - ICMD_ILOAD]; - _SSA_CHECK_BOUNDS(a, 0, ls->max_vars); - /* i <- top(stack[a]) */ - _SSA_CHECK_BOUNDS(ls->stack_top[a]-1, 0, ls->num_defs[a]+1); - i = ls->stack[a][ls->stack_top[a]-1]; - _SSA_CHECK_BOUNDS(i, 0, ls->num_defs[a]); - /* Replace use of x with xi */ -#if 0 - /* there are no LOCALVAR Stackslots with SSA */ - if ((iptr->dst->varkind == LOCALVAR) && - (iptr->dst->varnum == iptr->op1)) - iptr->dst->varnum = ls->var_to_index[a] + i; -#endif - iptr->op1 = ls->var_to_index[a] + i; - ssa_Rename_use(ls, n, ls->var_to_index[a] + i); + /* check for use (s1, s2, s3 or special (argp) ) */ - break; - case ICMD_ISTORE: - case ICMD_LSTORE: - case ICMD_FSTORE: - case ICMD_DSTORE: - case ICMD_ASTORE: - /* replace definition of a with def of ai */ - _SSA_CHECK_BOUNDS(iptr->op1, 0, jd->maxlocals); - a = ls->var[iptr->op1][iptr->opc - ICMD_ISTORE]; - _SSA_CHECK_BOUNDS(a, 0, ls->max_vars); - def_count[a]++; + switch (icmd_table[iptr->opc].dataflow) { + case DF_3_TO_0: + case DF_3_TO_1: /* icmd has s1, s2 and s3 */ + j = ssa_rename_use(ls, n, iptr->sx.s23.s3.varindex); +#ifdef SSA_DEBUG_VERBOSE + ssa_rename_print( iptr, "s3 ", iptr->sx.s23.s3.varindex, j); +#endif + iptr->sx.s23.s3.varindex = j; - i = ssa_Rename_def(ls, n, a); - _SSA_CHECK_BOUNDS(i, 0, ls->num_defs[a]); + /* now "fall through" for handling of s2 and s1 */ - iptr->op1 = ls->var_to_index[a] + i; - /* Mark Def as use, too. Since param initialisation is in var_def */ - /* and this would not remove this locals, if not used elsewhere */ - ssa_Rename_use(ls, n, ls->var_to_index[a] + i); - break; - case ICMD_IINC: - - /* Load from iptr->op1 */ - _SSA_CHECK_BOUNDS(iptr->op1, 0, jd->maxlocals); - a = ls->var[iptr->op1][TYPE_INT]; - _SSA_CHECK_BOUNDS(a, 0, ls->max_vars); - /* i <- top(stack[a]) */ - _SSA_CHECK_BOUNDS(ls->stack_top[a]-1, 0, ls->num_defs[a]+1); - i = ls->stack[a][ls->stack_top[a]-1]; - _SSA_CHECK_BOUNDS(i, 0, ls->num_defs[a]); - /* Replace use of x with xi */ - iptr->op1 = ls->var_to_index[a] + i; - - ssa_Rename_use(ls, n, ls->var_to_index[a] + i); - /* Store new(iinced) value in iptr->val._i.opq_t */ - - /* replace definition of a with def of ai */ - _SSA_CHECK_BOUNDS(iptr->val._i.op1_t, 0, jd->maxlocals); - a = ls->var[iptr->val._i.op1_t][TYPE_INT]; - _SSA_CHECK_BOUNDS(a, 0, ls->max_vars); - def_count[a]++; + case DF_2_TO_0: + case DF_2_TO_1: /* icmd has s1 and s2 */ + j = ssa_rename_use(ls, n, iptr->sx.s23.s2.varindex); +#ifdef SSA_DEBUG_VERBOSE + ssa_rename_print( iptr, "s2 ", iptr->sx.s23.s2.varindex, j); +#endif + iptr->sx.s23.s2.varindex = j; - i = ssa_Rename_def(ls, n, a); - _SSA_CHECK_BOUNDS(i, 0, ls->num_defs[a]); + /* now "fall through" for handling of s1 */ - iptr->val._i.op1_t = ls->var_to_index[a] + i; - /* Mark Def as use, too. Since param initialisation is in var_def */ - /* and this would not remove this locals, if not used elsewhere */ - ssa_Rename_use(ls, n, ls->var_to_index[a] + i); + case DF_1_TO_0: + case DF_1_TO_1: + case DF_MOVE: + case DF_COPY: + j = ssa_rename_use(ls, n, iptr->s1.varindex); +#ifdef SSA_DEBUG_VERBOSE + ssa_rename_print( iptr, "s1 ", iptr->s1.varindex, j); +#endif + iptr->s1.varindex = j; + break; + case DF_INVOKE: + case DF_BUILTIN: + case DF_N_TO_1: + /* do not use md->paramcount, pass-through stackslots have */ + /* to be renamed, too */ + i = iptr->s1.argcount; + argp = iptr->sx.s23.s2.args; + while (--i >= 0) { + j = ssa_rename_use(ls, n, *argp); +#ifdef SSA_DEBUG_VERBOSE + ssa_rename_print( iptr, "arg", *argp, j); +#endif + *argp = j; + argp++; + } break; } - in = iptr->dst; - } - /* change def of outstack Interface stackslots */ - in = ls->basicblocks[n]->instack; - in_d = ls->basicblocks[n]->indepth; - out = ls->basicblocks[n]->outstack; - out_d = ls->basicblocks[n]->outdepth; - - for(;in_d > out_d; in = in->prev, in_d--); - - for (;out != NULL; out = out->prev, out_d--) { - if ((in_d < out_d) || (out != in)) { - /* Def of ls->var[out_d - 1 + jd->maxlocals][out->type] */ - _SSA_CHECK_BOUNDS(out_d - 1 + jd->maxlocals, 0, jd->maxlocals + cd->maxstack); - a = ls->var[out_d - 1 + jd->maxlocals][out->type]; - _SSA_CHECK_BOUNDS(a, 0, ls->max_vars); - def_count[a]++; - i = ssa_Rename_def(ls, n, a); - _SSA_CHECK_BOUNDS(i, 0, ls->num_defs[a]); - /* Replace use of x with xi */ - #ifdef SSA_DEBUG_VERBOSE - if (compileverbose) - printf("Ren def:BB %3i: stackslot: depth %3i old val: %3i Var,0: %3i varind: %3i\n", n, in_d, out->varnum, ls->var_to_index[a], ls->var_to_index[a]-i); -#endif - out->varnum = ls->var_to_index[a] - i; - lt = &(ls->lifetime[-out->varnum-1]); - out->varkind = TEMPVAR; - lt->v_index = out->varnum; - lsra_add_ss(lt, out); - ls->lifetime[-out->varnum-1].bb_last_use = -1; - } - if (out_d == in_d) { - in_d--; - in = in->prev; - } - } - - /* change phi Functions of Successors */ - Y = graph_get_first_successor(gd, n, &iter_succ); - for(; Y != -1; Y = graph_get_next(&iter_succ)) { - _SSA_CHECK_BOUNDS(Y, 0, ls->basicblockcount); - k = graph_get_first_predecessor(gd, Y, &iter_pred); - for (j = 0; (k != -1) && (k != n); j++, k = graph_get_next(&iter_pred)); - _SSA_ASSERT(k == n); - /* n is jth Predecessor of Y */ - for(a = 0; a < ls->max_vars; a++) - if (ls->phi[Y][a] != NULL) { - /* i <- top(stack[a]) */ - _SSA_CHECK_BOUNDS(ls->stack_top[a]-1, 0, ls->num_defs[a]+1); - i = ls->stack[a][ls->stack_top[a]-1]; - _SSA_CHECK_BOUNDS(i, 0, ls->num_defs[a]); - /* change jth operand from a0 to ai */ - if (ls->var_to_index[a] >= 0) { - /* local var */ - ls->phi[Y][a][j+1] += i; - _SSA_CHECK_BOUNDS(ls->phi[Y][a][j+1], 0, - ls->local_0[ls->max_locals]); - /* use by phi function has to be remembered, too */ - ssa_Rename_use(ls, n, ls->phi[Y][a][j+1]); - } else { - /* interface */ - ls->phi[Y][a][j+1] -= i; -/* _SSA_CHECK_BOUNDS(ls->phi[Y][a][j+1], */ -/* ls->interface_0[-ls->max_interfaces-1], 0); */ - } - } - } - - /* Call ssa_Rename_ for all Childs of n of the Dominator Tree */ - for(i = 0; i < ls->basicblockcount; i++) - if (dd->idom[i] == n) - ssa_Rename_(cd, ls, gd, dd, i); - /* pop Stack[a] for each definition of a var a in the original S */ - for(a = 0; a < ls->max_vars; a++) { - ls->stack_top[a] -= def_count[a]; - _SSA_ASSERT(ls->stack_top[a] >= 0); - } -} + /* Look for definitions (iptr->dst). INVOKE and BUILTIN have */ + /* an optional dst - so they to be checked first */ -void ssa_Rename(methodinfo *m, codegendata *cd, registerdata *rd, lsradata *ls, - graphdata *gd, dominatordata *dd) -{ - int i, p, t, type, flags; - methoddesc *md = m->parseddesc; + v = UNUSED; + if (icmd_table[iptr->opc].dataflow == DF_INVOKE) { + INSTRUCTION_GET_METHODDESC(iptr,md); + if (md->returntype.type != TYPE_VOID) + v = iptr->dst.varindex; + } + else if (icmd_table[iptr->opc].dataflow == DF_BUILTIN) { + bte = iptr->sx.s23.s3.bte; + md = bte->md; + if (md->returntype.type != TYPE_VOID) + v = iptr->dst.varindex; + } + else if (icmd_table[iptr->opc].dataflow >= DF_DST_BASE) { + v = iptr->dst.varindex; + } - varinfo5 *locals; + if (v != UNUSED) { + j = ssa_rename_def(jd, def_count, iptr->dst.varindex); #ifdef SSA_DEBUG_VERBOSE - int j; + ssa_rename_print( iptr, "dst", iptr->dst.varindex, j); #endif + iptr->dst.varindex = j; + } - if (ls->max_vars == 0) { - /* no locals or interfaces to rename */ - /* init lifetimes */ + /* ?????????????????????????????????????????????????????????? */ + /* Mark Def as use, too. Since param initialisation is in */ + /* var_def and this would not remove this locals, if not used */ + /* elsewhere */ + /* ?????????????????????????????????????????????????????????? */ - ls->maxlifetimes = /*m*/ ls->maxlifetimes + ls->basicblockcount * m->maxstack; - ls->lifetimecount = ls->maxlifetimes + ls->max_locals + cd->maxstack *5; - ls->lifetime = DMNEW(struct lifetime, ls->lifetimecount); - ls->lt_used = DMNEW(int, ls->lifetimecount); - ls->lt_int = DMNEW(int, ls->lifetimecount); - ls->lt_int_count = 0; - ls->lt_flt = DMNEW(int, ls->lifetimecount); - ls->lt_flt_count = 0; - ls->lt_mem = DMNEW(int, ls->lifetimecount); - ls->lt_mem_count = 0; - for (i=0; i < ls->lifetimecount; i++) ls->lifetime[i].type = -1; - return; } - - ssa_Rename_init(m, cd, ls, gd); - /* Consider definition of Local Vars initialized with Arguments */ - /* in Block 0 */ - /* init is regarded as use too-> ssa_Rename_use ->bullshit!!*/ - for (p = 0, i= 0; p < md->paramcount; p++) { - t = md->paramtypes[p].type; + /* change outstack Interface stackslots */ + out = ls->basicblocks[n]->outvars; + out_d = ls->basicblocks[n]->outdepth - 1; - /* !!!!! locals are now numbered as the parameters !!!! */ - /* !!!!! no additional increment for 2 word types !!!!! */ - /* this happens later on! here we still need the increment */ - /* index of var can be in the range from 0 up to not including */ - /* jd->maxlocals */ - _SSA_CHECK_BOUNDS(i,0,jd->maxlocals); - _SSA_CHECK_BOUNDS(ls->var[i][t], 0, ls->local_0[ls->max_locals]); - ssa_Rename_def(ls, 0, ls->var[i][t]); - i++; - if (IS_2_WORD_TYPE(t)) - i++; - } - ssa_Rename_(cd, ls, gd, dd, 0); + for (;out_d >= 0; out_d--) { + /* Possible Use of ls->new_varindex[jd->var[out_d]] */ + _SSA_ASSERT(ls->new_varindex[out[out_d]] != UNUSED); -#if 0 - /* DO _NOT_ DO THIS! Look at java.util.stringtokenizer.counttokens! */ - /* if there is no use of the defined Var itself by the phi function */ - /* for an loop path, in which this var is not used, it will not be life */ - /* in this path and overwritten! */ + a = ls->new_varindex[out[out_d]]; + _SSA_CHECK_BOUNDS(a, 0, ls->ssavarcount); - /* Invalidate all xij from phi(xi0)=xi1,xi2,xi3,..,xin with xij == xi0 */ - /* this happens if the phi function is the first definition of x or in a */ - /* path with a backedge xi has no definition */ - /* a phi(xij) = ...,xij,... with the only use and definition of xij by */ - /* this phi function would otherwise "deadlock" the dead code elemination */ - /* invalidate means set it to ls->max_vars_with_indices */ - /* a phi function phi(xi0)=xi1,xi2,...xin wiht xij == xi0 for all j in */ - /* [1,n] can be removed */ + /* i <- top(stack[a]) */ - for(i = 0; i < ls->max_vars; i++) { - for(t = 0; t < ls->basicblockcount; t++) { - if (ls->phi[t][i] != 0) { - remove_phi = true; - for(p = 1; p <= graph_get_num_predecessor(gd, t); p++) { - if (ls->phi[t][i][0] == ls->phi[t][i][p]) - ls->phi[t][i][p] = ls->max_vars_with_indices; - else - remove_phi = false; - } - } - if (remove_phi) - ls->phi[t][i] = NULL; - } - } -#endif + _SSA_CHECK_BOUNDS(ls->stack_top[a]-1, 0, ls->num_defs[a]+1); + i = ls->stack[a][ls->stack_top[a]-1]; + _SSA_CHECK_BOUNDS(i, 0, ls->num_defs[a]); + + /* Replace use of x with xi */ - /* recreate rd->locals[][] */ - /* now only one (local_index/type) pair exists anymore */ - /* all var[t][i] with var_to_index[var[t][i]] >= 0 are locals */ - /* max local index after SSA indexing is in ls->local_0[ls->max_locals] */ - - locals = DMNEW(varinfo5, ls->local_0[ls->max_locals]); - for(i = 0; i < ls->local_0[ls->max_locals] ; i++) - for(t = 0; t < 5; t++) - locals[i][t].type = -1; - for(t = 0; t < 5; t++) { - for(i = 0; i < jd->maxlocals; i++) { - p = ls->var[i][t]; - if (p != -1) { - _SSA_ASSERT(ls->var_to_index[p] >= 0); - /* It's a local variable */ - p = ls->var_to_index[p]; - locals[p][t].type = t; - locals[p][t].flags = rd->locals[i][t].flags; #ifdef SSA_DEBUG_VERBOSE - if (compileverbose) - printf("locals %3i %3i .type = %3i\n",p,t,t); + ssa_rename_print( NULL, "outvar", out[out_d], ls->var_0[a]+i); #endif - } - } + out[out_d] = ls->var_0[a] + i; + lt = ls->lifetime + out[out_d]; + + lt->v_index = out[out_d]; + lt->bb_last_use = -1; } - - type = -1; - flags = -1; + + /* change use in phi Functions of Successors */ + + Y = graph_get_first_successor(gd, n, &iter_succ); + for(; Y != -1; Y = graph_get_next(&iter_succ)) { + _SSA_CHECK_BOUNDS(Y, 0, ls->basicblockcount); + k = graph_get_first_predecessor(gd, Y, &iter_pred); + for (j = 0; (k != -1) && (k != n); j++) + k = graph_get_next(&iter_pred); + _SSA_ASSERT(k == n); + + /* n is jth Predecessor of Y */ + + for(a = 0; a < ls->ssavarcount; a++) + if (ls->phi[Y][a] != NULL) { + + /* i <- top(stack[a]) */ + + if (ls->stack_top[a] == 1) { + /* no definition till now in controll flow */ #ifdef SSA_DEBUG_VERBOSE - p = -1; - j = 0; + if (compileverbose) { + printf("Succ %3i Arg %3i \n", Y, j); + ssa_rename_print( NULL, "phi-use", ls->phi[Y][a][j+1], UNUSED); + } #endif - for(i = 0; i < ls->local_0[ls->max_locals]; i++) { - for(t = 0; (t < 5) && (locals[i][t].type == -1); t++); - if (t == 5) { - _SSA_ASSERT(type != -1); + ls->phi[Y][a][j+1] = UNUSED; + } + else { + _SSA_CHECK_BOUNDS(ls->stack_top[a]-1, 0, ls->num_defs[a]+1); + i = ls->stack[a][ls->stack_top[a]-1]; + _SSA_CHECK_BOUNDS(i, 0, ls->num_defs[a]); + + /* change jth operand from a0 to ai */ + + i = ls->var_0[a] + i; #ifdef SSA_DEBUG_VERBOSE - if (compileverbose) { - printf("L%3i=L%3i(%3i) type %3i\n",i,p,j,type); - j++; - } + if (compileverbose) { + printf("Succ %3i Arg %3i \n", Y, j); + ssa_rename_print( NULL, "phi-use", ls->phi[Y][a][j+1], i); + } #endif - locals[i][type].type = type; - locals[i][type].flags = flags; - } else { - type = locals[i][t].type; - flags = locals[i][t].flags; -#ifdef SSA_DEBUG_VERBOSE - if (compileverbose) { - j=0; - p++; - printf("L%3i=L%3i(%3i) type %3i\n",i,p,j,type); - j++; + ls->phi[Y][a][j+1] = i; + _SSA_CHECK_BOUNDS(ls->phi[Y][a][j+1], 0, + ls->varcount_with_indices); + + /* use by phi function has to be remembered, too */ + + ssa_rename_use_(ls, n, ls->phi[Y][a][j+1]); + } + + /* ????????????????????????????????????????????? */ + /* why was this only for local vars before ? */ + /* ????????????????????????????????????????????? */ + } -#endif - } } - rd->locals = locals; - jd->maxlocals = ls->local_0[ls->max_locals]; + + /* Call ssa_rename_ for all Childs of n of the Dominator Tree */ + for(i = 0; i < ls->basicblockcount; i++) + if (dd->idom[i] == n) + ssa_rename_(jd, gd, dd, i); + + /* pop Stack[a] for each definition of a var a in the original S */ + for(a = 0; a < ls->ssavarcount; a++) { + ls->stack_top[a] -= def_count[a]; + _SSA_ASSERT(ls->stack_top[a] >= 0); + } } + + #ifdef SSA_DEBUG_VERBOSE -void ssa_print_trees(methodinfo *m, codegendata *cd, lsradata *ls, - graphdata *gd, dominatordata *dd) { +void ssa_print_trees(jitdata *jd, graphdata *gd, dominatordata *dd) { int i,j; - printf("ssa_printtrees: maxlocals %3i", jd->maxlocals); + lsradata *ls; + + ls = jd->ls; + + printf("ssa_printtrees: maxlocals %3i", jd->localcount); printf("Dominator Tree: \n"); for(i = 0; i < ls->basicblockcount; i++) { @@ -1009,10 +1380,10 @@ void ssa_print_trees(methodinfo *m, codegendata *cd, lsradata *ls, } printf("\n"); } - - if (ls->max_locals > 0) { +#if 0 + if (ls->ssavarcount > 0) { printf("Use Sites\n"); - for(i = 0; i < ls->max_locals; i++) { + for(i = 0; i < ls->ssavarcount; i++) { printf("use_sites[%3i]=%p:",i,(void *)ls->use_sites[i]); for(j = 0; j < ls->basicblockcount; j++) { if ((j % 5) == 0) printf(" "); @@ -1024,11 +1395,11 @@ void ssa_print_trees(methodinfo *m, codegendata *cd, lsradata *ls, printf("\n"); } } - +#endif printf("var Definitions:\n"); - for(i = 0; i < ls->basicblockcount; i++) { + for(i = 0; i < jd->basicblockcount; i++) { printf("var_def[%3i]=%p:",i,(void *)ls->var_def[i]); - for(j = 0; j < ls->max_vars; j++) { + for(j = 0; j < ls->ssavarcount; j++) { if ((j % 5) == 0) printf(" "); if (bv_get_bit(ls->var_def[i], j)) printf("1"); @@ -1036,20 +1407,20 @@ void ssa_print_trees(methodinfo *m, codegendata *cd, lsradata *ls, printf("0"); } printf(" ("); - for(j=0; j < ((((ls->max_vars * 5+7)/8) + sizeof(int) - 1)/sizeof(int)); + for(j=0; j < ((((ls->ssavarcount * 5+7)/8) + sizeof(int) - 1)/sizeof(int)); j++) printf("%8x",ls->var_def[i][j]); - printf("\n"); + printf(")\n"); } } void ssa_print_phi(lsradata *ls, graphdata *gd) { int i,j,k; - printf("phi Functions (max_vars_with_indices: %3i):\n", - ls->max_vars_with_indices); + printf("phi Functions (varcount_with_indices: %3i):\n", + ls->varcount_with_indices); for(i = 0; i < ls->basicblockcount; i++) { - for(j = 0; j < ls->max_vars; j++) { + for(j = 0; j < ls->ssavarcount; j++) { if (ls->phi[i][j] != NULL) { printf("BB %3i %3i = phi(", i, ls->phi[i][j][0]); for(k = 1; k <= graph_get_num_predecessor(gd, i); k++) @@ -1063,20 +1434,39 @@ void ssa_print_phi(lsradata *ls, graphdata *gd) { #endif -void ssa_generate_phi_moves(lsradata *ls, graphdata *gd) { +void ssa_generate_phi_moves(jitdata *jd, graphdata *gd) { int a, i, j, pred; graphiterator iter; + lsradata *ls; + + ls = jd->ls; /* count moves to be inserted at the end of each block in moves[] */ ls->num_phi_moves = DMNEW(int, ls->basicblockcount); for(i = 0; i < ls->basicblockcount; i++) ls->num_phi_moves[i] = 0; for(i = 0; i < ls->basicblockcount; i++) - for(a = 0; a < ls->max_vars; a++) + for(a = 0; a < ls->ssavarcount; a++) if (ls->phi[i][a] != NULL) { - pred = graph_get_first_predecessor(gd, i, &iter); - for(; pred != -1; pred = graph_get_next(&iter)) { - ls->num_phi_moves[pred]++; +#if 0 + if (ls->lifetime[ls->phi[i][a][0]].use == NULL) { + /* Var defined (only <- SSA Form!) in this phi function */ + /* and not used anywhere -> delete phi function and set */ + /* var to unused */ + + /* TODO: first delete use sites of arguments of phi */ + /* function */ + VAR(ls->lifetime[ls->phi[i][a][0]].v_index)->type = UNUSED; + ls->lifetime[ls->phi[i][a][0]].def = NULL; + ls->phi[i][a] = NULL; + } + else +#endif + { + pred = graph_get_first_predecessor(gd, i, &iter); + for(; pred != -1; pred = graph_get_next(&iter)) { + ls->num_phi_moves[pred]++; + } } } @@ -1086,24 +1476,29 @@ void ssa_generate_phi_moves(lsradata *ls, graphdata *gd) { ls->phi_moves[i] = DMNEW( int *, ls->num_phi_moves[i]); for(j = 0; j num_phi_moves[i]; j++) ls->phi_moves[i][j] = DMNEW(int, 2); +#ifdef SSA_DEBUG_VERBOSE + if (compileverbose) + printf("ssa_generate_phi_moves: ls_num_phi_moves[%3i] = %3i\n", + i, ls->num_phi_moves[i]); +#endif } /* populate ls->phi_moves */ for(i = 0; i < ls->basicblockcount; i++) ls->num_phi_moves[i] = 0; for(i = 0; i < ls->basicblockcount; i++) - for(a = 0; a < ls->max_vars; a++) + for(a = 0; a < ls->ssavarcount; a++) if (ls->phi[i][a] != NULL) { pred = graph_get_first_predecessor(gd, i, &iter); for(j = 0; pred != -1; j++, pred = graph_get_next(&iter)) { /* target is phi[i][a][0] */ /* source is phi[i][a][j+1] */ - if (ls->phi[i][a][j+1] != ls->max_vars_with_indices) { + if (ls->phi[i][a][j+1] != ls->varcount_with_indices) { /* valid move */ if (ls->phi[i][a][0] != ls->phi[i][a][j+1]) { ls->phi_moves[pred][ls->num_phi_moves[pred]][0] = ls->phi[i][a][0]; - ls->phi_moves[pred][(ls->num_phi_moves[pred])++][1] = + ls->phi_moves[pred][(ls->num_phi_moves[pred])++][1]= ls->phi[i][a][j+1]; } } @@ -1111,129 +1506,32 @@ void ssa_generate_phi_moves(lsradata *ls, graphdata *gd) { } } - -void ssa(jitdata *jd, graphdata *gd) { - struct dominatordata *dd; - methodinfo *m; - codegendata *cd; - registerdata *rd; - lsradata *ls; - - m = jd->m; - cd = jd->cd; - rd = jd->rd; - ls = jd->ls; - - dd = compute_Dominators(gd, ls->basicblockcount); - computeDF(gd, dd, ls->basicblockcount, 0); - - ssa_place_phi_functions(cd, ls, gd, dd); - ssa_Rename(m, cd, rd, ls, gd, dd); -#ifdef SSA_DEBUG_VERBOSE - if (compileverbose) { - printf("Phi before Cleanup\n"); - ssa_print_phi(ls, gd); - ssa_print_lt(ls); - } -#endif - scan_lifetimes(m, cd, rd, ls, gd, dd); -#ifdef SSA_DEBUG_VERBOSE - if (compileverbose) { - ssa_print_lt(ls); - } -#endif - dead_code_elimination(m, rd, ls, gd); -#ifdef SSA_DEBUG_VERBOSE - if (compileverbose) { - printf("Phi after dead code elemination\n"); - ssa_print_phi(ls, gd); - ssa_print_lt(ls); - } -#endif - copy_propagation(m, rd, ls, gd); -#ifdef SSA_DEBUG_VERBOSE - if (compileverbose) { - printf("Phi after copy propagation\n"); - ssa_print_phi(ls, gd); - ssa_print_lt(ls); - } -#endif - - ssa_generate_phi_moves(ls, gd); - transform_BB(jd, gd); - - -#ifdef SSA_DEBUG_CHECK - { - int i, j, pred, in_d, out_d; - graphiterator iter_pred; - stackptr in, out; - bool phi_define; - - for(i = 0; i < ls->basicblockcount; i++) { - if (ls->basicblocks[i]->indepth != 0) { - pred = graph_get_first_predecessor(gd, i, &iter_pred); - for (; (pred != -1); pred = graph_get_next(&iter_pred)) { - in_d = ls->basicblocks[i]->indepth; - in = ls->basicblocks[i]->instack; - for (;in_d > 0; in_d--, in = in->prev) { - phi_define = false; - for (j = 0; (!phi_define) && (j < ls->max_vars); j++) { - if (ls->phi[i][j] != NULL) - if (ls->phi[i][j][0] == in->varnum) - phi_define = true; - } - if (!phi_define) { - /* in not defined in phi function -> check with outstack(s) */ - /* of predecessor(s) */ - out_d = ls->basicblocks[pred]->outdepth; - out = ls->basicblocks[pred]->outstack; - _SSA_ASSERT(out_d >= in_d); - for(; out_d > in_d; out_d--, out = out->prev); - if ((in->varnum != out->varnum) || - (in->varkind != out->varkind)) { - printf("Method: %s %s\n", m->class->name->text, m->name->text); - printf("Error: Stack Varnum Mismatch BBin %3i BBout %3i Stackdepth %3i\n", i, pred, in_d); - if (compileverbose) - printf("Error: Stack Varnum Mismatch BBin %3i BBout %3i Stackdepth %3i\n", i, pred, in_d); -/* else */ -/* _SSA_ASSERT(0); */ - } - } - } - } - } - } - } - -#endif - - -#ifdef SSA_DEBUG_VERBOSE - if (compileverbose) - ssa_print_trees(m,cd,ls, gd, dd); -#endif -} - /**************************************************************************** -Optimization +Optimizations ****************************************************************************/ /**************************************************************************** Dead Code Elimination ****************************************************************************/ -void dead_code_elimination(methodinfo *m,registerdata *rd, lsradata *ls, graphdata *gd) { +void dead_code_elimination(jitdata *jd, graphdata *gd) { int a, i, source; worklist *W; instruction *iptr; - stackptr src; struct lifetime *lt, *s_lt; bool remove_statement; struct site *use; + lsradata *ls; +#ifdef SSA_DEBUG_VERBOSE + methodinfo *m; + + m = jd->m; +#endif + ls = jd->ls; + W = wl_new(ls->lifetimecount); if (ls->lifetimecount > 0) { /* put all lifetimes on Worklist */ @@ -1288,28 +1586,24 @@ void dead_code_elimination(methodinfo *m,registerdata *rd, lsradata *ls, graphda for (i = 1;i <= graph_get_num_predecessor(gd, lt->def->b_index); i++) { - source = ls->phi[lt->def->b_index][-lt->def->iindex-1][i]; - if ((source != ls->max_vars_with_indices) && + source = + ls->phi[lt->def->b_index][-lt->def->iindex-1][i]; + if ((source != ls->varcount_with_indices) && (source != lt->v_index)) { + /* phi Argument was not already removed (already in because of selfdefinition) */ - if (source >= 0) { - /* Local Var */ - s_lt = &(ls->lifetime[ls->maxlifetimes + source]); - } else { - /* Interface Stackslot */ - s_lt = &(ls->lifetime[-source-1]); - } + + s_lt = &(ls->lifetime[source]); + /* remove it */ - remove_use_site(s_lt,lt->def->b_index, lt->def->iindex); + + lt_remove_use_site(s_lt,lt->def->b_index, + lt->def->iindex); + /* put it on the Worklist */ - if (source >= 0) { - /* Local Var */ - wl_add(W, ls->maxlifetimes + source); - } else { - /* Interface Stackslot */ - wl_add(W, -source - 1); - } + + wl_add(W, source); } } /* now delete phi function itself */ @@ -1318,210 +1612,68 @@ void dead_code_elimination(methodinfo *m,registerdata *rd, lsradata *ls, graphda /* "normal" Use by ICMD */ remove_statement = false; if (lt->def->b_index != 0) { + /* do not look at artificial block 0 (parameter init) */ + iptr = ls->basicblocks[lt->def->b_index]->iinstr + lt->def->iindex; if (icmd_table[iptr->opc].flags & ICMDTABLE_PEI) remove_statement = false; + /* if ICMD could throw an exception do not remove it! */ - else { - /* get src stack */ - if (lt->def->iindex == 0) - src = ls->basicblocks[lt->def->b_index]->instack; - else - src = (iptr-1)->dst; - - remove_statement = true; - /* Statement has side effects? (== ICMD_INVOKE*) */ - switch (iptr->opc) { - case ICMD_INVOKEVIRTUAL: - case ICMD_INVOKESPECIAL: - case ICMD_INVOKESTATIC: - case ICMD_INVOKEINTERFACE: - case ICMD_BUILTIN: - /* check if really a side effect is possible */ - case ICMD_MULTIANEWARRAY: /* here, too */ - /* side effects by Statement possible -> - do not remove it */ - remove_statement = false; - break; - /* delete use of vars by these statments: */ - - /* use of iptr->op1 */ - case ICMD_IINC: - case ICMD_ILOAD: - case ICMD_LLOAD: - case ICMD_FLOAD: - case ICMD_DLOAD: - case ICMD_ALOAD: - s_lt = &(ls->lifetime[ls->maxlifetimes + iptr->op1]); - remove_use_site(s_lt,lt->def->b_index, lt->def->iindex); - /* put it on the Worklist */ - wl_add(W, ls->maxlifetimes + iptr->op1); - break; + else { - /* remove src->prev and src */ - case ICMD_IALOAD: - case ICMD_LALOAD: - case ICMD_FALOAD: - case ICMD_DALOAD: - case ICMD_AALOAD: - - case ICMD_BALOAD: - case ICMD_CALOAD: - case ICMD_SALOAD: - - case ICMD_LADD: - case ICMD_LSUB: - case ICMD_LMUL: - - case ICMD_LOR: - case ICMD_LAND: - case ICMD_LXOR: - - case ICMD_LSHL: - case ICMD_LSHR: - case ICMD_LUSHR: - - case ICMD_IADD: - case ICMD_IMUL: - - case ICMD_ISHL: - case ICMD_ISHR: - case ICMD_IUSHR: - case ICMD_IAND: - case ICMD_IOR: - case ICMD_IXOR: - - - case ICMD_FADD: - case ICMD_FSUB: - case ICMD_FMUL: - - case ICMD_DADD: - case ICMD_DSUB: - case ICMD_DMUL: - case ICMD_DDIV: - case ICMD_DREM: - case ICMD_ISUB: - case ICMD_LDIV: - case ICMD_LREM: - - case ICMD_IDIV: - case ICMD_IREM: - - case ICMD_FDIV: - case ICMD_FREM: - - case ICMD_LCMP: - case ICMD_FCMPL: - case ICMD_FCMPG: - case ICMD_DCMPL: - case ICMD_DCMPG: - /* Remove src->prev and then "fall through" for removal - of src */ - s_lt = &(ls->lifetime[-src->prev->varnum-1]); - remove_use_site(s_lt,lt->def->b_index, lt->def->iindex); - /* put it on the Worklist */ - wl_add(W, -src->prev->varnum - 1); - /* remove src */ - case ICMD_ISTORE: - case ICMD_LSTORE: - case ICMD_FSTORE: - case ICMD_DSTORE: - case ICMD_ASTORE: - case ICMD_LADDCONST: - case ICMD_LSUBCONST: - case ICMD_LMULCONST: - case ICMD_LMULPOW2: - case ICMD_LDIVPOW2: - case ICMD_LREMPOW2: - case ICMD_LANDCONST: - case ICMD_LORCONST: - case ICMD_LXORCONST: - case ICMD_LSHLCONST: - case ICMD_LSHRCONST: - case ICMD_LUSHRCONST: - - case ICMD_IADDCONST: - case ICMD_ISUBCONST: - case ICMD_IMULCONST: - case ICMD_IMULPOW2: - case ICMD_IDIVPOW2: - case ICMD_IREMPOW2: - case ICMD_IANDCONST: - case ICMD_IORCONST: - case ICMD_IXORCONST: - case ICMD_ISHLCONST: - case ICMD_ISHRCONST: - case ICMD_IUSHRCONST: - - /* case ICMD_IFEQ_ICONST: */ - /* case ICMD_IFNE_ICONST: */ - /* case ICMD_IFLT_ICONST: */ - /* case ICMD_IFGE_ICONST: */ - /* case ICMD_IFGT_ICONST: */ - /* case ICMD_IFLE_ICONST: */ - - case ICMD_INEG: - case ICMD_INT2BYTE: - case ICMD_INT2CHAR: - case ICMD_INT2SHORT: - case ICMD_LNEG: - case ICMD_FNEG: - case ICMD_DNEG: - - case ICMD_I2L: - case ICMD_I2F: - case ICMD_I2D: - case ICMD_L2I: - case ICMD_L2F: - case ICMD_L2D: - case ICMD_F2I: - case ICMD_F2L: - case ICMD_F2D: - case ICMD_D2I: - case ICMD_D2L: - case ICMD_D2F: - case ICMD_CHECKCAST: - case ICMD_ARRAYLENGTH: - case ICMD_INSTANCEOF: - - case ICMD_NEWARRAY: - case ICMD_ANEWARRAY: - - case ICMD_GETFIELD: - /* Remove src->prev and then "fall through" for removal - of src */ - s_lt = &(ls->lifetime[-src->varnum-1]); - remove_use_site(s_lt,lt->def->b_index, lt->def->iindex); - /* put it on the Worklist */ - wl_add(W, -src->varnum - 1); - break; - /* ignore these for now */ - case ICMD_DUP: - case ICMD_DUP2: - case ICMD_DUP_X1: - case ICMD_DUP_X2: - case ICMD_DUP2_X1: - case ICMD_DUP2_X2: - case ICMD_SWAP: -#ifdef SSA_DEBUG_VERBOSE - if (compileverbose) - printf("INFO2: ICMD_DUPX to be removed\n"); -#endif - /* DUPX has sideefects - cannot be removed, only because - one of the output vars is unused - TODO: extend the dead code elimination, so that all - output ss are checked*/ - remove_statement = false; - break; - } /* switch (iptr->opc) */ + /* ICMD_INVOKE*, ICMD_BUILTIN and ICMD_MULTIANEWARRAY */ + /* have possible sideeffects -> do not remove them */ + +/* remove_statement = !(ICMD_HAS_SPECIAL(iptr->opc)); */ + + remove_statement = !( + (icmd_table[iptr->opc].dataflow == DF_INVOKE) || + (icmd_table[iptr->opc].dataflow == DF_BUILTIN) || + (icmd_table[iptr->opc].dataflow == DF_N_TO_1)); + + if (remove_statement) { + switch (icmd_table[iptr->opc].dataflow) { + case DF_3_TO_0: + case DF_3_TO_1: /* icmd has s1, s2 and s3 */ + a = iptr->sx.s23.s3.varindex; + s_lt = ls->lifetime + a; + lt_remove_use_site(s_lt, lt->def->b_index, + lt->def->iindex); + wl_add(W, a); + + /* now "fall through" for handling of s2 and s1 */ + + case DF_2_TO_0: + case DF_2_TO_1: /* icmd has s1 and s2 */ + a = iptr->sx.s23.s2.varindex; + s_lt = ls->lifetime + a; + lt_remove_use_site(s_lt, lt->def->b_index, + lt->def->iindex); + wl_add(W, a); + + /* now "fall through" for handling of s1 */ + + case DF_1_TO_0: + case DF_1_TO_1: + case DF_MOVE: + case DF_COPY: + a = iptr->s1.varindex; + s_lt = ls->lifetime + a; + lt_remove_use_site(s_lt, lt->def->b_index, + lt->def->iindex); + wl_add(W, a); + } + } } + if (remove_statement) { + /* remove statement */ + #ifdef SSA_DEBUG_VERBOSE if (compileverbose) printf("INFO: %s %s:at BB %3i II %3i NOP-<%s\n", @@ -1533,117 +1685,27 @@ void dead_code_elimination(methodinfo *m,registerdata *rd, lsradata *ls, graphda } } /* (lt->def->b_index != 0) */ } /* if (lt->def->iindex < 0 ) else */ + /* remove definition of a */ - if (lt->v_index >= 0) { - /* local var */ - rd->locals[lt->v_index][lt->type].type = -1; - } + + VAR(lt->v_index)->type = -1; lt->type = -1; lt->def = NULL; } /* if (lt->use == NULL) */ - } /* while(!wl_is_empty(W)) */ } /* dead_code_elimination */ - - -#if 0 -void dead_code_elimination(registerdata *rd, lsradata *ls, graphdata *gd) { - int A,a,i,n,t; - bool is_empty; - - int *W_stack; - int W_top; - - W_top = 0; - if (ls->max_locals > 0) { - W_stack = DMNEW(int, ls->max_vars); - /* put unused local vars on Worklist */ - for(a = 0; a < ls->local_0[ls->max_locals]; a++) { - if (bv_is_empty(ls->use_sites[a], ls->basicblockcount)) { - /* a is not used */ - W_stack[W_top++] = a; - } - } - } - /* Remove unused local vars */ - while(W_top > 0) { - /* take a var out of Worklist */ - a = W_stack[--W_top]; - - if (bv_is_empty(ls->use_sites[a], ls->basicblockcount)) { - for(t = 0; t < 5; t++) - rd->locals[a][t].type = -1; - } - /* Change and if necessary delete phi functions */ - for(n = 0; n < ls->basicblockcount; n++) { - for(A = 0; A < ls->max_vars; A++) { - if (ls->var_to_index[A] >= 0) { - if (ls->phi[n][A] != NULL) { - is_empty = true; - /* look through the arguments of the phi function */ - for(i = 1; i < (graph_get_num_predecessor(gd, n)+1); i++) { - /* check if entry was not already removed */ - if (ls->phi[n][A][i] != -1) { - if (bv_is_empty(ls->use_sites[ls->phi[n][A][i]], - ls->basicblockcount)) - { - ls->num_var_use[n][ls->phi[n][A][i]]--; - if (ls->num_var_use[n][ls->phi[n][A][i]] == - 0) { - /* this was the only use in this Basic Block */ - bv_reset_bit( - ls->use_sites[ls->phi[n][A][i]],n); - if (bv_is_empty( - ls->use_sites[ls->phi[n][A][i]], - ls->basicblockcount)) - { - /* this was the only use in the whole Method */ - /* -> put this local var on the Worklist */ - W_stack[W_top++] = - ls->phi[n][A][i]; - } - } - ls->phi[n][A][i] = -1; - } else - is_empty = false; - } - } - /* look at the target of the phi function */ - /* Remove it,if target is not used or all arguments where */ - /* removed */ - if (bv_is_empty(ls->use_sites[ls->phi[n][A][0]], - ls->basicblockcount) || is_empty) { - /* phi function can be removed */ - ls->phi[n][A] = NULL; - } - } /* if (ls->phi[n][A] != NULL) */ - } /* if (ls->var_to_index[A] >= 0 */ - } /* for(li = 0; li < ls->max_locals; li++) */ - } /* for(n = 0; n < ls->basicblockcount; n++) */ - } /* while(W_top>0) */ - /* Remove unused Local Vars from rd->local */ - if (ls->max_locals > 0) - for(a = 0; a < ls->local_0[ls->max_locals]; a++) { - if (bv_is_empty(ls->use_sites[a], ls->basicblockcount)) { - /* a is not used */ - for(t = 0; t < 5; t++) - rd->locals[a][t].type = -1; - } - } -} -#endif /**************************************************************************** Simple Constant Propagation ****************************************************************************/ void simple_constant_propagation() { } + /**************************************************************************** Optimization *******************************************************************************/ -void copy_propagation(methodinfo *m,registerdata *rd, lsradata *ls, - graphdata *gd) { +void copy_propagation(jitdata *jd, graphdata *gd) { int a, i, source; int only_source; @@ -1651,8 +1713,11 @@ void copy_propagation(methodinfo *m,registerdata *rd, lsradata *ls, instruction *iptr; struct lifetime *lt, *s_lt; - struct stackslot *ss; - stackptr in; + s4 *in; + + lsradata *ls; + + ls = jd->ls; W = wl_new(ls->lifetimecount); if (ls->lifetimecount > 0) { @@ -1668,69 +1733,70 @@ void copy_propagation(methodinfo *m,registerdata *rd, lsradata *ls, /* take a var out of Worklist */ a = wl_get(W); - lt = &(ls->lifetime[a]); + lt = ls->lifetime + a; if (lt->type == -1) continue; _SSA_ASSERT(lt->def != NULL); _SSA_ASSERT(lt->use != NULL); if (lt->def->iindex < 0 ) { + /* phi function */ /* look, if phi function degenerated to a x = phi(y) */ /* and if so, substitute y for every use of x */ _SSA_ASSERT(ls->phi[lt->def->b_index][-lt->def->iindex-1] != NULL); - only_source = ls->max_vars_with_indices; + only_source = ls->varcount_with_indices; for (i = 1; i <= graph_get_num_predecessor(gd, lt->def->b_index); i++) { source = ls->phi[lt->def->b_index][-lt->def->iindex-1][i]; - if (source != ls->max_vars_with_indices) { - if (only_source == ls->max_vars_with_indices) { + if (source != ls->varcount_with_indices) { + if (only_source == ls->varcount_with_indices) { /* first valid source argument of phi function */ only_source = source; } else { /* second valid source argument of phi function */ /* exit for loop */ - only_source = ls->max_vars_with_indices; + only_source = ls->varcount_with_indices; break; } } } - if (only_source != ls->max_vars_with_indices) { + if (only_source != ls->varcount_with_indices) { + /* replace all use sites of lt with the var_index only_source */ - replace_use_sites( ls, gd, lt, only_source, W); + + ssa_replace_use_sites( jd, gd, lt, only_source, W); /* delete def of lt and replace uses of lt with "only_source" */ + ls->phi[lt->def->b_index][-lt->def->iindex-1] = NULL; - if (only_source >= 0) { - /* Local Var */ - s_lt = &(ls->lifetime[ls->maxlifetimes + only_source]); - rd->locals[lt->v_index][lt->type].type = -1; - } else { - /* Interface Stackslot */ - s_lt = &(ls->lifetime[-only_source-1]); - } - remove_use_site(s_lt, lt->def->b_index, lt->def->iindex); + s_lt = ls->lifetime + only_source; + + VAR(lt->v_index)->type = -1; + lt_remove_use_site(s_lt, lt->def->b_index, lt->def->iindex); lt->def = NULL; /* move use sites from lt to s_lt */ - move_use_sites(lt, s_lt); - move_stackslots(lt, s_lt); + lt_move_use_sites(lt, s_lt); lt->type = -1; - } /* if (only_source != ls->max_vars_with_indices) */ + } /* if (only_source != ls->varcount_with_indices) */ } else { /* if (lt->def->iindex < 0 )*/ /* def in "normal" ICMD */ +#if 0 iptr = ls->basicblocks[lt->def->b_index]->iinstr + lt->def->iindex; - if (lt->v_index >= 0) { + + if ( localvar ) { if (lt->def->b_index == 0) continue; + switch(iptr->opc) { case ICMD_ISTORE: case ICMD_LSTORE: case ICMD_FSTORE: case ICMD_DSTORE: - case ICMD_ASTORE: + case ICMD_ASTORE: if (lt->def->iindex == 0) { /* first instruction in bb -> instack==bb->instack */ in = ls->basicblocks[lt->def->b_index]->instack; @@ -1745,16 +1811,16 @@ void copy_propagation(methodinfo *m,registerdata *rd, lsradata *ls, printf("copy propagation xstore: BB %3i I %3i: %3i -> %3i\n", lt->def->b_index, lt->def->iindex, iptr->op1, in->varnum); #endif s_lt = &(ls->lifetime[-in->varnum-1]); - + for (ss = s_lt->local_ss; ss != NULL; ss = ss->next) { ss->s->varkind = LOCALVAR; ss->s->varnum = iptr->op1; } - + /* replace all use sites of s_lt with the var_index */ /* iptr->op1 */ - replace_use_sites(ls, gd, s_lt, iptr->op1, W); + ssa_replace_use_sites(jd, gd, s_lt, iptr->op1, W); /* s_lt->def is the new def site of lt */ /* the old ->def site will get a use site of def */ @@ -1816,7 +1882,7 @@ void copy_propagation(methodinfo *m,registerdata *rd, lsradata *ls, /* replace all use sites of lt with the var_index iptr->op1*/ - replace_use_sites( ls, gd, lt, iptr->op1, W); + ssa_replace_use_sites(jd, gd, lt, iptr->op1, W); lt->def = NULL; @@ -1830,34 +1896,45 @@ void copy_propagation(methodinfo *m,registerdata *rd, lsradata *ls, if (lt->local_ss->s->varnum != iptr->op1) printf("copy propagation: ILOAD -> LOCALVAR ss BB %i II %i\n", lt->def->b_index, lt->def->iindex); - + break; } - } - } - } + } /* localvar or interface stackslot */ +#endif + } /* i(lt->def->iindex < 0 ) */ + + } /* while(!wl_is_empty(W)) */ } -void replace_use_sites( lsradata *ls, graphdata *gd, struct lifetime *lt, - int new_v_index, worklist *W) { +void ssa_replace_use_sites(jitdata *jd, graphdata *gd, struct lifetime *lt, + int new_v_index, worklist *W) { struct site *s; int i, source; instruction *iptr; - struct stackslot *ss; + s4 *argp; + + methoddesc *md; + builtintable_entry *bte; + lsradata *ls; + + ls = jd->ls; + md = jd->m->parseddesc; + for(s = lt->use; s != NULL; s = s->next) { if (s->iindex < 0) { + /* Use in phi function */ - for (i = 1;i <= graph_get_num_predecessor(gd,s->b_index); - i++) { + + for (i = 1;i <= graph_get_num_predecessor(gd, s->b_index); i++) { source = ls->phi[s->b_index][-s->iindex-1][i]; if (source == lt->v_index) { #ifdef SSA_DEBUG_VERBOSE if (W != NULL) { - if (compileverbose) - printf("copy propagation phi: BB %3i I %3i: %3i -> \ + if (compileverbose) + printf("copy propagation phi: BB %3i I %3i: %3i -> \ %3i\n", s->b_index, s->iindex, - new_v_index, source); + new_v_index, source); } #endif ls->phi[s->b_index][-s->iindex-1][i] @@ -1865,67 +1942,110 @@ void replace_use_sites( lsradata *ls, graphdata *gd, struct lifetime *lt, } } if (W != NULL) { + /* Add var, which is defined by this phi function to */ /* the worklist */ + source = ls->phi[s->b_index][-s->iindex-1][0]; - if (source >= 0) { - /* Local Var */ - wl_add(W, ls->maxlifetimes + source); - } else { - /* Interface Stackslot */ - wl_add(W, -source - 1); - } + wl_add(W, source); } - } else { - /* use in ICMD */ + } + else { /* use in ICMD */ iptr = ls->basicblocks[s->b_index]->iinstr + s->iindex; - if (lt->v_index >= 0) { - /* Local Var use */ - switch(iptr->opc) { - case ICMD_ILOAD: - case ICMD_LLOAD: - case ICMD_FLOAD: - case ICMD_DLOAD: - case ICMD_ALOAD: - case ICMD_ISTORE: - case ICMD_LSTORE: - case ICMD_FSTORE: - case ICMD_DSTORE: - case ICMD_ASTORE: - case ICMD_IINC: /* iptr->op1 == USE */ - /* TODO: check if for XSTORE not src->varnum has */ - /* to be changed instead of iptr->op1 */ - _SSA_ASSERT(iptr->op1 == lt->v_index); + + /* check for use (s1, s2, s3 or special (argp) ) */ + + i = UNUSED; + switch (icmd_table[iptr->opc].dataflow) { + case DF_3_TO_0: + case DF_3_TO_1: /* icmd has s1, s2 and s3 */ + if (iptr->sx.s23.s3.varindex == lt->v_index) { #ifdef SSA_DEBUG_VERBOSE if (W != NULL) { - if (compileverbose) - printf("copy propagation loc: BB %3i I %3i: %3i -> \ + if (compileverbose) + printf("copy propagation loc: BB %3i I %3i: %3i -> \ %3i\n", s->b_index, s->iindex, - new_v_index, iptr->op1); + new_v_index, iptr->sx.s23.s3.varindex); } #endif - iptr->op1 = new_v_index; - break; - default: - exit(1); + iptr->sx.s23.s3.varindex = new_v_index; } - } else { - /* Interface Stackslot Use */ + + /* now "fall through" for handling of s2 and s1 */ + + case DF_2_TO_0: + case DF_2_TO_1: /* icmd has s1 and s2 */ + if (iptr->sx.s23.s2.varindex == lt->v_index) { +#ifdef SSA_DEBUG_VERBOSE + if (W != NULL) { + if (compileverbose) + printf("copy propagation loc: BB %3i I %3i: %3i -> \ + %3i\n", s->b_index, s->iindex, + new_v_index, iptr->sx.s23.s2.varindex); + } +#endif + iptr->sx.s23.s2.varindex = new_v_index; + } + + /* now "fall through" for handling of s1 */ + + case DF_1_TO_0: + case DF_1_TO_1: + case DF_MOVE: + case DF_COPY: + if (iptr->s1.varindex == lt->v_index) { #ifdef SSA_DEBUG_VERBOSE - if (compileverbose) - printf("copy propagation int: BB %3i I %3i: %3i -> \ - %3i\n", s->b_index, s->iindex, new_v_index, - lt->local_ss->s->varnum); + if (W != NULL) { + if (compileverbose) + printf("copy propagation loc: BB %3i I %3i: %3i -> \ + %3i\n", s->b_index, s->iindex, + new_v_index, iptr->s1.varindex); + } #endif - for (ss = lt->local_ss; ss != NULL; ss = ss->next) { - ss->s->varkind = LOCALVAR; - ss->s->varnum = new_v_index; + iptr->s1.varindex = new_v_index; } + break; + + /* TODO: */ + /* ? really look at md->paramcount or iptr->s1.argcount */ + /* has to be taken, so that pass-through stackslots get */ + /* renamed, too? */ + + case DF_INVOKE: + INSTRUCTION_GET_METHODDESC(iptr,md); + i = md->paramcount; + break; + case DF_BUILTIN: + bte = iptr->sx.s23.s3.bte; + md = bte->md; + i = md->paramcount; + break; + case DF_N_TO_1: + i = iptr->s1.argcount; + break; + } + if (i != UNUSED) { + argp = iptr->sx.s23.s2.args; + while (--i >= 0) { + if (*argp == lt->v_index) { +#ifdef SSA_DEBUG_VERBOSE + if (W != NULL) { + if (compileverbose) + printf( + "copy propagation loc: BB %3i I %3i: %3i -> %3i\n" + , s->b_index, s->iindex, new_v_index, *argp); + } +#endif + *argp = new_v_index; - } - } + } + argp++; + } + } + + } /* if (s->iindex < 0) */ } /* for(s = lt->use; s != NULL; s = s->next) */ } @@ -1937,8 +2057,8 @@ void ssa_print_lt(lsradata *ls) { printf("SSA LT Def/Use\n"); for(i = 0; i < ls->lifetimecount; i++) { - lt = &(ls->lifetime[i]); - if (lt->type != -1) { + lt = ls->lifetime + i; + if (lt->type != UNUSED) { printf("VI %3i Type %3i Def: ",lt->v_index, lt->type); if (lt->def != NULL) printf("%3i,%3i Use: ",lt->def->b_index, lt->def->iindex); @@ -1950,7 +2070,49 @@ void ssa_print_lt(lsradata *ls) { } } } + +void ssa_show_variable(jitdata *jd, int index, varinfo *v, int stage) +{ + char type; + char kind; + + switch (v->type) { + case TYPE_INT: type = 'i'; break; + case TYPE_LNG: type = 'l'; break; + case TYPE_FLT: type = 'f'; break; + case TYPE_DBL: type = 'd'; break; + case TYPE_ADR: type = 'a'; break; + case TYPE_RET: type = 'r'; break; + default: type = '?'; + } + + if (index < jd->localcount) { + kind = 'L'; + if (v->flags & (PREALLOC | INOUT)) + printf(""); + } + else { + if (v->flags & PREALLOC) { + kind = 'A'; + if (v->flags & INOUT) + printf(""); + } + else if (v->flags & INOUT) + kind = 'I'; + else + kind = 'T'; + } + + printf("%c%c%3d", kind, type, index); + + if (v->flags & SAVEDVAR) + putchar('!'); + + putchar(' '); + fflush(stdout); +} #endif + /**************************************************************************** Optimization ****************************************************************************/ diff --git a/src/vm/jit/optimizing/ssa.h b/src/vm/jit/optimizing/ssa.h index 56f876c5d..df8dbf424 100644 --- a/src/vm/jit/optimizing/ssa.h +++ b/src/vm/jit/optimizing/ssa.h @@ -50,14 +50,8 @@ # define _SSA_ASSERT(a) #endif -/* #define JOIN_PHI_LT */ /* build intereference graph for lt used in phi */ - /* funcs and try to merge them */ - /* function prototypes */ void ssa_init(jitdata *); -void ssa_set_local_def(lsradata *, int , int , int); -void ssa_set_use(lsradata *, int , int , int ); -void ssa_set_interface(codegendata *, lsradata *, basicblock *); void ssa(jitdata *, graphdata *); #endif /* _SSA_H */ @@ -70,7 +64,8 @@ void ssa(jitdata *, graphdata *); * Local variables: * mode: c * indent-tabs-mode: t - * c-basic-offset: 4 - * tab-width: 4 + * c-basic-offset): 4 + * tab-width): 4 * End: + * vim:noexpandtab:sw=4:ts=4: */ diff --git a/src/vm/jit/stack.c b/src/vm/jit/stack.c index 89ae9c0e9..b81dfd45e 100644 --- a/src/vm/jit/stack.c +++ b/src/vm/jit/stack.c @@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - $Id: stack.c 7766 2007-04-19 13:24:48Z michi $ + $Id: stack.c 7908 2007-05-15 09:55:17Z christian $ */ @@ -61,12 +61,14 @@ #include "vm/jit/jit.h" #include "vm/jit/stack.h" +#if 0 #if defined(ENABLE_SSA) # include "vm/jit/optimizing/lsra.h" # include "vm/jit/optimizing/ssa.h" #elif defined(ENABLE_LSRA) # include "vm/jit/allocator/lsra.h" #endif +#endif #include "vmcore/options.h" #include "vm/resolve.h" @@ -2038,9 +2040,6 @@ bool stack_analyse(jitdata *jd) methodinfo *m; /* method being analyzed */ registerdata *rd; stackdata_t sd; -#if defined(ENABLE_SSA) - lsradata *ls; -#endif int stackdepth; stackptr curstack; /* current stack top */ stackptr copy; @@ -2082,9 +2081,6 @@ bool stack_analyse(jitdata *jd) m = jd->m; rd = jd->rd; -#if defined(ENABLE_SSA) - ls = jd->ls; -#endif /* initialize the stackdata_t struct */ @@ -2107,10 +2103,6 @@ bool stack_analyse(jitdata *jd) sd.exstack.varnum = sd.localcount; sd.var[sd.exstack.varnum].type = TYPE_ADR; -#if defined(ENABLE_LSRA) - m->maxlifetimes = 0; -#endif - #if defined(ENABLE_STATISTICS) iteration_count = 0; #endif @@ -3180,18 +3172,7 @@ normal_ACONST: return false; } #endif - -#if defined(ENABLE_SSA) - if (ls != NULL) { - GET_NEW_VAR(sd, new_index, type); - DST(type, new_index); - stackdepth++; - } - else - -#else LOAD(type, varindex); -#endif break; /* pop 2 push 1 */ @@ -3224,13 +3205,6 @@ normal_ACONST: case ICMD_IINC: STATISTICS_STACKDEPTH_DISTRIBUTION(count_store_depth); -#if defined(ENABLE_SSA) - if (ls != NULL) { - iptr->s1.varindex = - jd->local_map[iptr->s1.varindex * 5 +TYPE_INT]; - } - else { -#endif last_store_boundary[iptr->s1.varindex] = sd.new; iptr->s1.varindex = @@ -3248,9 +3222,6 @@ normal_ACONST: i--; copy = copy->prev; } -#if defined(ENABLE_SSA) - } -#endif iptr->dst.varindex = iptr->s1.varindex; break; @@ -3314,9 +3285,6 @@ normal_ACONST: } #endif -#if defined(ENABLE_SSA) - if (ls != NULL) { -#endif /* check for conflicts as described in Figure 5.2 */ copy = curstack->prev; @@ -3387,9 +3355,6 @@ assume_conflict: /* remember the stack boundary at this store */ store_tail: last_store_boundary[javaindex] = sd.new; -#if defined(ENABLE_SSA) - } /* if (ls != NULL) */ -#endif if (opcode == ICMD_ASTORE && curstack->type == TYPE_RET) STORE(TYPE_RET, varindex);