1 /* src/vm/jit/loop/analyze.c - bound check removal functions
3 Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 Contact: cacao@cacaojvm.org
27 Authors: Christopher Kruegel
29 Changes: Christian Thalinger
31 Contains the functions which perform the bound check removals. With
32 the loops identified, these functions scan the code for array
33 accesses that take place in loops and try to guarantee that their
34 bounds are never violated. The function to call is
49 #include "mm/memory.h"
50 #include "toolbox/logging.h"
51 #include "vm/jit/jit.h"
52 #include "vm/jit/loop/analyze.h"
53 #include "vm/jit/loop/graph.h"
54 #include "vm/jit/loop/loop.h"
55 #include "vm/jit/loop/tracing.h"
60 /* Test functions -> will be removed in final release
63 void show_trace(struct Trace *trace)
66 switch (trace->type) {
69 printf("\nNr.:\t%d", trace->var);
70 printf("\nValue:\t%d", trace->constant);
75 printf("\nNr.:\t%d", trace->var);
79 printf("array-length");
80 printf("\nNr.:\t%d", trace->var);
81 printf("\nValue:\t%d", trace->constant);
86 printf("\nValue:\t%d", trace->constant);
95 printf("Trace is null");
101 void show_change(struct Changes *c)
103 printf("*** Changes ***\n");
105 printf("Lower/Upper Bound:\t%d/%d\n", c->lower_bound, c->upper_bound);
107 printf("Unrestricted\n");
110 show_varinfo(struct LoopVar *lv)
112 printf(" *** Loop Info ***\n");
113 printf("Value:\t%d\n", lv->value);
114 printf("Static:\t\t%d/%d\n", lv->static_l, lv->static_u);
115 printf("D-Valid:\t%d/%d\n", lv->dynamic_l_v, lv->dynamic_u_v);
116 printf("Dynamic\t\t%d/%d\n", lv->dynamic_l, lv->dynamic_u);
119 void show_right_side(methodinfo *m)
122 printf("\n *** Head *** \nType:\t");
123 show_trace(m->loopdata->c_rightside);
125 printf("\n *** Nested Loops: ***\n");
126 for (i=0; i<m->basicblockcount; ++i)
127 printf("%d\t", m->loopdata->c_nestedLoops[i]);
130 printf("\n *** Hierarchie: ***\n");
131 for (i=0; i<m->basicblockcount; ++i)
132 printf("%d\t", m->loopdata->c_hierarchie[i]);
136 printf("\n *** Current Loop ***\n");
137 for (i=0; i<m->basicblockcount; ++i)
138 printf("%d\t", m->loopdata->c_current_loop[i]);
142 void resultPass3(methodinfo *m)
145 struct LoopContainer *lc = m->loopdata->c_allLoops;
147 printf("\n\n****** PASS 3 ******\n\n");
150 printf("Loop Analysis:\n");
151 printf("Optimize:\t%d\n", lc->toOpt);
152 printf("Modified Vars: ");
154 for (i=0; i<lc->num_vars; ++i)
155 printf("%d ", lc->vars[i]);
161 printf("\nNested Loops:\n");
162 for (i=0; i<m->basicblockcount; ++i)
163 printf("%d ", m->loopdata->c_nestedLoops[i]);
165 for (i=0; i<m->basicblockcount; ++i)
166 printf("%d ", m->loopdata->c_hierarchie[i]);
171 void show_tree(struct LoopContainer *lc, int tabs)
176 for (cnt = 0; cnt < tabs; ++cnt)
178 printf("%d\n", lc->loop_head);
180 show_tree(lc->tree_down, tabs+1);
188 #ifdef ENABLE_STATISTICS
190 void show_loop_statistics(loopdata *ld)
192 printf("\n\n****** LOOP STATISTICS ****** \n\n");
194 printf("Optimization cancelled by or\n");
195 else if (ld->c_stat_exception)
196 printf("Optimization cancelled by exception\n");
198 printf("Number of array accesses:\t%d\n", ld->c_stat_array_accesses);
199 if (ld->c_stat_array_accesses) {
200 printf("\nFully optimized:\t%d\n", ld->c_stat_full_opt);
201 printf("Not optimized:\t\t%d\n", ld->c_stat_no_opt);
202 printf("Upper optimized:\t%d\n", ld->c_stat_upper_opt);
203 printf("Lower optimized:\t%d\n", ld->c_stat_lower_opt);
208 void show_procedure_statistics(loopdata *ld)
210 printf("\n\n****** PROCEDURE STATISTICS ****** \n\n");
211 printf("Number of loops:\t\t%d\n", ld->c_stat_num_loops);
212 printf("Number of array accesses:\t%d\n", ld->c_stat_sum_accesses);
213 if (ld->c_stat_sum_accesses) {
214 printf("\nFully optimized:\t%d\n", ld->c_stat_sum_full);
215 printf("Not optimized:\t\t%d\n", ld->c_stat_sum_no);
216 printf("Upper optimized:\t%d\n", ld->c_stat_sum_upper);
217 printf("Lower optimized:\t%d\n", ld->c_stat_sum_lower);
219 printf("Opt. cancelled by or:\t\t%d\n", ld->c_stat_sum_or);
220 printf("Opt. cancelled by exception:\t%d\n", ld->c_stat_sum_exception);
226 /* This function is used to merge two loops with the same header together.
227 A simple merge sort of the lists nodes of both loops is performed.
229 void analyze_merge(struct LoopContainer *l1, struct LoopContainer *l2)
231 struct LoopElement *start, *last, *le1, *le2;
232 /* start and last are pointers to the newly built list, le1 and le2 step */
233 /* step through the lists, that have to be merged. */
238 /* start a simple merge sort of the nodes of both loops. These lists are */
239 /* already sorted, so merging is easy. */
240 if (le1->node < le2->node) {
244 else if (le1->node == le2->node) {
254 /* while the first loop != NULL, depending of the first element of second */
255 /* loop, add new node to result list */
256 while (le1 != NULL) {
262 if (le1->node < le2->node) {
266 else if (le1->node == le2->node) {
283 /* This function is used to merge loops with the same header node to a single
284 one. O(n^2) of number of loops. This merginig is necessary, because the loop
285 finding algorith sometimes (eg. when loopbody ends with a if-else construct)
286 reports a single loop as two loops with the same header node.
288 void analyze_double_headers(loopdata *ld)
291 LoopContainer *t1, *t2, *t3;
295 while (t1 != NULL) { /* for all loops do */
296 toCheck = t1->loop_head; /* get header node */
299 while (t2 != NULL) { /* compare it to headers of rest */
300 if (t2->loop_head == toCheck) {
302 /* found overlapping loops -> merge them together */
303 /* printf("C_INFO: found overlapping loops - merging"); */
304 analyze_merge(t1, t2);
306 /* remove second loop from the list of all loops */
308 while (t3->next != t2)
320 /* After the hierarchie of loops has been built, we have to insert the exceptions
321 into this tree. The exception ex is inserted into the subtree pointed to by
324 void insert_exception(methodinfo *m, struct LoopContainer *lc, exceptiontable *ex)
326 struct LoopContainer *temp;
327 struct LoopElement *le;
330 /* printf("insert_exception called with %d-%d and loop %d\n", ex->start->nr, ex->end->nr, lc->loop_head); */
333 /* if child node is reached immediately insert exception into the tree */
334 if (lc->tree_down == NULL) {
335 ex->next = lc->exceptions;
339 /* if we are inside the tree, there are two possibilities: */
340 /* 1. the exception is inside a nested loop or */
341 /* 2. in the loop body of the current loop */
343 /* check all children (= nested loops) */
344 temp = lc->tree_down;
346 while (temp != NULL) {
352 printf("%d.%d\n", le->node, block_index[ex->startpc]);
354 /* if the start of the exception is part of the loop, the */
355 /* whole exception must be part of the loop */
356 if (le->node == m->basicblockindex[ex->startpc])
361 /* Exception is part of a nested loop (Case 1) -> insert it there */
363 insert_exception(m, temp, ex);
366 else if ((temp->loop_head >= m->basicblockindex[ex->startpc]) && (temp->loop_head < m->basicblockindex[ex->endpc])) {
368 /* optimization: if nested loop is part of the exception, the */
369 /* exception cannot be part of a differnet nested loop. */
370 ex->next = lc->exceptions;
375 temp = temp->tree_right;
378 /* Exception is not contained in any nested loop (Case 2) */
380 ex->next = lc->exceptions;
387 /* This function builds a loop hierarchie. The header node of the innermost loop,
388 each basic block belongs to, is stored in the array c_nestedLoops. The array
389 c_hierarchie stores the relationship between differnt loops in as follows:
390 Each loop, that is a nested loop, stores its direct surrounding loop as a
391 parent. Top level loops have no parents.
394 void analyze_nested(methodinfo *m, codegendata *cd, loopdata *ld)
396 /* i/count/tmp are counters */
397 /* toOverwrite is used while loop hierarchie is built (see below) */
398 int i, header, toOverwrite, tmp, len;
400 /* first/last are used during topological sort to build ordered loop list */
401 struct LoopContainer *first, *last, *start, *t, *temp;
403 /* Used to step through all nodes of a loop. */
404 struct LoopElement *le;
406 /* init global structures */
407 ld->c_nestedLoops = DMNEW(int, m->basicblockcount);
408 ld->c_hierarchie = DMNEW(int, m->basicblockcount);
409 for (i=0; i<m->basicblockcount; ++i) {
410 ld->c_nestedLoops[i] = -1;
411 ld->c_hierarchie[i] = -1;
414 /* if there are no optimizable loops -> return */
415 if (ld->c_allLoops == NULL)
418 temp = ld->c_allLoops;
419 while (temp != NULL) { /* for all loops, do */
420 header = temp->loop_head;
422 /* toOverwrite is number of current parent loop (-1 if none) */
423 toOverwrite = ld->c_nestedLoops[header];
425 ld->c_hierarchie[header] = toOverwrite;
427 if (toOverwrite == header) /* check for loops with same header */
428 printf("C_ERROR: Loops have same header\n");
431 while (le != NULL) { /* for all loop nodes, do */
432 tmp = ld->c_nestedLoops[le->node];
434 /* if node is part of parent loop -> overwrite it with nested */
435 if (tmp == toOverwrite)
436 ld->c_nestedLoops[le->node] = header;
438 ld->c_hierarchie[tmp] = header;
440 /* printf("set head of %d to %d", tmp, header); */
450 /* init root of hierarchie tree */
451 ld->root = DMNEW(struct LoopContainer, 1);
452 LoopContainerInit(m, ld->root, -1);
454 /* obtain parent pointer and build hierarchie tree */
455 start = ld->c_allLoops;
456 while (start != NULL) {
458 /* look for parent of loop pointed at by start */
459 first = ld->c_allLoops;
460 while (first != NULL) {
462 /* the parent of the loop, pointed at by start has been found */
463 if (first->loop_head == ld->c_hierarchie[start->loop_head]) {
465 /* printf("set parent to pointer\n"); */
468 start->parent = first;
469 start->tree_right = first->tree_down;
470 first->tree_down = start;
477 /* no parent loop found, set parent to root */
480 /* printf("set parent to root\n"); */
483 start->parent = ld->root;
484 start->tree_right = ld->root->tree_down;
485 ld->root->tree_down = start;
487 /* if a parent exists, increase this nodes indegree */
489 start->parent->in_degree += 1;
494 /* insert exceptions into tree */
496 printf("--- Showing tree ---\n");
497 show_tree(ld->root, 0);
498 printf(" --- End ---\n");
500 for (len = 0; len < jd->exceptiontablelength; ++len)
501 insert_exception(m, ld->root, jd->exceptiontable + len);
504 /* determine sequence of loops for optimization by topological sort */
508 temp = ld->c_allLoops;
509 while (temp != NULL) {
511 /* a loops with indegree == 0 are pushed onto the stack */
512 if (temp->in_degree == 0) {
524 first = last = start;
528 printf("C_ERROR: loops are looped\n");
532 /* pop each node from the stack and decrease its parents indegree by one */
533 /* when the parents indegree reaches zero, push it onto the stack as well */
534 if ((last->parent != ld->root) && (--last->parent->in_degree == 0)) {
535 last->parent->next = start;
536 start = last->parent;
538 while (start != NULL) {
545 if ((last->parent != ld->root) && (--last->parent->in_degree == 0)) {
546 last->parent->next = start;
547 start = last->parent;
552 ld->c_allLoops = first;
555 printf("*** Hierarchie Results \n");
556 while (first != NULL) {
557 printf("%d ", first->loop_head);
566 /* This function is used to add variables that occur as index variables in
567 array accesses (ARRAY_INDEX) or as variables, that change their value (VAR_MOD)
568 to the list of interesting vars (c_loopvars) for the current loop.
571 void add_to_vars(loopdata *ld, int var, int type, int direction)
575 /* printf("Added to vars %d %d %d\n", var, type, direction); */
577 while (lv != NULL) { /* check if var has been previously added */
578 if (lv->value == var) {
579 if (type == ARRAY_INDEX)
580 lv->index = 1; /* var is used as index */
581 else if (type == VAR_MOD) {
582 lv->modified = 1; /* var is used in assignment */
583 switch (direction) { /* how was var modified ? */
585 lv->static_u = 0; /* incremented, no static upper */
586 break; /* bound can be guaranteeed */
588 lv->static_l = 0; /* decremented, no static lower */
589 break; /* bound can be guaranteeed */
591 lv->static_u = lv->static_l = 0;
592 break; /* no info at all */
594 printf("C_ERROR: unknown direction\n");
603 /* variable is not found in list -> add variable to list */
604 lv = DNEW(struct LoopVar);
606 lv->modified = lv->index = 0;
609 if (type == ARRAY_INDEX) {
611 lv->static_u = lv->static_l = 1; /* arrayindex -> var not modified */
613 else if (type == VAR_MOD) {
615 switch (direction) { /* var used in assignment -> set */
616 case D_UP: /* proper static bounds */
617 lv->static_u = 0; lv->static_l = 1;
620 lv->static_u = 1; lv->static_l = 0;
623 lv->static_u = lv->static_l = 0;
626 printf("C_ERROR: unknown direction\n");
631 /* no dynamic bounds have been determined so far */
632 lv->dynamic_l = lv->dynamic_l_v = lv->dynamic_u = lv->dynamic_u_v = 0;
634 lv->next = ld->c_loopvars; /* add var to list */
639 /* This function checks, whether a given loop with header node contains array
640 accesses. If so, it returns 1, else it returns 0 and the loops needs no
641 further consideration in the optimization process. When array accesses are
642 found, a list of all variables, that are used as array index, is built and
643 stored in c_loopvars. For all variables (integer), which values are changed,
644 a flag in c_var_modified is set.
647 int analyze_for_array_access(methodinfo *m, loopdata *ld, int node)
652 struct depthElement *d;
655 if (ld->c_toVisit[node] > 0) { /* node has not been visited yet */
656 ld->c_toVisit[node] = 0;
658 bp = m->basicblocks[node]; /* prepare an instruction scan */
662 access = 0; /* number of array accesses in loop */
664 for (i=0; i<ic; ++i, ++ip) { /* for each instruction, check opcode */
666 case ICMD_IASTORE: /* array store */
674 t = tracing(&bp, i-1, 1); /* try to identify index variable */
676 if (t->type == TRACE_IVAR) {
677 /* if it is a variable, add it to list of index variables */
678 add_to_vars(ld, t->var, ARRAY_INDEX, D_UNKNOWN);
681 else if (t->type == TRACE_ICONST)
685 case ICMD_IALOAD: /* array load */
693 t = tracing(&bp, i-1, 0); /* try to identify index variable */
695 if (t->type == TRACE_IVAR) {
696 /* if it is a variable, add it to list of index variables */
697 add_to_vars(ld, t->var, ARRAY_INDEX, D_UNKNOWN);
700 else if (t->type == TRACE_ICONST)
704 case ICMD_ISTORE: /* integer store */
705 ld->c_var_modified[ip->op1] = 1;
707 /* try to find out, how it was modified */
708 t = tracing(&bp, i-1, 0);
709 if (t->type == TRACE_IVAR) {
710 if ((t->constant > 0) && (t->var == ip->op1))
711 /* a constant was added to the same var */
712 add_to_vars(ld, t->var, VAR_MOD, D_UP);
713 else if (t->var == ip->op1)
714 /* a constant was subtracted from the same var */
715 add_to_vars(ld, t->var, VAR_MOD, D_DOWN);
717 add_to_vars(ld, t->var, VAR_MOD, D_UNKNOWN);
720 add_to_vars(ld, ip->op1, VAR_MOD, D_UNKNOWN);
723 case ICMD_IINC: /* simple add/sub of a constant */
724 ld->c_var_modified[ip->op1] = 1;
727 add_to_vars(ld, ip->op1, VAR_MOD, D_UP);
729 add_to_vars(ld, ip->op1, VAR_MOD, D_DOWN);
736 ld->c_var_modified[ip->op1] = 1;
741 d = ld->c_dTable[node];
742 while (d != NULL) { /* check all successors of block */
743 access += analyze_for_array_access(m, ld, d->value);
754 /* This function scans the exception graph structure to find modifications of
755 array index variables of the current loop. If any modifications are found,
756 1 is returned, else 0.
759 int quick_scan(methodinfo *m, loopdata *ld, int node)
765 struct depthElement *d;
767 /* printf("QS: %d - %d\n", node, ld->c_exceptionVisit[node]); */
770 if (ld->c_exceptionVisit[node] > 0) { /* node is part of exception graph */
771 ld->c_exceptionVisit[node] = -1;
773 bp = m->basicblocks[node]; /* setup scan of all instructions */
777 for (i=0; i<count; ++i, ++ip) { /* for each instruction do */
780 case ICMD_IINC: /* a variable is modified */
782 lv = ld->c_loopvars; /* is it an array index var ? */
784 if ((lv->index) && (lv->value == ip->op1))
785 return 1; /* yes, so return 1 */
792 d = ld->c_exceptionGraph[node]; /* check all successor nodes */
794 if (quick_scan(m, ld, d->value) > 0)
795 return 1; /* if an access is found return 1 */
799 return 0; /* nothing found, so return 0 */
806 /* This function returns 1, when the condition of the loop contains
807 or statements or when an array index variable is modified in any
808 catch block within the loop.
811 int analyze_or_exceptions(methodinfo *m, codegendata *cd, loopdata *ld, int head, struct LoopContainer *lc)
813 struct depthElement *d;
814 int i, k, value, flag, count;
815 struct LoopElement *le;
817 d = ld->c_dTable[head];
820 /* analyze for or-statements */
822 printf("*** Analyze for OR ... ");
826 while (d != NULL) { /* for all successor nodes check if they */
827 value = d->value; /* are part of the loop */
832 if (le->node == value)
837 if (le == NULL) /* node is not part of the loop */
844 if ((count > 1) && (flag == 0)){/* if all successors part of the loop, exit */
845 #ifdef ENABLE_STATISTICS
851 /* check for exceptions */
852 /* printf("done\n*** Analyze for EXCEPTIONS(%d) . ", jd->exceptiontablelength); */
854 if (!jd->exceptiontablelength) /* when there are no exceptions, exit */
857 if ((ld->c_exceptionGraph = (struct depthElement **) malloc(sizeof(struct depthElement *) * m->basicblockcount)) == NULL)
859 if ((ld->c_exceptionVisit = (int *) malloc(sizeof(int) * m->basicblockcount)) == NULL)
862 for (k=0; k<m->basicblockcount; ++k) {
863 ld->c_exceptionVisit[k] = -1;
864 ld->c_exceptionGraph[k] = NULL;
868 /* for all nodes that start catch block check whether they are part of loop */
869 for (i = 0; i < ld->c_old_xtablelength; i++) {
870 value = m->basicblockindex[jd->exceptiontable[i].startpc];
875 if (le->node == value) { /* exception is in loop */
877 printf("C_INFO: Loop contains exception\n");
881 /* build a graph structure, that contains all nodes that are */
882 /* part of the catc block */
883 dF_Exception(m, ld, -1, m->basicblockindex[jd->exceptiontable[i].handlerpc]);
885 /* if array index variables are modified there, return 0 */
886 if (quick_scan(m, ld, m->basicblockindex[jd->exceptiontable[i].handlerpc]) > 0) {
887 #ifdef ENABLE_STATISTICS
888 ld->c_stat_exception++;
890 /* printf("C_INFO: loopVar modified in exception\n"); */
899 printf("none ... done\n");
906 /* This function sets a flag in c_var_modified for all variables that have
907 been found as part of an assigment in the loop.
910 void scan_global_list(loopdata *ld)
917 ld->c_var_modified[lv->value] = 1;
923 /* This function analyses the condition in the loop header and trys to find
924 out, whether some dynamic guarantees can be set up.
927 void init_constraints(methodinfo *m, loopdata *ld, int head)
931 int ic, l_mod, r_mod, changed, operand;
932 struct Trace *left, *right, *th;
933 struct LoopVar *lv_left, *lv_right, *lh;
935 /* prevent some compiler warnings */
941 bp = m->basicblocks[head];
943 ip = bp.iinstr+(ic-1); /* set ip to last instruction in header node */
945 switch (ip->opc) { /* check op-code */
947 /* comparison against constant value */
948 case ICMD_IFEQ: /* ..., value ==> ... */
949 case ICMD_IFLT: /* ..., value ==> ... */
950 case ICMD_IFLE: /* ..., value ==> ... */
951 case ICMD_IFGT: /* ..., value ==> ... */
952 case ICMD_IFGE: /* ..., value ==> ... */
953 /* op1 = target JavaVM pc, val.i = constant */
955 left = tracing(&bp, ic-2, 0); /* analyse left arg., right is constant */
956 right = create_trace(TRACE_ICONST, -1, ip->val.i, 0);
959 /* standard comparison */
960 case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */
961 case ICMD_IF_ICMPLT: /* ..., value, value ==> ... */
962 case ICMD_IF_ICMPGT: /* ..., value, value ==> ... */
963 case ICMD_IF_ICMPLE: /* ..., value, value ==> ... */
964 case ICMD_IF_ICMPGE: /* ..., value, value ==> ... */
966 left = tracing(&bp, ic-2, 1); /* get left and right argument */
967 right = tracing(&bp, ic-2, 0);
970 /* other condition */
972 left = create_trace(TRACE_UNKNOWN, -1, 0, 0);
973 right = create_trace(TRACE_UNKNOWN, -1, 0, 0);
977 /* analyse left and right side of comparison */
980 if (left->type == TRACE_IVAR) { /* is a loop variable on left side ? */
981 lv_left = ld->c_loopvars;
982 while (lv_left != NULL) {
983 if (lv_left->value == left->var) {
984 l_mod = lv_left->modified; /* yes, but has it been modified ? */
987 lv_left = lv_left->next;
991 if (right->type == TRACE_IVAR){ /* is a loop variable on right side ? */
992 lv_right = ld->c_loopvars;
993 while (lv_right != NULL) {
994 if (lv_right->value == right->var) {
995 r_mod = lv_right->modified; /* yes, but has it been modified ? */
998 lv_right = lv_right->next;
1002 if ((l_mod - r_mod) == 0) { /* both 1 or both 0 -> no dynamic contraints*/
1003 ld->c_rightside = NULL; /* possible */
1007 /* to simplify processing, make the left side the one, that contains the */
1008 /* modified variable */
1009 if (r_mod > l_mod) {
1010 th = left; left = right; right = th;
1011 lh = lv_left; lv_left = lv_right; lv_right = lh;
1012 changed = 1; /* set changed to true */
1015 changed = 0; /* no change needed */
1017 /* make sure that right side's value does not change during loop execution */
1018 if (right->type == TRACE_UNKNOWN) {
1019 ld->c_rightside = NULL;
1023 /* determine operands: */
1024 /* for further explaination a is modified, b nonmodified var */
1025 switch (ip->opc) { /* check opcode again */
1026 case ICMD_IFEQ: /* ..., value ==> ... */
1027 case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */
1028 operand = OP_EQ; /* a == b */
1031 case ICMD_IFLE: /* ..., value ==> ... */
1032 case ICMD_IF_ICMPLE: /* ..., value, value ==> ... */
1034 operand = OP_GE; /* b<=a -> a>=b */
1036 operand = OP_LT; /* a<=b -> a<(b+1) */
1037 if (left->constant != 0)
1038 left->constant -= 1;
1040 right->constant += 1;
1044 case ICMD_IFLT: /* ..., value ==> ... */
1045 case ICMD_IF_ICMPLT: /* ..., value, value ==> ... */
1047 operand = OP_GE; /* b<a -> a>=(b+1) */
1048 if (left->constant != 0)
1049 left->constant -= 1;
1051 right->constant += 1;
1054 operand = OP_LT; /* a<b -> a<b */
1057 case ICMD_IFGT: /* ..., value ==> ... */
1058 case ICMD_IF_ICMPGT: /* ..., value, value ==> ... */
1060 operand = OP_LT; /* b>a -> a<b */
1062 operand = OP_GE; /* a>b -> a>=(b+1) */
1063 if (left->constant != 0)
1064 left->constant -= 1;
1066 right->constant += 1;
1070 case ICMD_IFGE: /* ..., value ==> ... */
1071 case ICMD_IF_ICMPGE: /* ..., value, value ==> ... */
1073 operand = OP_LT; /* b>=a -> a<(b+1) */
1074 if (left->constant != 0)
1075 left->constant -= 1;
1077 right->constant += 1;
1080 operand = OP_GE; /* a>=b -> a>=b */
1084 printf("C_ERROR: debugging error 0x00\n");
1088 /* NOW: left/lv_left -> loopVar */
1089 /* right/lv_right -> const, nonmod. var, arraylength */
1090 switch (operand) { /* check operand */
1092 lv_left->dynamic_u_v = 1; /* upper + lower bound tested */
1093 lv_left->dynamic_l_v = 1;
1095 lv_left->dynamic_l = lv_left->dynamic_u = left->constant;
1099 lv_left->dynamic_u_v = 1; /* upper bound tested */
1101 lv_left->dynamic_u = left->constant;
1105 lv_left->dynamic_l_v = 1; /* lower bound tested */
1107 lv_left->dynamic_l = left->constant;
1111 printf("C_ERROR: debugging error 0x01\n");
1114 ld->c_rightside = right;
1116 switch (ld->c_rightside->type) {
1118 ld->c_rs_needed_instr = 1;
1121 ld->c_rs_needed_instr = 2;
1124 ld->c_rs_needed_instr = 3;
1127 printf("C_ERROR: wrong right-side type\n");
1132 /* This function is needed to add and record new static tests (before loop
1133 entry) of variables to make guaratees for index variables. type states
1134 the kind of the test. arrayRef is the array, which length is tested
1135 against, varRef is the variable, that is testes and constant is the
1136 constant value, that is tested.
1139 void add_new_constraint(methodinfo *m, codegendata *cd, loopdata *ld, int type, int arrayRef, int varRef, int constant)
1141 struct Constraint *tc;
1144 case TEST_ZERO: /* a variable is tested against a const */
1146 tc = ld->c_constraints[varRef]; /* does a test already exist for this var ? */
1147 while (tc != NULL) {
1148 if (tc->type == TEST_ZERO) {
1149 if (constant < tc->constant)
1150 tc->constant = constant;
1151 return; /* yes. update constant and return */
1156 /* insert a new test for this variable */
1157 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1159 tc->type = TEST_ZERO;
1160 tc->varRef = varRef;
1161 tc->constant = constant;
1162 tc->next = ld->c_constraints[varRef];
1163 ld->c_constraints[varRef] = tc;
1164 ld->c_needed_instr += 3;
1168 case TEST_ALENGTH: /* variable is tested against array length */
1170 tc = ld->c_constraints[varRef]; /* does a test already exist for this var ? */
1171 while (tc != NULL) {
1172 if ((tc->type == TEST_ALENGTH) && (tc->arrayRef == arrayRef)) {
1173 if (constant > tc->constant)
1174 tc->constant = constant;
1175 return; /* yes. update constant and return */
1180 /* insert a new test for this variable */
1181 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1183 tc->type = TEST_ALENGTH;
1184 tc->arrayRef = arrayRef;
1185 tc->varRef = varRef;
1186 tc->constant = constant;
1187 tc->next = ld->c_constraints[varRef];
1188 ld->c_constraints[varRef] = tc;
1189 ld->c_needed_instr += 6;
1191 /* if arrayRef is not already tested against null, insert that test */
1192 if (!(ld->c_null_check[arrayRef])) {
1193 ld->c_null_check[arrayRef] = 1;
1194 ld->c_needed_instr +=2;
1199 case TEST_CONST_ZERO:
1203 case TEST_CONST_ALENGTH: /* a const is tested against array length */
1205 /* does a test already exist for this array */
1206 tc = ld->c_constraints[jd->maxlocals];
1207 while (tc != NULL) {
1208 if ((tc->type == TEST_CONST_ALENGTH) && (tc->arrayRef == arrayRef)) {
1209 if (constant > tc->constant)
1210 tc->constant = constant;
1211 return; /* yes. update constant and return */
1216 /* insert a new test for this array */
1217 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1219 tc->type = TEST_CONST_ALENGTH;
1220 tc->arrayRef = arrayRef;
1221 tc->constant = constant;
1222 tc->next = ld->c_constraints[jd->maxlocals];
1223 ld->c_constraints[jd->maxlocals] = tc;
1224 ld->c_needed_instr += 4;
1226 /* if arrayRef is not already tested against null, insert that test */
1227 if (!(ld->c_null_check[arrayRef])) {
1228 ld->c_null_check[arrayRef] = 1;
1229 ld->c_needed_instr +=2;
1234 case TEST_UNMOD_ZERO: /* test unmodified var against constant */
1236 /* search if test already exists */
1237 tc = ld->c_constraints[varRef];
1238 while (tc != NULL) {
1239 if (tc->type == TEST_UNMOD_ZERO) {
1240 if (constant < tc->constant)
1241 tc->constant = constant;
1242 return; /* yes, so update constant */
1247 /* else, a new test is inserted */
1248 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1250 tc->type = TEST_UNMOD_ZERO;
1251 tc->varRef = varRef;
1252 tc->constant = constant;
1253 tc->next = ld->c_constraints[varRef];
1254 ld->c_constraints[varRef] = tc;
1255 ld->c_needed_instr += 3;
1259 case TEST_UNMOD_ALENGTH: /* test unmodified var against array length */
1261 /* search if test alreay exists */
1262 tc = ld->c_constraints[varRef];
1263 while (tc != NULL) {
1264 if ((tc->type == TEST_UNMOD_ALENGTH) && (tc->arrayRef == arrayRef)) {
1265 if (constant > tc->constant)
1266 tc->constant = constant;
1267 return; /* yes, so modify constants */
1272 /* create new entry */
1273 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1275 tc->type = TEST_UNMOD_ALENGTH;
1276 tc->varRef = varRef;
1277 tc->arrayRef = arrayRef;
1278 tc->constant = constant;
1279 tc->next = ld->c_constraints[varRef];
1280 ld->c_constraints[varRef] = tc;
1281 ld->c_needed_instr += 6;
1283 /* if arrayRef is not already tested against null, insert that test */
1284 if (!(ld->c_null_check[arrayRef])) {
1285 ld->c_null_check[arrayRef] = 1;
1286 ld->c_needed_instr +=2;
1291 case TEST_RS_ZERO: /* test right side of the loop condition */
1292 /* against a constant - needed by dynamic */
1294 /*!! varRef -> maxlocals */
1295 /* search if test already exists */
1296 tc = ld->c_constraints[jd->maxlocals];
1297 while (tc != NULL) {
1298 if (tc->type == TEST_RS_ZERO) {
1299 if (constant < tc->constant)
1300 tc->constant = constant;
1301 return; /* yes, so modify constants */
1306 /* create new entry */
1307 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1309 tc->type = TEST_RS_ZERO;
1310 tc->constant = constant;
1311 tc->next = ld->c_constraints[jd->maxlocals];
1312 ld->c_constraints[jd->maxlocals] = tc;
1313 ld->c_needed_instr += (2 + ld->c_rs_needed_instr);
1315 /* if arrayRef on right side is not already tested against null, */
1316 /* insert that test */
1317 if ((ld->c_rightside->type == TRACE_ALENGTH) && (!(ld->c_null_check[ld->c_rightside->var]))) {
1318 ld->c_null_check[ld->c_rightside->var] = 1;
1319 ld->c_needed_instr +=2;
1324 case TEST_RS_ALENGTH: /* test right side of the loop condition */
1325 /* against array length - needed by dynamic */
1327 /*!! varRef -> maxlocals */
1328 /* search if test already exists */
1329 tc = ld->c_constraints[jd->maxlocals];
1332 if ((tc->type == TEST_RS_ALENGTH) && (tc->arrayRef == arrayRef))
1334 if (constant > tc->constant)
1335 tc->constant = constant;
1336 return; /* yes, so modify constants */
1341 /* create new entry */
1342 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1344 tc->type = TEST_RS_ALENGTH;
1345 tc->arrayRef = arrayRef;
1346 tc->constant = constant;
1347 tc->next = ld->c_constraints[jd->maxlocals];
1348 ld->c_constraints[jd->maxlocals] = tc;
1349 ld->c_needed_instr += (3 + ld->c_rs_needed_instr);
1351 /* if arrayRef is not already tested against null, insert that test */
1352 if (!(ld->c_null_check[arrayRef])) {
1353 ld->c_null_check[arrayRef] = 1;
1354 ld->c_needed_instr +=2;
1357 /* if arrayRef on right side is not already tested against null, */
1358 /* insert that test */
1359 if ((ld->c_rightside->type == TRACE_ALENGTH) && (!(ld->c_null_check[ld->c_rightside->var]))) {
1360 ld->c_null_check[ld->c_rightside->var] = 1;
1361 ld->c_needed_instr +=2;
1369 /* This functions adds new static (before loop enry) tests of variables to the
1370 program to be able to guarantee certain values for index variables in array
1371 access (to safely remove bound checks).
1374 int insert_static(methodinfo *m, codegendata *cd, loopdata *ld, int arrayRef, struct Trace *index, struct Changes *varChanges, int special)
1380 /* printf("insert static check - %d\n", arrayRef);
1382 show_change(varChanges);
1385 if (varChanges == NULL) { /* the variable hasn't changed / const */
1386 if ((varChanges = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
1388 varChanges->lower_bound = varChanges->upper_bound = 0;
1391 switch (index->type) { /* check index type */
1392 case TRACE_IVAR: /* it is a variable */
1393 if (index->neg < 0) { /* if it's a negated var, return */
1394 #ifdef ENABLE_STATISTICS
1395 ld->c_stat_no_opt++;
1400 varRef = index->var;
1403 if (ld->c_var_modified[varRef]) { /* volatile var */
1405 lv = ld->c_loopvars; /* get reference to loop variable */
1407 while ((lv != NULL) && (lv->value != varRef))
1410 printf("C_ERROR: debugging error 0x02\n");
1412 /* show_varinfo(lv); */
1414 /* check existing static bounds and add new contraints on variable */
1415 /* to possibly remove bound checks */
1417 /* the var is never decremented, so we add a static test againt */
1419 if (varChanges->lower_bound > varChanges->upper_bound)
1420 add_new_constraint(m, cd, ld, TEST_ZERO, arrayRef, varRef, index->constant);
1422 add_new_constraint(m, cd, ld, TEST_ZERO, arrayRef, varRef, varChanges->lower_bound+index->constant);
1425 else if ((lv->dynamic_l_v) && (!special)) {
1426 /* the variable is decremented, but it is checked against a */
1427 /* bound in the loop condition */
1428 if (varChanges->lower_bound <= varChanges->upper_bound) {
1429 add_new_constraint(m, cd, ld, TEST_RS_ZERO, arrayRef, varRef, varChanges->lower_bound+index->constant+lv->dynamic_l);
1435 /* the var is never incremented, so we add a static test againt */
1437 if (varChanges->lower_bound > varChanges->upper_bound)
1438 add_new_constraint(m, cd, ld, TEST_ALENGTH, arrayRef, varRef, index->constant);
1440 add_new_constraint(m, cd, ld, TEST_ALENGTH, arrayRef, varRef, varChanges->upper_bound+index->constant);
1443 else if ((lv->dynamic_u_v) && (!special)) {
1444 /* the variable is decremented, but it is checked against a */
1445 /* bound in the loop condition */
1446 if (varChanges->lower_bound <= varChanges->upper_bound) {
1447 add_new_constraint(m, cd, ld, TEST_RS_ALENGTH, arrayRef, varRef, varChanges->upper_bound+index->constant+lv->dynamic_u);
1452 else { /* the var is never modified at all */
1453 add_new_constraint(m, cd, ld, TEST_UNMOD_ZERO, arrayRef, index->var, index->constant);
1454 add_new_constraint(m, cd, ld, TEST_UNMOD_ALENGTH, arrayRef, index->var, index->constant);
1458 /* if the addition of new variable tests made guarantees possible, */
1459 /* return the best possible optimization */
1460 if ((high > 0) && (low > 0)) {
1461 /* printf("fully optimzed\n"); */
1462 #ifdef ENABLE_STATISTICS
1463 ld->c_stat_full_opt++;
1467 else if (high > 0) {
1468 /* printf("upper optimzed\n"); */
1469 #ifdef ENABLE_STATISTICS
1470 ld->c_stat_upper_opt++;
1475 /* printf("lower optimzed\n"); */
1476 #ifdef ENABLE_STATISTICS
1477 ld->c_stat_lower_opt++;
1482 /* printf("not optimzed\n"); */
1483 #ifdef ENABLE_STATISTICS
1484 ld->c_stat_no_opt++;
1490 case TRACE_ICONST: /* if it is a constant, optimization is easy */
1491 if (index->constant < 0) {
1492 #ifdef ENABLE_STATISTICS
1493 ld->c_stat_no_opt++;
1495 return OPT_NONE; /* negative index -> bad */
1498 add_new_constraint(m, cd, ld, TEST_CONST_ALENGTH, arrayRef, 0, index->constant);
1499 #ifdef ENABLE_STATISTICS
1500 ld->c_stat_full_opt++;
1502 return OPT_FULL; /* else just test constant against array length */
1506 case TRACE_ALENGTH: /* else, no optimizations possible */
1509 #ifdef ENABLE_STATISTICS
1510 ld->c_stat_no_opt++;
1515 /* keep compiler happy */
1521 /* copy a stack and return the start pointer of the newly created one
1523 stackptr copy_stack_from(stackptr source) {
1524 stackptr current, top;
1529 /* copy first element */
1530 current = DMNEW(stackelement, 1);
1531 current->type = source->type;
1532 current->flags = source->flags;
1533 current->varkind = source->varkind;
1534 current->varnum = source->varnum;
1535 current->regoff = source->regoff;
1539 /* if there exist more, then copy the rest */
1540 while (source->prev != NULL) {
1541 source = source->prev;
1542 current->prev = DMNEW(stackelement, 1);
1543 current->type = source->type;
1544 current->flags = source->flags;
1545 current->varkind = source->varkind;
1546 current->varnum = source->varnum;
1547 current->regoff = source->regoff;
1548 current = current->prev;
1551 current->prev = NULL;
1556 /* The following defines are used in the procedure void create_static_checks(...)
1557 They add a new instruction with its corresponding stack manipulation and
1558 are used to build the new loop header of an optimized loop, where we have
1559 to check certain variables and constants against values to guarantee that
1560 index values in array accesses remain with array bounds.
1562 inst: pointer to the new instruction
1563 tos: stackpointer before this operation is executed
1564 newstack: temporary stackptr
1565 stackdepth: counts the current stackdepth
1566 original start: blockpointer to the head of the new, optimized loop
1569 /* Load a local integer variable v */
1570 #define LOAD_VAR(v) { \
1571 inst->opc = ICMD_ILOAD; \
1573 newstack = DMNEW(stackelement, 1); \
1574 inst->dst = newstack; \
1575 newstack->prev = tos; \
1576 newstack->type = TYPE_INT; \
1577 newstack->flags = 0; \
1578 newstack->varkind = LOCALVAR; \
1579 newstack->varnum = v; \
1585 /* Load a constant with value c */
1586 #define LOAD_CONST(c) { \
1587 inst->opc = ICMD_ICONST; \
1589 inst->val.i = (c); \
1590 newstack = DMNEW(stackelement, 1); \
1591 newstack->prev = tos; \
1592 newstack->type = TYPE_INT; \
1593 newstack->flags = 0; \
1594 newstack->varkind = UNDEFVAR; \
1595 newstack->varnum = stackdepth; \
1602 /* Load a local reference (adress) variable a */
1603 #define LOAD_ADDR(a) { \
1604 inst->opc = ICMD_ALOAD; \
1606 newstack = DMNEW(stackelement, 1); \
1607 newstack->prev = tos; \
1608 newstack->type = TYPE_ADR; \
1609 newstack->flags = 0; \
1610 newstack->varkind = LOCALVAR; \
1611 newstack->varnum = a; \
1618 /* Insert a compare greater-or-equal and jump to the unoptimized loop, if the */
1619 /* comparison is true */
1620 #define GOTO_NOOPT_IF_GE { \
1621 inst->opc = ICMD_IF_ICMPGE; \
1622 inst->target = original_start->copied_to; \
1623 if (tos->varkind == UNDEFVAR) \
1624 tos->varkind = TEMPVAR; \
1626 if (tos->varkind == UNDEFVAR) \
1627 tos->varkind = TEMPVAR; \
1634 /* Insert a compare greater than and jump to the unoptimized loop, if the */
1635 /* comparison is true */
1636 #define GOTO_NOOPT_IF_GT { \
1637 inst->opc = ICMD_IF_ICMPGT; \
1638 inst->target = original_start->copied_to; \
1639 if (tos->varkind == UNDEFVAR) \
1640 tos->varkind = TEMPVAR; \
1642 if (tos->varkind == UNDEFVAR) \
1643 tos->varkind = TEMPVAR; \
1651 /* Insert a compare less-than and jump to the unoptimized loop, if the */
1652 /* comparison is true */
1653 #define GOTO_NOOPT_IF_LT { \
1654 inst->opc = ICMD_IF_ICMPLT; \
1655 inst->target = original_start->copied_to; \
1656 if(tos->varkind == UNDEFVAR) \
1657 tos->varkind = TEMPVAR; \
1659 if(tos->varkind == UNDEFVAR) \
1660 tos->varkind = TEMPVAR; \
1667 /* Insert a compare if-not-null and jump to the unoptimized loop, if the */
1668 /* comparison is true */
1669 #define GOTO_NOOPT_IF_NULL { \
1670 inst->opc = ICMD_IFNULL; \
1671 inst->target = original_start->copied_to; \
1672 if(tos->varkind == UNDEFVAR) \
1673 tos->varkind = TEMPVAR; \
1680 /* Insert an add instruction, that adds two integer values on top of the stack */
1683 inst->opc = ICMD_IADD; \
1684 if(tos->varkind == UNDEFVAR) \
1685 tos->varkind = TEMPVAR; \
1687 if(tos->varkind == UNDEFVAR) \
1688 tos->varkind = TEMPVAR; \
1690 newstack = DMNEW(stackelement, 1); \
1691 newstack->prev = tos; \
1692 newstack->type = TYPE_INT; \
1693 newstack->flags = 0; \
1694 newstack->varkind = UNDEFVAR; \
1695 newstack->varnum = stackdepth; \
1702 /* Insert instructions to load the arraylength of an array with reference a */
1703 /* fisrt, the reference must be loaded, then a null-pointer check is inserted */
1704 /* if not already done earlier. Finally an arraylength instruction is added */
1705 #define LOAD_ARRAYLENGTH(a) { \
1706 if (ld->c_null_check[a]) { \
1708 GOTO_NOOPT_IF_NULL; \
1709 ld->c_null_check[a] = 0; \
1712 inst->opc = ICMD_ARRAYLENGTH; \
1713 if(tos->varkind == UNDEFVAR) \
1714 tos->varkind = TEMPVAR; \
1716 newstack = DMNEW(stackelement, 1); \
1717 newstack->prev = tos; \
1718 newstack->type = TYPE_INT; \
1719 newstack->flags = 0; \
1720 newstack->varkind = UNDEFVAR; \
1721 newstack->varnum = stackdepth; \
1728 /* Inserts the instructions to load the value of the right side of comparison */
1729 /* Depending of the type of the right side, the apropriate instructions are */
1731 #define LOAD_RIGHT_SIDE { \
1732 switch (ld->c_rightside->type) { \
1733 case TRACE_ICONST: \
1734 LOAD_CONST(ld->c_rightside->constant); \
1737 LOAD_VAR(ld->c_rightside->var); \
1738 LOAD_CONST(ld->c_rightside->constant); \
1741 case TRACE_ALENGTH: \
1742 LOAD_ARRAYLENGTH(ld->c_rightside->var); \
1745 log_text("C_ERROR: illegal trace on rightside of loop-header"); \
1750 /* Patch jumps in original loop and in copied loop, add gotos in copied loop.
1751 All jumps in the original loop to the loop head have to be redirected to
1752 the newly inserted one. For the copied loop, it is necessay to redirect all
1753 jumps inside that loop to the copied nodes. lc points to the current loop,
1754 loop_head is a pointer to the newly inserted head and original start was
1755 the old head and is now the head of the optimized variant of the loop.
1757 void patch_jumps(basicblock *original_start, basicblock *loop_head, struct LoopContainer *lc)
1759 /* step through all nodes of a loop */
1760 struct LoopElement *le;
1762 instruction *inst, *temp_instr;
1766 while (le != NULL) {
1768 /* do nothing for new loop head */
1769 if (le->block == loop_head) {
1774 /* for original version */
1776 inst = bptr->iinstr;
1777 for (i = 0; i < bptr->icount; ++i, ++inst) {
1778 switch (inst->opc) {
1780 case ICMD_IF_ICMPEQ:
1781 case ICMD_IF_ICMPLT:
1782 case ICMD_IF_ICMPLE:
1783 case ICMD_IF_ICMPNE:
1784 case ICMD_IF_ICMPGT:
1785 case ICMD_IF_ICMPGE:
1787 case ICMD_IF_LCMPEQ:
1788 case ICMD_IF_LCMPLT:
1789 case ICMD_IF_LCMPLE:
1790 case ICMD_IF_LCMPNE:
1791 case ICMD_IF_LCMPGT:
1792 case ICMD_IF_LCMPGE:
1794 case ICMD_IF_ACMPEQ:
1795 case ICMD_IF_ACMPNE:
1814 case ICMD_IFNONNULL:
1816 /* jump to newly inserted loopheader has to be redirected */
1817 if (((basicblock *) inst->target) == loop_head)
1818 inst->target = (void *) original_start;
1821 case ICMD_TABLESWITCH:
1826 tptr = (void **) inst->target;
1828 s4ptr = inst->val.a;
1829 l = s4ptr[1]; /* low */
1830 i = s4ptr[2]; /* high */
1834 /* jump to newly inserted loopheader has to be redirected */
1835 for (tptr = inst->target; i >= 0; --i, ++tptr) {
1836 if (((basicblock *) *tptr) == loop_head)
1837 tptr[0] = (void *) original_start;
1842 case ICMD_LOOKUPSWITCH:
1847 tptr = (void **) inst->target;
1849 s4ptr = inst->val.a;
1850 l = s4ptr[0]; /* default */
1851 i = s4ptr[1]; /* count */
1853 /* jump to newly inserted loopheader has to be redirected */
1854 for (tptr = inst->target; i >= 0; --i, ++tptr) {
1855 if (((basicblock *) *tptr) == loop_head)
1856 tptr[0] = (void *) original_start;
1863 /* if node is part of loop and has fall through to original start, that */
1864 /* must be redirected. Unfortunately the instructions have to be copied */
1866 if (bptr->next == loop_head) {
1867 temp_instr = DMNEW(instruction, bptr->icount + 1);
1868 memcpy(temp_instr, bptr->iinstr, sizeof(instruction)*bptr->icount);
1869 bptr->iinstr = temp_instr;
1871 bptr->iinstr[bptr->icount].opc = ICMD_GOTO;
1872 bptr->iinstr[bptr->icount].target = original_start;
1873 bptr->iinstr[bptr->icount].dst = NULL;
1877 /* for copied version - which gets the unoptimized variant */
1878 bptr = le->block->copied_to;
1879 inst = bptr->iinstr;
1880 for (i = 0; i < bptr->icount; ++i, ++inst) {
1882 switch (inst->opc) {
1884 case ICMD_IASTORE: /* array store */
1892 case ICMD_IALOAD: /* array load */
1901 /* undo previous optimizations in new loop */
1905 case ICMD_IF_ICMPEQ:
1906 case ICMD_IF_ICMPLT:
1907 case ICMD_IF_ICMPLE:
1908 case ICMD_IF_ICMPNE:
1909 case ICMD_IF_ICMPGT:
1910 case ICMD_IF_ICMPGE:
1912 case ICMD_IF_LCMPEQ:
1913 case ICMD_IF_LCMPLT:
1914 case ICMD_IF_LCMPLE:
1915 case ICMD_IF_LCMPNE:
1916 case ICMD_IF_LCMPGT:
1917 case ICMD_IF_LCMPGE:
1919 case ICMD_IF_ACMPEQ:
1920 case ICMD_IF_ACMPNE:
1939 case ICMD_IFNONNULL:
1941 /* jump to newly inserted loopheader has to be redirected */
1942 if (((basicblock *) inst->target) == loop_head)
1943 inst->target = (void *) original_start->copied_to;
1944 /* jump to loop internal nodes has to be redirected */
1945 else if (((basicblock *) inst->target)->lflags & LOOP_PART)
1946 inst->target = (void *) ((basicblock *) inst->target)->copied_to;
1949 case ICMD_TABLESWITCH:
1953 void **copy_ptr, *base_ptr;
1956 tptr = (void **) inst->target;
1958 s4ptr = inst->val.a;
1959 l = s4ptr[1]; /* low */
1960 i = s4ptr[2]; /* high */
1964 copy_ptr = (void**) DMNEW(void*, i+1);
1965 base_ptr = (void*) copy_ptr;
1967 /* Targets for switch instructions are stored in an extra */
1968 /* that must be copied for new inserted loop. */
1970 for (tptr = inst->target; i >= 0; --i, ++tptr, ++copy_ptr) {
1971 /* jump to newly inserted loopheader must be redirected */
1972 if (((basicblock *) *tptr) == loop_head)
1973 copy_ptr[0] = (void *) original_start->copied_to;
1974 /* jump to loop internal nodes has to be redirected */
1975 else if (((basicblock *) *tptr)->lflags & LOOP_PART)
1976 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
1978 copy_ptr[0] = tptr[0];
1981 inst->target = base_ptr;
1985 case ICMD_LOOKUPSWITCH:
1989 void **copy_ptr, **base_ptr;
1992 tptr = (void **) inst->target;
1994 s4ptr = inst->val.a;
1995 l = s4ptr[0]; /* default */
1996 i = s4ptr[1]; /* count */
1998 copy_ptr = (void**) DMNEW(void*, i+1);
1999 base_ptr = (void*) copy_ptr;
2001 /* Targets for switch instructions are stored in an extra */
2002 /* that must be copied for new inserted loop. */
2004 for (tptr = inst->target; i >= 0; --i, ++tptr, ++copy_ptr) {
2005 /* jump to newly inserted loopheader must be redirected */
2006 if (((basicblock *) *tptr) == loop_head)
2007 copy_ptr[0] = (void *) original_start->copied_to;
2008 /* jump to loop internal nodes has to be redirected */
2009 else if (((basicblock *) *tptr)->lflags & LOOP_PART)
2010 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2012 copy_ptr[0] = tptr[0];
2015 inst->target = base_ptr;
2022 /* if fall through exits loop, goto is needed */
2023 if (!(le->block->next->lflags & LOOP_PART)) {
2024 bptr->iinstr[bptr->icount].opc = ICMD_GOTO;
2025 bptr->iinstr[bptr->icount].dst = NULL;
2026 bptr->iinstr[bptr->icount].target = le->block->next;
2035 /* Add the new header node of a loop that has been duplicated to all parent
2036 loops in nesting hierarchie.
2039 void header_into_parent_loops(loopdata *ld, struct LoopContainer *lc, basicblock *to_insert, basicblock *replace, basicblock *after)
2041 /* we have to insert the node to_insert before the node after and replace */
2042 /* the pointer of to_insert by the node replace */
2044 struct LoopElement *le, *t;
2046 /* if the top of the tree is reached, then return */
2047 if ((lc == NULL) || (lc == ld->root))
2050 /* create new node, that should be inserted */
2051 t = DMNEW(struct LoopElement, 1);
2052 t->block = to_insert;
2055 /* first, find the node, that has to be replaced (= "to_insert") and */
2056 /* replace it by the node "replace" */
2058 while (le->block != to_insert)
2060 le->block = replace;
2063 if (after == to_insert)
2066 /* now find the node after and insert the newly create node before "after" */
2068 if (le->block == after) {
2069 t->next = lc->nodes;
2073 while (le->next->block != after)
2080 /* go up one hierarchie level */
2081 header_into_parent_loops(ld, lc->parent, to_insert, replace, after);
2085 /* Add a new node (not header) of a duplicated loop to all parent loops in
2089 void node_into_parent_loops(loopdata *ld, struct LoopContainer *lc, basicblock *to_insert)
2091 struct LoopElement *le, *t;
2093 /* if the top of the tree is reached, then return */
2094 if ((lc == NULL) || (lc == ld->root))
2097 /* create new node, that should be inserted */
2098 t = DNEW(LoopElement);
2099 t->block = to_insert;
2104 /* append new node to node list of loop */
2105 while (le->next != NULL)
2111 /* go up one hierarchie level */
2112 node_into_parent_loops(ld, NULL, to_insert);
2116 /* void patch_handler(...) is very similar to parts of the function patch_jumps.
2117 Its task is to redirect all jumps from the original head to the new head and
2118 to redirect internal jumps inside the exception handler to the newly
2119 created (copied) nodes.
2122 void patch_handler(struct LoopContainer *lc, basicblock *bptr, basicblock *original_head, basicblock *new_head)
2127 /* If node is not part of exception handler or has been visited, exit */
2128 if (!(bptr->lflags & HANDLER_PART) || (bptr->lflags & HANDLER_VISITED))
2131 /* mark block as visited */
2132 bptr->lflags |= HANDLER_VISITED;
2134 /* for all instructions in the copied block, do */
2135 for (i = 0, ip = bptr->copied_to->iinstr; i < bptr->copied_to->icount; ++i, ++ip) {
2146 case ICMD_IF_ICMPEQ:
2147 case ICMD_IF_ICMPLT:
2148 case ICMD_IF_ICMPLE:
2149 case ICMD_IF_ICMPNE:
2150 case ICMD_IF_ICMPGT:
2151 case ICMD_IF_ICMPGE:
2153 case ICMD_IF_LCMPEQ:
2154 case ICMD_IF_LCMPLT:
2155 case ICMD_IF_LCMPLE:
2156 case ICMD_IF_LCMPNE:
2157 case ICMD_IF_LCMPGT:
2158 case ICMD_IF_LCMPGE:
2160 case ICMD_IF_ACMPEQ:
2161 case ICMD_IF_ACMPNE:
2179 case ICMD_IFNONNULL:
2181 patch_handler(lc, bptr->next, original_head, new_head);
2187 patch_handler(lc, ip->target, original_head, new_head);
2189 /* jumps to old header have to be redirected */
2190 if (((basicblock *) ip->target) == original_head)
2191 ip->target = (void *) new_head->copied_to;
2192 /* jumps to handler internal nodes have to be redirected */
2193 else if (((basicblock *) ip->target)->lflags & HANDLER_PART)
2194 ip->target = (void *) ((basicblock *) ip->target)->copied_to;
2195 /* jumps to loop internal nodes have to be redirected */
2196 else if (((basicblock *) ip->target)->lflags & LOOP_PART)
2197 ip->target = (void *) ((basicblock *) ip->target)->copied_to;
2202 case ICMD_TABLESWITCH:
2206 void **copy_ptr, **base_ptr;
2208 tptr = (void **) ip->target;
2210 l = s4ptr[1]; /* low */
2211 i = s4ptr[2]; /* high */
2214 copy_ptr = (void**) DMNEW(void*, i+1);
2215 base_ptr = (void*) copy_ptr;
2217 for (tptr = ip->target; i >= 0; --i, ++tptr, ++copy_ptr) {
2218 patch_handler(lc, ((basicblock *) *tptr), original_head, new_head);
2219 /* jumps to old header have to be redirected */
2220 if (((basicblock *) *tptr) == original_head)
2221 copy_ptr[0] = (void *) new_head->copied_to;
2222 /* jumps to handler internal nodes have to be redirected */
2223 else if (((basicblock *) *tptr)->lflags & HANDLER_PART)
2224 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2225 /* jumps to loop internal nodes have to be redirected */
2226 else if (((basicblock *) ip->target)->lflags & LOOP_PART)
2227 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2229 copy_ptr[0] = tptr[0];
2232 ip->target = base_ptr;
2236 case ICMD_LOOKUPSWITCH:
2241 void **copy_ptr, **base_ptr;
2243 tptr = (void **) ip->target;
2245 l = s4ptr[0]; /* default */
2246 i = s4ptr[1]; /* count */
2248 copy_ptr = (void**) DMNEW(void*, i+1);
2249 base_ptr = (void*) copy_ptr;
2251 for (tptr = ip->target; i >= 0; --i, ++tptr, ++copy_ptr) {
2253 patch_handler(lc, ((basicblock *) *tptr), original_head, new_head);
2254 /* jumps to old header have to be redirected */
2255 if (((basicblock *) *tptr) == original_head)
2256 copy_ptr[0] = (void *) new_head->copied_to;
2257 /* jumps to handler internal nodes have to be redirected */
2258 else if (((basicblock *) *tptr)->lflags & HANDLER_PART)
2259 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2260 /* jumps to loop internal nodes have to be redirected */
2261 else if (((basicblock *) ip->target)->lflags & LOOP_PART)
2262 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2264 copy_ptr[0] = tptr[0];
2267 ip->target = base_ptr;
2275 /* if fall through exits loop, goto is needed */
2276 if (!(bptr->next->lflags & HANDLER_PART)) {
2277 bptr->copied_to->iinstr[bptr->copied_to->icount].opc = ICMD_GOTO;
2278 bptr->copied_to->iinstr[bptr->copied_to->icount].dst = NULL;
2279 bptr->copied_to->iinstr[bptr->copied_to->icount].target = bptr->next;
2280 bptr->copied_to->icount++;
2285 /* copy_handler ****************************************************************
2287 This function copys the exception handler and redirects all jumps from the
2288 original head to the new head in the original exception handler. All
2289 redirection in the copied exception handler is done in patch_handler(...).
2291 *******************************************************************************/
2293 void copy_handler(methodinfo *m, loopdata *ld, struct LoopContainer *lc, basicblock *bptr, basicblock *original_head, basicblock *new_head)
2298 int high, low, count;
2299 struct LoopElement *le;
2300 basicblock *new, *temp;
2302 /* If this node has already been copied, return */
2303 if (bptr->lflags & HANDLER_PART)
2306 /* The exception handler exists, when control flow enters loop again */
2308 if (bptr->lflags & LOOP_PART)
2310 for (le = lc->nodes; le != NULL; le = le->next) {
2311 if (le->block == bptr) {
2312 printf("C_PANIC: should not happen\n");
2317 /* mark block as part of handler */
2318 bptr->lflags |= HANDLER_PART;
2321 new = DMNEW(basicblock, 1);
2322 memcpy(new, bptr, sizeof(basicblock));
2325 ld->c_last_block_copied = new;
2327 /* copy instructions and allow one more slot for possible GOTO */
2328 new->iinstr = DMNEW(instruction, bptr->icount + 1);
2329 memcpy(new->iinstr, bptr->iinstr, bptr->icount * sizeof(instruction));
2331 /* update original block */
2332 bptr->copied_to = new;
2334 /* append block to global list of basic blocks */
2335 temp = m->basicblocks;
2344 /* find next block to copy, depending on last instruction of BB */
2345 if (bptr->icount == 0) {
2346 copy_handler(m, ld, lc, bptr->next, original_head, new_head);
2350 ip = bptr->iinstr + (bptr->icount - 1);
2369 case ICMD_IF_LCMPEQ:
2370 case ICMD_IF_LCMPLT:
2371 case ICMD_IF_LCMPLE:
2372 case ICMD_IF_LCMPNE:
2373 case ICMD_IF_LCMPGT:
2374 case ICMD_IF_LCMPGE:
2384 case ICMD_IFNONNULL:
2386 case ICMD_IF_ICMPEQ:
2387 case ICMD_IF_ICMPNE:
2388 case ICMD_IF_ICMPLT:
2389 case ICMD_IF_ICMPGE:
2390 case ICMD_IF_ICMPGT:
2391 case ICMD_IF_ICMPLE:
2392 case ICMD_IF_ACMPEQ:
2393 case ICMD_IF_ACMPNE:
2394 copy_handler(m, ld, lc, bptr->next, original_head, new_head);
2399 /* redirect jump from original_head to new_head */
2400 if ((basicblock *) ip->target == original_head)
2401 ip->target = (void *) new_head;
2403 copy_handler(m, ld, lc, (basicblock *) (ip->target), original_head, new_head);
2407 case ICMD_TABLESWITCH:
2409 tptr = (void **) ip->target;
2411 /* default branch */
2412 if (((basicblock *) *tptr) == original_head)
2413 tptr[0] = (void *) new_head;
2415 copy_handler(m, ld, lc, (basicblock *) *tptr, original_head, new_head);
2422 count = (high-low+1);
2424 while (--count >= 0) {
2426 /* redirect jump from original_head to new_head */
2427 if (((basicblock *) *tptr) == original_head)
2428 tptr[0] = (void *) new_head;
2429 copy_handler(m, ld, lc, (basicblock *) *tptr, original_head, new_head);
2433 case ICMD_LOOKUPSWITCH:
2435 tptr = (void **) ip->target;
2437 /* default branch */
2438 if (((basicblock *) *tptr) == original_head)
2439 tptr[0] = (void *) new_head;
2441 copy_handler(m, ld, lc, (basicblock *) *tptr, original_head, new_head);
2446 while (--count >= 0) {
2448 /* redirect jump from original_head to new_head */
2449 if (((basicblock *) *tptr) == original_head)
2450 tptr[0] = (void *) new_head;
2451 copy_handler(m, ld, lc, (basicblock *) *tptr, original_head, new_head);
2456 ld->c_last_target = bptr;
2457 copy_handler(m, ld, lc, (basicblock *) (ip->target), original_head, new_head);
2461 copy_handler(m, ld, lc, ld->c_last_target->next, original_head, new_head);
2465 copy_handler(m, ld, lc, bptr->next, original_head, new_head);
2471 /* If a loop is duplicated, all exceptions, that are contained in this loops' body
2472 have to be duplicated as well. The following function together with the
2473 two helper functions copy_handler and patch_handler perform this task.
2476 void update_internal_exceptions(methodinfo *m, codegendata *cd, loopdata *ld, struct LoopContainer *lc, basicblock *original_head, basicblock *new_head)
2478 exceptiontable *ex, *new;
2479 struct LoopContainer *l;
2481 /* Bottom of tree reached -> return */
2485 /* Call update_internal for all nested (=child) loops */
2488 update_internal_exceptions(m, cd, ld, l, original_head, new_head);
2492 /* For all exceptions of this loop, do */
2493 ex = lc->exceptions;
2494 while (ex != NULL) {
2496 /* Copy the exception and patch the jumps */
2497 copy_handler(m, ld, lc, ex->handler, original_head, new_head);
2498 patch_handler(lc, ex->handler, original_head, new_head);
2500 /* Insert a new exception into the global exception table */
2501 new = DNEW(exceptiontable);
2502 memcpy(new, ex, sizeof(exceptiontable));
2504 /* Increase number of exceptions */
2505 ++jd->exceptiontablelength;
2510 /* Set new start and end point of this exception */
2511 new->start = ex->start->copied_to;
2512 new->end = ex->end->copied_to;
2514 /* Set handler pointer to copied exception handler */
2515 new->handler = ex->handler->copied_to;
2523 /* If a loop is duplicated, all exceptions that contain this loop have to be
2524 extended to the copied nodes as well. The following function checks for
2525 all exceptions of all parent loops, whether they contain the loop pointed to
2526 by lc. If so, the exceptions are extended to contain all newly created nodes.
2529 void update_external_exceptions(methodinfo *m, codegendata *cd, loopdata *ld, struct LoopContainer *lc, int loop_head)
2531 exceptiontable *ex, *new;
2533 /* Top of tree reached -> return */
2537 ex = lc->exceptions;
2539 /* For all exceptions of this loop do */
2540 while (ex != NULL) {
2542 /* It is possible that the loop contains exceptions that do not protect */
2543 /* the loop just duplicated. It must be checked, if this is the case */
2544 if ((loop_head >= m->basicblockindex[ex->startpc]) && (loop_head < m->basicblockindex[ex->endpc])) {
2546 /* loop is really inside exception, so create new exception entry */
2547 /* in global exception list */
2548 new = DNEW(exceptiontable);
2549 memcpy(new, ex, sizeof(exceptiontable));
2552 /* Increase number of exceptions */
2553 ++jd->exceptiontablelength;
2558 /* Set new start and end point of this exception */
2559 new->start = ld->c_first_block_copied;
2560 new->end = ld->c_last_block_copied;
2564 /* exception does not contain the duplicated loop -> do nothing */
2569 /* Call update_external for parent node */
2570 update_external_exceptions(m, cd, ld, lc->parent, loop_head);
2574 /* This function is needed to insert the static checks, stored in c_constraints
2575 into the intermediate code.
2578 void create_static_checks(methodinfo *m, codegendata *cd, loopdata *ld, struct LoopContainer *lc)
2580 int i, stackdepth, cnt;
2581 struct Constraint *tc1;
2582 struct LoopElement *le;
2584 /* loop_head points to the newly inserted loop_head, original_start to */
2585 /* the old loop header */
2586 basicblock *bptr, *loop_head, *original_start, *temp;
2587 instruction *inst, *tiptr;
2589 /* tos and newstack are needed by the macros, that insert instructions into */
2590 /* the new loop head */
2591 stackptr newstack, tos;
2594 /* prevent some compiler warnings */
2598 #ifdef ENABLE_STATISTICS
2599 /* show_loop_statistics(l); */
2602 loop_head = &m->basicblocks[ld->c_current_head];
2603 ld->c_first_block_copied = ld->c_last_block_copied = NULL;
2605 /* the loop nodes are copied */
2609 bptr = DMNEW(basicblock, 1);
2610 memcpy(bptr, le->block, sizeof(basicblock));
2613 /* determine beginning of copied loop to extend exception handler, that */
2614 /* protect this loop */
2615 if (ld->c_first_block_copied == NULL)
2616 ld->c_first_block_copied = bptr;
2618 /* copy instructions and add one more slot for possible GOTO */
2619 bptr->iinstr = DMNEW(instruction, bptr->icount + 1);
2621 memcpy(bptr->iinstr, le->block->iinstr, (bptr->icount+1)*sizeof(instruction));
2623 le->block->copied_to = bptr;
2625 /* add block to global list of BBs */
2626 temp = m->basicblocks;
2634 node_into_parent_loops(ld, lc->parent, bptr);
2638 ld->c_last_block_copied = bptr;
2640 /* create an additional basicblock for dynamic checks */
2641 original_start = bptr = DMNEW(basicblock, 1);
2643 /* copy current loop header to new basic block */
2644 memcpy(bptr, loop_head, sizeof(basicblock));
2647 /* insert the new basic block and move header before first loop node */
2651 /* if header is first node of loop, insert original header after it */
2652 if (temp == loop_head)
2653 loop_head->next = bptr;
2655 /* else, we have to find the predecessor of loop header */
2656 while (temp->next != loop_head)
2659 /* insert original header after newly created block */
2662 /* if predecessor is not loop part, insert a goto */
2663 if (!(temp->lflags & LOOP_PART)) {
2665 /* copy instructions and add an additional slot */
2666 tiptr = DMNEW(instruction, temp->icount + 1);
2667 memcpy(tiptr, temp->iinstr, sizeof(instruction)*temp->icount);
2669 temp->iinstr = tiptr;
2670 tiptr = temp->iinstr + temp->icount;
2672 /* add goto to loop header. If node is part of exception handler */
2673 /* jmp is automagically redirected during patch_handler and works */
2675 tiptr->opc = ICMD_GOTO;
2677 tiptr->target = (void*) loop_head;
2683 temp = m->basicblocks;
2684 /* if first loop block is first BB of global list, insert loop_head at */
2685 /* beginning of global BB list */
2686 if (temp == le->block) {
2687 if (ld->c_newstart == NULL) {
2688 ld->c_needs_redirection = true;
2689 ld->c_newstart = loop_head;
2690 loop_head->next = m->basicblocks;
2693 loop_head->next = ld->c_newstart;
2694 ld->c_newstart = loop_head;
2699 while (temp->next != le->block)
2702 loop_head->next = temp->next;
2703 temp->next = loop_head;
2705 /* to be on the safe side insert a jump from the previous instr */
2706 /* over thr new inserted node */
2708 /* special case - jump from node to loop_head: then remove */
2709 /* goto / happens rather often due to loop layout */
2710 tiptr = temp->iinstr + (temp->icount-1);
2712 if ((tiptr->opc == ICMD_GOTO) && (tiptr->target == loop_head)) {
2713 tiptr->opc = ICMD_NOP;
2718 tiptr = DMNEW(instruction, temp->icount + 1);
2719 memcpy(tiptr, temp->iinstr, sizeof(instruction)*temp->icount);
2721 temp->iinstr = tiptr;
2722 tiptr = temp->iinstr + temp->icount;
2724 tiptr->opc = ICMD_GOTO;
2726 tiptr->target = (void*) loop_head->next;
2733 /* adjust exceptions */
2734 ex = jd->exceptiontable;
2735 while (ex != NULL) {
2737 /* if an exception covers whole loop and starts at first loop node, it */
2738 /* has to be extended to cover the new first node as well */
2739 if (ex->start == le->block) {
2741 if ((lc->loop_head >= m->basicblockindex[ex->startpc]) && (lc->loop_head < m->basicblockindex[ex->endpc]))
2742 ex->start = loop_head;
2745 /* an exception that ended at the old loop header now must contains the */
2746 /* new loop header as well */
2747 if (ex->end == loop_head)
2748 ex->end = original_start;
2754 /* insert new header node into nodelists of all enclosing loops */
2755 header_into_parent_loops(ld, lc, loop_head, original_start, le->block);
2757 /* prepare instruction array to insert checks */
2758 inst = loop_head->iinstr = DMNEW(instruction, ld->c_needed_instr + 2);
2759 loop_head->icount = ld->c_needed_instr + 1;
2761 /* init instruction array */
2762 for (cnt=0; cnt<ld->c_needed_instr + 1; ++cnt) {
2763 inst[0].opc = ICMD_NOP;
2767 loop_head->copied_to = NULL;
2770 loop_head->instack = copy_stack_from(bptr->instack);
2771 loop_head->outstack = copy_stack_from(bptr->instack);
2773 tos = loop_head->instack;
2774 stackdepth = loop_head->indepth;
2776 /* step through all inserted checks and create instructions for them */
2777 for (i=0; i<jd->maxlocals+1; ++i)
2779 tc1 = ld->c_constraints[i];
2785 /* check a variable against a constant */
2787 case TEST_UNMOD_ZERO:
2790 printf("insert ZERO-test\n");
2794 /* optimize if tc1->varRef >= tc1->constant */
2795 LOAD_VAR(tc1->varRef);
2796 LOAD_CONST(tc1->constant);
2800 /* check a variable against an array length */
2802 case TEST_UNMOD_ALENGTH:
2805 /* tc1->varRef + tc1->constant < lengthOf(tc1->arrayRef) */
2807 printf("insert ALENGTH-test\n");
2811 LOAD_VAR(tc1->varRef);
2812 LOAD_CONST(tc1->constant);
2814 LOAD_ARRAYLENGTH(tc1->arrayRef);
2818 /* test right side of comparison against constant */
2822 printf("insert RS-ZERO-test\n");
2826 /* optimize if right-side >= tc1->constant */
2828 LOAD_CONST(tc1->constant);
2832 /* test right side of comparison against array length */
2833 case TEST_RS_ALENGTH:
2836 printf("insert RS-ALENGTH-test\n");
2839 /* optimize if right-side < lengthOf(arrayRef) */
2841 LOAD_ARRAYLENGTH(tc1->arrayRef);
2845 /* test unmodified variable against arraylength */
2846 case TEST_CONST_ALENGTH:
2849 printf("insert CONST ALENGTH-test\n");
2853 /* optimize if tc1->constant < lengthOf(tc1->arrayRef) */
2854 LOAD_CONST(tc1->constant);
2855 LOAD_ARRAYLENGTH(tc1->arrayRef);
2862 ld->c_constraints[i] = NULL;
2865 /* if all tests succeed, jump to optimized loop header */
2866 if (loop_head->next != original_start) {
2867 inst->opc = ICMD_GOTO;
2869 inst->target = original_start;
2872 /* redirect jumps from original loop head to newly inserted one */
2873 patch_jumps(original_start, loop_head, lc);
2875 /* if exceptions have to be correct due to loop duplication these two */
2876 /* functions perform this task. */
2877 update_internal_exceptions(m, cd, ld, lc, loop_head, original_start);
2878 update_external_exceptions(m, cd, ld, lc->parent, lc->loop_head);
2882 /* This function performs an update between two arrays of struct Changes (that
2883 reflect variable changes). The merge is performed unrstricted in the way, that
2884 all variable changes in c1 took place in a nested loop and therefore are
2885 considered to be without limit. Beside that, the merge is a simple union of the
2886 changes recorded in both arrays. A variable, which limits are undefinied, is
2887 represented by its lower bound being higher than the upper bound. The result
2888 of the union is stored in c1.
2890 struct Changes ** constraints_unrestricted_merge(codegendata *cd, struct Changes **c1, struct Changes **c2)
2894 if ((c1 == NULL) || (c2 == NULL))
2895 printf("C_ERROR: debugging error 0x03\n");
2898 for (i=0; i<jd->maxlocals; ++i) {
2899 if (c1[i] == NULL) {
2900 if (c2[i] != NULL) { /* a change in c2 is updated in c1 */
2903 c1[i]->lower_bound = c1[i]->upper_bound+1;
2907 if (c1[i]->lower_bound > c1[i]->upper_bound)
2908 continue; /* variable's bounds already undefined */
2910 if (c2[i] == NULL) { /* variable changed in c1 -> now undef. */
2912 c1[i]->lower_bound = c1[i]->upper_bound+1;
2915 if ((c1[i]->lower_bound == c2[i]->lower_bound) &&
2916 (c1[i]->upper_bound == c2[i]->upper_bound))
2917 continue; /* variable's bounds remain the same */
2920 c1[i]->lower_bound = c1[i]->upper_bound+1;
2921 } /* variable changed in c1 -> now undef. */
2932 /* This function performs an update between two arrays of struct Changes (that
2933 reflect variable changes). The merge is a simple union of the bounds
2934 changes recorded in both arrays. A variable, which limits are undefinied, is
2935 represented by its lower bound being higher than the upper bound. The result
2936 of the union is stored in c1.
2938 struct Changes ** constraints_merge(codegendata *cd, struct Changes **c1, struct Changes **c2)
2942 if ((c1 == NULL) || (c2 == NULL))
2943 printf("C_ERROR: debugging error 0x04\n");
2947 for (i=0; i<jd->maxlocals; ++i) {
2948 if (c1[i] == NULL) {
2949 if (c2[i] != NULL) { /* update changes in c2 in c1 */
2950 if ((c1[i] = (struct Changes *) malloc (sizeof(struct Changes))) == NULL)
2953 c1[i]->lower_bound = c2[i]->lower_bound;
2954 c1[i]->upper_bound = c2[i]->upper_bound;
2959 if (c2[i] != NULL) {
2961 if (c1[i]->lower_bound > c1[i]->upper_bound)
2962 continue; /* var in c1 is unrestricted */
2964 if (c1[i]->lower_bound > c2[i]->lower_bound) {
2965 c1[i]->lower_bound = c2[i]->lower_bound;
2966 changed = 1; /* write new lower bound */
2968 if (c1[i]->upper_bound < c2[i]->upper_bound) {
2969 c1[i]->upper_bound = c2[i]->upper_bound;
2970 changed = 1; /* write new higher bound */
2983 /* This function simply copies an array of changes
2985 struct Changes** constraints_clone(codegendata *cd, struct Changes **c)
2990 if ((t = (struct Changes **) malloc(jd->maxlocals * sizeof(struct Changes *))) == NULL)
2993 for (i=0; i<jd->maxlocals; ++i) { /* for all array elements (vars) do */
2997 if ((t[i] = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
2999 t[i]->lower_bound = c[i]->lower_bound;
3000 t[i]->upper_bound = c[i]->upper_bound;
3007 /* This function is used to reset the changes of a variable to the time, it was
3008 pushed onto the stack. If a variable has been modified between an instruction
3009 and a previous push onto the stack, its value in the changes array does not
3010 correctly reflect its bounds the time, it was pushed onto the stack. This
3011 function corrects the situation.
3013 struct Changes* backtrack_var(methodinfo *m, int node, int from, int to, int varRef, struct Changes *changes)
3015 struct Changes *tmp;
3020 if (changes == NULL) /* if there are no changes, immediately return */
3022 else { /* init a Changes structure with current values */
3023 if ((tmp = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
3026 tmp->upper_bound = changes->upper_bound;
3027 tmp->lower_bound = changes->lower_bound;
3030 if (tmp->upper_bound < tmp->lower_bound)
3031 return tmp; /* if it is unrestricted no backtracking can happen */
3033 bp = m->basicblocks[node];
3034 ip = bp.iinstr + to;
3036 for (; from < to; --to, --ip) { /* scan instructions backwards */
3038 case ICMD_IINC: /* a var has been modified */
3039 if (varRef != ip->op1) /* not the one, we are interested in */
3041 tmp->upper_bound -= ip->val.i; /* take back modifications */
3042 tmp->lower_bound -= ip->val.i;
3045 case ICMD_ISTORE: /* a var has been modified */
3046 if (varRef != ip->op1) /* not the one, we are interested in */
3049 /* it is our variable, so trace its origin */
3050 t = tracing(&m->basicblocks[node],to, 0);
3054 if ((t->var = ip->op1) && (t->neg > 0)) {
3055 /* it was the same var -> take back modifications */
3056 tmp->upper_bound -= t->constant;
3057 tmp->lower_bound -= t->constant;
3060 tmp->lower_bound = tmp->upper_bound+1; /* unknown */
3063 /* cannot restore it -> invalidate t */
3068 tmp->lower_bound = tmp->upper_bound+1;
3079 /* This function performs the main task of bound check removal. It removes
3080 all bound-checks in node. change is a pointer to an array of struct Changes
3081 that reflect for all local variables, how their values have changed from
3082 the start of the loop. The special flag is needed to deal with the header
3086 void remove_boundchecks(methodinfo *m, codegendata *cd, loopdata *ld, int node, int from, struct Changes **change, int special)
3090 int i, count, ignore, degrade_checks, opt_level;
3091 struct depthElement *d;
3092 struct Changes **t1, **tmp, *t;
3093 struct Trace *t_array, *t_index;
3095 /* prevent some compiler warnings */
3100 /* printf("remove_bc called: %d - %d - %d\n", node, from, special); */
3102 /* a flag, that is set, when previous optimzations have to be taken back */
3105 if (ld->c_current_loop[node] > 0) { /* this node is part of the loop */
3106 if (ld->c_current_loop[node] > 1) { /* it is not the header node */
3108 /* get variable changes, already recorded for this node */
3109 t1 = ld->c_dTable[node]->changes;
3111 if (t1 != NULL) { /* it is not the first visit */
3112 if ((ld->c_nestedLoops[node] != ld->c_current_head) && (ld->c_nestedLoops[node] == ld->c_nestedLoops[from])) {
3113 /* we are looping in a nested loop, so made optimizations */
3114 /* need to be reconsidered */
3116 if (constraints_unrestricted_merge(cd, t1, change) == NULL)
3117 return; /* no changes since previous visit */
3118 /* if there have been changes, they are updated by */
3119 /* constraints_unrestricted_merge in t1 */
3122 if (constraints_merge(cd, t1, change) == NULL)
3123 return; /* no changes since previous visit */
3124 /* if there have been changes, they are updated by */
3125 /* constraints_merge in t1 */
3128 else { /* first visit */
3129 /* printf("first visit - constraints cloned\n"); */
3130 ld->c_dTable[node]->changes = constraints_clone(cd, change);
3133 /* tmp now holds a copy of the updated variable changes */
3134 tmp = constraints_clone(cd, ld->c_dTable[node]->changes);
3136 else if (special) { /* header and need special traetment */
3137 /* printf("special treatment called\n"); */
3138 /* tmp now holds a copy of the current new variable changes */
3139 tmp = constraints_clone(cd, change);
3144 bp = m->basicblocks[node]; /* scan all instructions */
3149 for (i=0; i<count; ++i, ++ip) {
3151 case ICMD_IASTORE: /* found an array store */
3160 t_index = tracing(&bp, i-1, 1); /* get index */
3161 t_array = tracing(&bp, i-1, 2); /* get array refernce */
3165 case ICMD_IALOAD: /* found an array load */
3174 t_index = tracing(&bp, i-1, 0); /* get index */
3175 t_array = tracing(&bp, i-1, 1); /* get array refernce */
3179 /* printf("Array access with params:\n");
3181 show_trace(t_array);
3183 show_trace(t_index);
3186 #ifdef ENABLE_STATISTICS
3187 if (ip->op1 == OPT_UNCHECKED) { /* found new access */
3188 ld->c_stat_array_accesses++;
3190 ld->c_stat_no_opt++;
3194 /* can only optimize known arrays that do not change */
3195 if ((t_array->type != TRACE_AVAR) || (ld->c_var_modified[t_array->var]))
3198 switch (t_index->type) { /* now we look at the index */
3199 case TRACE_ICONST: /* it is a constant value or an */
3200 case TRACE_ALENGTH: /* array length */
3201 #ifdef ENABLE_STATISTICS
3202 switch (ip->op1) { /* take back old optimzation */
3206 ld->c_stat_no_opt--;
3209 ld->c_stat_full_opt--;
3212 ld->c_stat_upper_opt--;
3215 ld->c_stat_lower_opt--;
3219 if (degrade_checks) /* replace existing optimization */
3220 ip->op1 = insert_static(m, cd, ld, t_array->var, t_index, NULL, special);
3222 /* Check current optimization and try to improve it by */
3223 /* inserting new checks */
3226 ip->op1 = insert_static(m, cd, ld, t_array->var, t_index, NULL, special);
3229 ip->op1 = insert_static(m, cd, ld, t_array->var, t_index, NULL, special);
3232 opt_level = insert_static(m, cd, ld, t_array->var, t_index, NULL, special);
3233 if ((opt_level == OPT_FULL) || (opt_level == OPT_LOWER))
3237 opt_level = insert_static(m, cd, ld, t_array->var, t_index, NULL, special);
3238 if ((opt_level == OPT_FULL) || (opt_level == OPT_UPPER))
3242 #ifdef ENABLE_STATISTICS
3243 ld->c_stat_full_opt++;
3250 case TRACE_IVAR: /* it's a variable */
3252 /* if the variable is changed between its usage as an index */
3253 /* of the array access and its push onto the stack, we have */
3254 /* to set the changes back to the time, it is pushed onto */
3255 /* the stack as an index variable. */
3256 t = backtrack_var(m, node, t_index->nr, i-1, t_index->var, tmp[t_index->var]);
3257 #ifdef ENABLE_STATISTICS
3258 switch (ip->op1) { /* take back old optimzation */
3262 ld->c_stat_no_opt--;
3265 ld->c_stat_full_opt--;
3268 ld->c_stat_upper_opt--;
3271 ld->c_stat_lower_opt--;
3276 ip->op1 = insert_static(m, cd, ld, t_array->var, t_index, t, special);
3278 /* Check current optimization and try to improve it by */
3279 /* insert new check. t reflects var changes for index */
3282 ip->op1 = insert_static(m, cd, ld, t_array->var, t_index, t, special);
3285 ip->op1 = insert_static(m, cd, ld, t_array->var, t_index, t, special);
3288 opt_level = insert_static(m, cd, ld, t_array->var, t_index, t, special);
3289 if ((opt_level == OPT_FULL) || (opt_level == OPT_LOWER))
3293 opt_level = insert_static(m, cd, ld, t_array->var, t_index, t, special);
3294 if ((opt_level == OPT_FULL) || (opt_level == OPT_UPPER))
3298 #ifdef ENABLE_STATISTICS
3299 ld->c_stat_full_opt++;
3312 case ICMD_ISTORE: /* an integer value is stored */
3313 t_index = tracing(&bp, i-1, 0); /* trace back its origin */
3315 /* the struct Changes for this variable needs to be updated */
3317 if (t == NULL) { /* if it's the first one, create new entry */
3318 if ((t = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
3320 t->upper_bound = t->lower_bound = 0;
3324 switch (t_index->type) { /* check origin of store */
3326 case TRACE_ICONST: /* constant -> set bounds to const value */
3327 t->upper_bound = t->lower_bound = t_index->constant;
3330 case TRACE_IVAR: /* if it's the same variable, update consts */
3331 if ((t_index->var = ip->op1) && (t_index->neg > 0)) {
3332 t->upper_bound += t_index->constant;
3333 t->lower_bound += t_index->constant;
3336 t->lower_bound = t->upper_bound+1;
3339 case TRACE_ALENGTH: /* else -> unknown */
3342 t->lower_bound = t->upper_bound+1;
3350 /* the struct Changes for this variable needs to be updated */
3351 if ((t = tmp[ip->op1]) == NULL) { /* first one -> create new */
3352 if ((t = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
3354 t->upper_bound = t->lower_bound = ip->val.i;
3357 else { /* update changes, made by iinc */
3358 t->upper_bound += ip->val.i;
3359 t->lower_bound += ip->val.i;
3365 if (!special) { /* we are not interested in only the header */
3366 d = ld->c_dTable[node];
3367 while (d != NULL) { /* check all sucessors of current node */
3368 remove_boundchecks(m, cd, ld, d->value, node, tmp, special);
3376 /* This function calls the bound-check removal function for the header node
3377 with a special flag. It is important to notice, that no dynamic
3378 constraint hold in the header node (because the comparison is done at
3382 void remove_header_boundchecks(methodinfo *m, codegendata *cd, loopdata *ld, int node, struct Changes **changes)
3384 remove_boundchecks(m, cd, ld, node, -1, changes, BOUNDCHECK_SPECIAL);
3388 /* Marks all basicblocks that are part of the loop
3391 void mark_loop_nodes(struct LoopContainer *lc)
3393 struct LoopElement *le = lc->nodes;
3395 while (le != NULL) {
3396 le->block->lflags |= LOOP_PART;
3402 /* Clears mark for all basicblocks that are part of the loop
3404 void unmark_loop_nodes(LoopContainer *lc)
3406 LoopElement *le = lc->nodes;
3408 while (le != NULL) {
3409 le->block->lflags = 0;
3415 /* This function performs the analysis of code in detected loops and trys to
3416 identify array accesses suitable for optimization (bound check removal). The
3417 intermediate code is then modified to reflect these optimizations.
3419 void optimize_single_loop(methodinfo *m, codegendata *cd, loopdata *ld, LoopContainer *lc)
3421 struct LoopElement *le;
3422 struct depthElement *d;
3424 struct Changes **changes;
3426 if ((changes = (struct Changes **) malloc(jd->maxlocals * sizeof(struct Changes *))) == NULL)
3429 head = ld->c_current_head = lc->loop_head;
3430 ld->c_needed_instr = ld->c_rs_needed_instr = 0;
3432 /* init array for null ptr checks */
3433 for (i=0; i<jd->maxlocals; ++i)
3434 ld->c_null_check[i] = 0;
3437 /* don't optimize root node (it is the main procedure, not a loop) */
3441 /* setup variables with initial values */
3442 ld->c_loopvars = NULL;
3443 for (i=0; i < m->basicblockcount; ++i) {
3444 ld->c_toVisit[i] = 0;
3445 ld->c_current_loop[i] = -1;
3446 if ((d = ld->c_dTable[i]) != NULL)
3450 for (i=0; i < jd->maxlocals; ++i) {
3451 ld->c_var_modified[i] = 0;
3452 if (changes[i] != NULL) {
3457 for (i=0; i < (jd->maxlocals+1); ++i) {
3458 if (ld->c_constraints[i] != NULL) {
3459 ld->c_constraints[i] = NULL;
3464 while (le != NULL) {
3468 ld->c_current_loop[node] = 1; /* the header node gets 1 */
3469 else if (ld->c_nestedLoops[node] == head)
3470 ld->c_current_loop[node] = 2; /* top level nodes get 2 */
3472 ld->c_current_loop[node] = 3; /* nodes, part of nested loop get 3 */
3474 ld->c_toVisit[node] = 1;
3478 /* After setup work has been performed, start to analyse */
3480 printf("****** Starting analysis (%d)******\n", head);
3484 if (analyze_for_array_access(m, ld, head) > 0) {/* loop contains array access */
3489 printf("analyze for array access finished and found\n");
3491 lv = ld->c_loopvars;
3492 while (lv != NULL) {
3494 printf("Var --> %d\n", lv->value);
3499 /* for performance reasons the list of all interesting loop vars is */
3500 /* scaned and for all modified vars a flag in c_var_modified is set */
3501 scan_global_list(ld);
3504 printf("global list scanned\n");
3508 /* if the loop header contains or-conditions or an index variable */
3509 /* is modified in the catch-block within the loop, a conservative */
3510 /* approach is taken and optimizations are cancelled */
3511 if (analyze_or_exceptions(m, cd, ld, head, lc) > 0) {
3514 printf("Analyzed for or/exception - no problems \n");
3518 init_constraints(m, ld, head); /* analyze dynamic bounds in header */
3524 if (ld->c_rightside == NULL)
3527 /* single pass bound check removal - for all successors, do */
3528 remove_header_boundchecks(m, cd, ld, head, changes);
3530 d = ld->c_dTable[head];
3532 remove_boundchecks(m, cd, ld, d->value, -1, changes, BOUNDCHECK_REGULAR);
3537 printf("Array-bound checks finished\n");
3541 mark_loop_nodes(lc);
3544 printf("START: create static checks\n");
3548 create_static_checks(m, cd, ld, lc); /* create checks */
3551 printf("END: create static checks\n");
3554 unmark_loop_nodes(lc);
3558 printf("No array accesses found\n"); */
3560 #ifdef ENABLE_STATISTICS
3561 ld->c_stat_num_loops++; /* increase number of loops */
3563 ld->c_stat_sum_accesses += ld->c_stat_array_accesses;
3564 ld->c_stat_sum_full += ld->c_stat_full_opt;
3565 ld->c_stat_sum_no += ld->c_stat_no_opt;
3566 ld->c_stat_sum_lower += ld->c_stat_lower_opt;
3567 ld->c_stat_sum_upper += ld->c_stat_upper_opt;
3568 ld->c_stat_sum_or += ld->c_stat_or;
3569 ld->c_stat_sum_exception += ld->c_stat_exception;
3571 ld->c_stat_array_accesses = 0;
3572 ld->c_stat_full_opt = 0;
3573 ld->c_stat_no_opt = 0;
3574 ld->c_stat_lower_opt = 0;
3575 ld->c_stat_upper_opt = 0;
3576 ld->c_stat_or = ld->c_stat_exception = 0;
3582 /* optimize_loops **************************************************************
3584 This function preforms necessary setup work, before the recursive
3585 function optimize_single loop can be called.
3587 *******************************************************************************/
3589 void optimize_loops(jitdata *jd)
3596 /* get required compiler data */
3602 lc = ld->c_allLoops;
3604 /* first, merge loops with same header node - all loops with the same */
3605 /* header node are optimizied in one pass, because they all depend on the */
3606 /* same dynamic loop condition */
3609 printf("start analyze_double_headers\n");
3613 analyze_double_headers(ld);
3615 /* create array with loop nesting levels - nested loops cause problems, */
3616 /* especially, when they modify index variables used in surrounding loops */
3617 /* store results in array c_nestedLoops and c_hierarchie */
3620 printf("double done\n");
3624 analyze_nested(m,cd, ld);
3627 printf("analyze nested done\n");
3631 /* create array with entries for current loop */
3632 ld->c_current_loop = DMNEW(int, m->basicblockcount);
3633 ld->c_toVisit = DMNEW(int, m->basicblockcount);
3634 ld->c_var_modified = DMNEW(int, jd->maxlocals);
3635 ld->c_null_check = DMNEW(int, jd->maxlocals);
3637 if ((ld->c_constraints = (struct Constraint **) malloc((jd->maxlocals+1) * sizeof(struct Constraint *))) == NULL)
3640 #ifdef ENABLE_STATISTICS
3641 ld->c_stat_num_loops = 0; /* set statistic vars to zero */
3642 ld->c_stat_array_accesses = ld->c_stat_sum_accesses = 0;
3643 ld->c_stat_full_opt = ld->c_stat_sum_full = 0;
3644 ld->c_stat_no_opt = ld->c_stat_sum_no = 0;
3645 ld->c_stat_lower_opt = ld->c_stat_sum_lower = 0;
3646 ld->c_stat_upper_opt = ld->c_stat_sum_upper = 0;
3647 ld->c_stat_or = ld->c_stat_sum_or = 0;
3648 ld->c_stat_exception = ld->c_stat_sum_exception = 0;
3651 /* init vars needed by all loops */
3652 ld->c_needs_redirection = false;
3653 ld->c_newstart = NULL;
3654 ld->c_old_xtablelength = jd->exceptiontablelength;
3656 /* loops have been topologically sorted */
3657 lc = ld->c_allLoops;
3658 while (lc != NULL) {
3659 optimize_single_loop(m, cd, ld, lc);
3662 printf(" *** Optimized loop *** \n");
3669 printf("---*** All loops finished ***---\n");
3673 /* if global BB list start is modified, set block to new start */
3674 if (ld->c_needs_redirection == true)
3675 m->basicblocks = ld->c_newstart;
3681 * These are local overrides for various environment variables in Emacs.
3682 * Please do not remove this and leave it at the end of the file, where
3683 * Emacs will automagically detect them.
3684 * ---------------------------------------------------------------------
3687 * indent-tabs-mode: t