1 /* vm/jit/loop/analyze.c - bound check removal functions
3 Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
4 R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
5 C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
6 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., 59 Temple Place - Suite 330, Boston, MA
25 Contact: cacao@complang.tuwien.ac.at
27 Authors: Christopher Kruegel
29 Contains the functions which perform the bound check removals. With
30 the loops identified, these functions scan the code for array
31 accesses that take place in loops and try to guarantee that their
32 bounds are never violated. The function to call is
35 $Id: analyze.c 1735 2004-12-07 14:33:27Z twisti $
44 #include "mm/memory.h"
45 #include "toolbox/logging.h"
46 #include "vm/jit/jit.h"
47 #include "vm/jit/loop/analyze.h"
48 #include "vm/jit/loop/graph.h"
49 #include "vm/jit/loop/loop.h"
50 #include "vm/jit/loop/tracing.h"
55 /* Test functions -> will be removed in final release
58 void show_trace(struct Trace *trace)
61 switch (trace->type) {
64 printf("\nNr.:\t%d", trace->var);
65 printf("\nValue:\t%d", trace->constant);
70 printf("\nNr.:\t%d", trace->var);
74 printf("array-length");
75 printf("\nNr.:\t%d", trace->var);
76 printf("\nValue:\t%d", trace->constant);
81 printf("\nValue:\t%d", trace->constant);
90 printf("Trace is null");
96 void show_change(struct Changes *c)
98 printf("*** Changes ***\n");
100 printf("Lower/Upper Bound:\t%d/%d\n", c->lower_bound, c->upper_bound);
102 printf("Unrestricted\n");
105 show_varinfo(struct LoopVar *lv)
107 printf(" *** Loop Info ***\n");
108 printf("Value:\t%d\n", lv->value);
109 printf("Static:\t\t%d/%d\n", lv->static_l, lv->static_u);
110 printf("D-Valid:\t%d/%d\n", lv->dynamic_l_v, lv->dynamic_u_v);
111 printf("Dynamic\t\t%d/%d\n", lv->dynamic_l, lv->dynamic_u);
114 void show_right_side(methodinfo *m)
117 printf("\n *** Head *** \nType:\t");
118 show_trace(m->loopdata->c_rightside);
120 printf("\n *** Nested Loops: ***\n");
121 for (i=0; i<m->basicblockcount; ++i)
122 printf("%d\t", m->loopdata->c_nestedLoops[i]);
125 printf("\n *** Hierarchie: ***\n");
126 for (i=0; i<m->basicblockcount; ++i)
127 printf("%d\t", m->loopdata->c_hierarchie[i]);
131 printf("\n *** Current Loop ***\n");
132 for (i=0; i<m->basicblockcount; ++i)
133 printf("%d\t", m->loopdata->c_current_loop[i]);
137 void resultPass3(methodinfo *m)
140 struct LoopContainer *lc = m->loopdata->c_allLoops;
142 printf("\n\n****** PASS 3 ******\n\n");
145 printf("Loop Analysis:\n");
146 printf("Optimize:\t%d\n", lc->toOpt);
147 printf("Modified Vars: ");
149 for (i=0; i<lc->num_vars; ++i)
150 printf("%d ", lc->vars[i]);
156 printf("\nNested Loops:\n");
157 for (i=0; i<m->basicblockcount; ++i)
158 printf("%d ", m->loopdata->c_nestedLoops[i]);
160 for (i=0; i<m->basicblockcount; ++i)
161 printf("%d ", m->loopdata->c_hierarchie[i]);
166 void show_tree(struct LoopContainer *lc, int tabs)
171 for (cnt = 0; cnt < tabs; ++cnt)
173 printf("%d\n", lc->loop_head);
175 show_tree(lc->tree_down, tabs+1);
185 void show_loop_statistics(loopdata *ld)
187 printf("\n\n****** LOOP STATISTICS ****** \n\n");
189 printf("Optimization cancelled by or\n");
190 else if (ld->c_stat_exception)
191 printf("Optimization cancelled by exception\n");
193 printf("Number of array accesses:\t%d\n", ld->c_stat_array_accesses);
194 if (ld->c_stat_array_accesses) {
195 printf("\nFully optimized:\t%d\n", ld->c_stat_full_opt);
196 printf("Not optimized:\t\t%d\n", ld->c_stat_no_opt);
197 printf("Upper optimized:\t%d\n", ld->c_stat_upper_opt);
198 printf("Lower optimized:\t%d\n", ld->c_stat_lower_opt);
203 void show_procedure_statistics(loopdata *ld)
205 printf("\n\n****** PROCEDURE STATISTICS ****** \n\n");
206 printf("Number of loops:\t\t%d\n", ld->c_stat_num_loops);
207 printf("Number of array accesses:\t%d\n", ld->c_stat_sum_accesses);
208 if (ld->c_stat_sum_accesses) {
209 printf("\nFully optimized:\t%d\n", ld->c_stat_sum_full);
210 printf("Not optimized:\t\t%d\n", ld->c_stat_sum_no);
211 printf("Upper optimized:\t%d\n", ld->c_stat_sum_upper);
212 printf("Lower optimized:\t%d\n", ld->c_stat_sum_lower);
214 printf("Opt. cancelled by or:\t\t%d\n", ld->c_stat_sum_or);
215 printf("Opt. cancelled by exception:\t%d\n", ld->c_stat_sum_exception);
221 /* This function is used to merge two loops with the same header together.
222 A simple merge sort of the lists nodes of both loops is performed.
224 void analyze_merge(struct LoopContainer *l1, struct LoopContainer *l2)
226 struct LoopElement *start, *last, *le1, *le2;
227 /* start and last are pointers to the newly built list, le1 and le2 step */
228 /* step through the lists, that have to be merged. */
233 /* start a simple merge sort of the nodes of both loops. These lists are */
234 /* already sorted, so merging is easy. */
235 if (le1->node < le2->node) {
239 else if (le1->node == le2->node) {
249 /* while the first loop != NULL, depending of the first element of second */
250 /* loop, add new node to result list */
251 while (le1 != NULL) {
257 if (le1->node < le2->node) {
261 else if (le1->node == le2->node) {
278 /* This function is used to merge loops with the same header node to a single
279 one. O(n^2) of number of loops. This merginig is necessary, because the loop
280 finding algorith sometimes (eg. when loopbody ends with a if-else construct)
281 reports a single loop as two loops with the same header node.
283 void analyze_double_headers(loopdata *ld)
286 LoopContainer *t1, *t2, *t3;
290 while (t1 != NULL) { /* for all loops do */
291 toCheck = t1->loop_head; /* get header node */
294 while (t2 != NULL) { /* compare it to headers of rest */
295 if (t2->loop_head == toCheck) {
297 /* found overlapping loops -> merge them together */
298 /* printf("C_INFO: found overlapping loops - merging"); */
299 analyze_merge(t1, t2);
301 /* remove second loop from the list of all loops */
303 while (t3->next != t2)
315 /* After the hierarchie of loops has been built, we have to insert the exceptions
316 into this tree. The exception ex is inserted into the subtree pointed to by
319 void insert_exception(methodinfo *m, struct LoopContainer *lc, exceptiontable *ex)
321 struct LoopContainer *temp;
322 struct LoopElement *le;
325 /* printf("insert_exception called with %d-%d and loop %d\n", ex->start->debug_nr, ex->end->debug_nr, lc->loop_head); */
328 /* if child node is reached immediately insert exception into the tree */
329 if (lc->tree_down == NULL) {
330 ex->next = lc->exceptions;
334 /* if we are inside the tree, there are two possibilities: */
335 /* 1. the exception is inside a nested loop or */
336 /* 2. in the loop body of the current loop */
338 /* check all children (= nested loops) */
339 temp = lc->tree_down;
341 while (temp != NULL) {
347 printf("%d.%d\n", le->node, block_index[ex->startpc]);
349 /* if the start of the exception is part of the loop, the */
350 /* whole exception must be part of the loop */
351 if (le->node == m->basicblockindex[ex->startpc])
356 /* Exception is part of a nested loop (Case 1) -> insert it there */
358 insert_exception(m, temp, ex);
361 else if ((temp->loop_head >= m->basicblockindex[ex->startpc]) && (temp->loop_head < m->basicblockindex[ex->endpc])) {
363 /* optimization: if nested loop is part of the exception, the */
364 /* exception cannot be part of a differnet nested loop. */
365 ex->next = lc->exceptions;
370 temp = temp->tree_right;
373 /* Exception is not contained in any nested loop (Case 2) */
375 ex->next = lc->exceptions;
382 /* This function builds a loop hierarchie. The header node of the innermost loop,
383 each basic block belongs to, is stored in the array c_nestedLoops. The array
384 c_hierarchie stores the relationship between differnt loops in as follows:
385 Each loop, that is a nested loop, stores its direct surrounding loop as a
386 parent. Top level loops have no parents.
389 void analyze_nested(methodinfo *m, codegendata *cd, loopdata *ld)
391 /* i/count/tmp are counters */
392 /* toOverwrite is used while loop hierarchie is built (see below) */
393 int i, header, toOverwrite, tmp, len;
395 /* first/last are used during topological sort to build ordered loop list */
396 struct LoopContainer *first, *last, *start, *t, *temp;
398 /* Used to step through all nodes of a loop. */
399 struct LoopElement *le;
401 /* init global structures */
402 ld->c_nestedLoops = DMNEW(int, m->basicblockcount);
403 ld->c_hierarchie = DMNEW(int, m->basicblockcount);
404 for (i=0; i<m->basicblockcount; ++i) {
405 ld->c_nestedLoops[i] = -1;
406 ld->c_hierarchie[i] = -1;
409 /* if there are no optimizable loops -> return */
410 if (ld->c_allLoops == NULL)
413 temp = ld->c_allLoops;
414 while (temp != NULL) { /* for all loops, do */
415 header = temp->loop_head;
417 /* toOverwrite is number of current parent loop (-1 if none) */
418 toOverwrite = ld->c_nestedLoops[header];
420 ld->c_hierarchie[header] = toOverwrite;
422 if (toOverwrite == header) /* check for loops with same header */
423 printf("C_ERROR: Loops have same header\n");
426 while (le != NULL) { /* for all loop nodes, do */
427 tmp = ld->c_nestedLoops[le->node];
429 /* if node is part of parent loop -> overwrite it with nested */
430 if (tmp == toOverwrite)
431 ld->c_nestedLoops[le->node] = header;
433 ld->c_hierarchie[tmp] = header;
435 /* printf("set head of %d to %d", tmp, header); */
445 /* init root of hierarchie tree */
446 ld->root = DMNEW(struct LoopContainer, 1);
447 LoopContainerInit(m, ld->root, -1);
449 /* obtain parent pointer and build hierarchie tree */
450 start = ld->c_allLoops;
451 while (start != NULL) {
453 /* look for parent of loop pointed at by start */
454 first = ld->c_allLoops;
455 while (first != NULL) {
457 /* the parent of the loop, pointed at by start has been found */
458 if (first->loop_head == ld->c_hierarchie[start->loop_head]) {
460 /* printf("set parent to pointer\n"); */
463 start->parent = first;
464 start->tree_right = first->tree_down;
465 first->tree_down = start;
472 /* no parent loop found, set parent to root */
475 /* printf("set parent to root\n"); */
478 start->parent = ld->root;
479 start->tree_right = ld->root->tree_down;
480 ld->root->tree_down = start;
482 /* if a parent exists, increase this nodes indegree */
484 start->parent->in_degree += 1;
489 /* insert exceptions into tree */
491 printf("--- Showing tree ---\n");
492 show_tree(ld->root, 0);
493 printf(" --- End ---\n");
495 for (len = 0; len < cd->exceptiontablelength; ++len)
496 insert_exception(m, ld->root, cd->exceptiontable + len);
499 /* determine sequence of loops for optimization by topological sort */
503 temp = ld->c_allLoops;
504 while (temp != NULL) {
506 /* a loops with indegree == 0 are pushed onto the stack */
507 if (temp->in_degree == 0) {
519 first = last = start;
523 printf("C_ERROR: loops are looped\n");
527 /* pop each node from the stack and decrease its parents indegree by one */
528 /* when the parents indegree reaches zero, push it onto the stack as well */
529 if ((last->parent != ld->root) && (--last->parent->in_degree == 0)) {
530 last->parent->next = start;
531 start = last->parent;
533 while (start != NULL) {
540 if ((last->parent != ld->root) && (--last->parent->in_degree == 0)) {
541 last->parent->next = start;
542 start = last->parent;
547 ld->c_allLoops = first;
550 printf("*** Hierarchie Results \n");
551 while (first != NULL) {
552 printf("%d ", first->loop_head);
561 /* This function is used to add variables that occur as index variables in
562 array accesses (ARRAY_INDEX) or as variables, that change their value (VAR_MOD)
563 to the list of interesting vars (c_loopvars) for the current loop.
566 void add_to_vars(loopdata *ld, int var, int type, int direction)
570 /* printf("Added to vars %d %d %d\n", var, type, direction); */
572 while (lv != NULL) { /* check if var has been previously added */
573 if (lv->value == var) {
574 if (type == ARRAY_INDEX)
575 lv->index = 1; /* var is used as index */
576 else if (type == VAR_MOD) {
577 lv->modified = 1; /* var is used in assignment */
578 switch (direction) { /* how was var modified ? */
580 lv->static_u = 0; /* incremented, no static upper */
581 break; /* bound can be guaranteeed */
583 lv->static_l = 0; /* decremented, no static lower */
584 break; /* bound can be guaranteeed */
586 lv->static_u = lv->static_l = 0;
587 break; /* no info at all */
589 printf("C_ERROR: unknown direction\n");
598 /* variable is not found in list -> add variable to list */
599 lv = DNEW(struct LoopVar);
601 lv->modified = lv->index = 0;
604 if (type == ARRAY_INDEX) {
606 lv->static_u = lv->static_l = 1; /* arrayindex -> var not modified */
608 else if (type == VAR_MOD) {
610 switch (direction) { /* var used in assignment -> set */
611 case D_UP: /* proper static bounds */
612 lv->static_u = 0; lv->static_l = 1;
615 lv->static_u = 1; lv->static_l = 0;
618 lv->static_u = lv->static_l = 0;
621 printf("C_ERROR: unknown direction\n");
626 /* no dynamic bounds have been determined so far */
627 lv->dynamic_l = lv->dynamic_l_v = lv->dynamic_u = lv->dynamic_u_v = 0;
629 lv->next = ld->c_loopvars; /* add var to list */
634 /* This function checks, whether a given loop with header node contains array
635 accesses. If so, it returns 1, else it returns 0 and the loops needs no
636 further consideration in the optimization process. When array accesses are
637 found, a list of all variables, that are used as array index, is built and
638 stored in c_loopvars. For all variables (integer), which values are changed,
639 a flag in c_var_modified is set.
642 int analyze_for_array_access(methodinfo *m, loopdata *ld, int node)
647 struct depthElement *d;
650 if (ld->c_toVisit[node] > 0) { /* node has not been visited yet */
651 ld->c_toVisit[node] = 0;
653 bp = m->basicblocks[node]; /* prepare an instruction scan */
657 access = 0; /* number of array accesses in loop */
659 for (i=0; i<ic; ++i, ++ip) { /* for each instruction, check opcode */
661 case ICMD_IASTORE: /* array store */
669 t = tracing(&bp, i-1, 1); /* try to identify index variable */
671 if (t->type == TRACE_IVAR) {
672 /* if it is a variable, add it to list of index variables */
673 add_to_vars(ld, t->var, ARRAY_INDEX, D_UNKNOWN);
676 else if (t->type == TRACE_ICONST)
680 case ICMD_IALOAD: /* array load */
688 t = tracing(&bp, i-1, 0); /* try to identify index variable */
690 if (t->type == TRACE_IVAR) {
691 /* if it is a variable, add it to list of index variables */
692 add_to_vars(ld, t->var, ARRAY_INDEX, D_UNKNOWN);
695 else if (t->type == TRACE_ICONST)
699 case ICMD_ISTORE: /* integer store */
700 ld->c_var_modified[ip->op1] = 1;
702 /* try to find out, how it was modified */
703 t = tracing(&bp, i-1, 0);
704 if (t->type == TRACE_IVAR) {
705 if ((t->constant > 0) && (t->var == ip->op1))
706 /* a constant was added to the same var */
707 add_to_vars(ld, t->var, VAR_MOD, D_UP);
708 else if (t->var == ip->op1)
709 /* a constant was subtracted from the same var */
710 add_to_vars(ld, t->var, VAR_MOD, D_DOWN);
712 add_to_vars(ld, t->var, VAR_MOD, D_UNKNOWN);
715 add_to_vars(ld, ip->op1, VAR_MOD, D_UNKNOWN);
718 case ICMD_IINC: /* simple add/sub of a constant */
719 ld->c_var_modified[ip->op1] = 1;
722 add_to_vars(ld, ip->op1, VAR_MOD, D_UP);
724 add_to_vars(ld, ip->op1, VAR_MOD, D_DOWN);
731 ld->c_var_modified[ip->op1] = 1;
736 d = ld->c_dTable[node];
737 while (d != NULL) { /* check all successors of block */
738 access += analyze_for_array_access(m, ld, d->value);
749 /* This function scans the exception graph structure to find modifications of
750 array index variables of the current loop. If any modifications are found,
751 1 is returned, else 0.
754 int quick_scan(methodinfo *m, loopdata *ld, int node)
760 struct depthElement *d;
762 /* printf("QS: %d - %d\n", node, ld->c_exceptionVisit[node]); */
765 if (ld->c_exceptionVisit[node] > 0) { /* node is part of exception graph */
766 ld->c_exceptionVisit[node] = -1;
768 bp = m->basicblocks[node]; /* setup scan of all instructions */
772 for (i=0; i<count; ++i, ++ip) { /* for each instruction do */
775 case ICMD_IINC: /* a variable is modified */
777 lv = ld->c_loopvars; /* is it an array index var ? */
779 if ((lv->index) && (lv->value == ip->op1))
780 return 1; /* yes, so return 1 */
787 d = ld->c_exceptionGraph[node]; /* check all successor nodes */
789 if (quick_scan(m, ld, d->value) > 0)
790 return 1; /* if an access is found return 1 */
794 return 0; /* nothing found, so return 0 */
801 /* This function returns 1, when the condition of the loop contains
802 or statements or when an array index variable is modified in any
803 catch block within the loop.
806 int analyze_or_exceptions(methodinfo *m, codegendata *cd, loopdata *ld, int head, struct LoopContainer *lc)
808 struct depthElement *d;
809 int i, k, value, flag, count;
810 struct LoopElement *le;
812 d = ld->c_dTable[head];
815 /* analyze for or-statements */
817 printf("*** Analyze for OR ... ");
821 while (d != NULL) { /* for all successor nodes check if they */
822 value = d->value; /* are part of the loop */
827 if (le->node == value)
832 if (le == NULL) /* node is not part of the loop */
839 if ((count > 1) && (flag == 0)){/* if all successors part of the loop, exit */
846 /* check for exceptions */
847 /* printf("done\n*** Analyze for EXCEPTIONS(%d) . ", cd->exceptiontablelength); */
849 if (!cd->exceptiontablelength) /* when there are no exceptions, exit */
852 if ((ld->c_exceptionGraph = (struct depthElement **) malloc(sizeof(struct depthElement *) * m->basicblockcount)) == NULL)
854 if ((ld->c_exceptionVisit = (int *) malloc(sizeof(int) * m->basicblockcount)) == NULL)
857 for (k=0; k<m->basicblockcount; ++k) {
858 ld->c_exceptionVisit[k] = -1;
859 ld->c_exceptionGraph[k] = NULL;
863 /* for all nodes that start catch block check whether they are part of loop */
864 for (i = 0; i < ld->c_old_xtablelength; i++) {
865 value = m->basicblockindex[cd->exceptiontable[i].startpc];
870 if (le->node == value) { /* exception is in loop */
872 printf("C_INFO: Loop contains exception\n");
876 /* build a graph structure, that contains all nodes that are */
877 /* part of the catc block */
878 dF_Exception(m, ld, -1, m->basicblockindex[cd->exceptiontable[i].handlerpc]);
880 /* if array index variables are modified there, return 0 */
881 if (quick_scan(m, ld, m->basicblockindex[cd->exceptiontable[i].handlerpc]) > 0) {
883 ld->c_stat_exception++;
885 /* printf("C_INFO: loopVar modified in exception\n"); */
894 printf("none ... done\n");
901 /* This function sets a flag in c_var_modified for all variables that have
902 been found as part of an assigment in the loop.
905 void scan_global_list(loopdata *ld)
912 ld->c_var_modified[lv->value] = 1;
918 /* This function analyses the condition in the loop header and trys to find
919 out, whether some dynamic guarantees can be set up.
922 void init_constraints(methodinfo *m, loopdata *ld, int head)
926 int ic, l_mod, r_mod, changed, operand;
927 struct Trace *left, *right, *th;
928 struct LoopVar *lv_left, *lv_right, *lh;
930 bp = m->basicblocks[head];
932 ip = bp.iinstr+(ic-1); /* set ip to last instruction in header node */
934 switch (ip->opc) { /* check op-code */
936 /* comparison against constant value */
937 case ICMD_IFEQ: /* ..., value ==> ... */
938 case ICMD_IFLT: /* ..., value ==> ... */
939 case ICMD_IFLE: /* ..., value ==> ... */
940 case ICMD_IFGT: /* ..., value ==> ... */
941 case ICMD_IFGE: /* ..., value ==> ... */
942 /* op1 = target JavaVM pc, val.i = constant */
944 left = tracing(&bp, ic-2, 0); /* analyse left arg., right is constant */
945 right = create_trace(TRACE_ICONST, -1, ip->val.i, 0);
948 /* standard comparison */
949 case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */
950 case ICMD_IF_ICMPLT: /* ..., value, value ==> ... */
951 case ICMD_IF_ICMPGT: /* ..., value, value ==> ... */
952 case ICMD_IF_ICMPLE: /* ..., value, value ==> ... */
953 case ICMD_IF_ICMPGE: /* ..., value, value ==> ... */
955 left = tracing(&bp, ic-2, 1); /* get left and right argument */
956 right = tracing(&bp, ic-2, 0);
959 /* other condition */
961 left = create_trace(TRACE_UNKNOWN, -1, 0, 0);
962 right = create_trace(TRACE_UNKNOWN, -1, 0, 0);
966 /* analyse left and right side of comparison */
969 if (left->type == TRACE_IVAR) { /* is a loop variable on left side ? */
970 lv_left = ld->c_loopvars;
971 while (lv_left != NULL) {
972 if (lv_left->value == left->var) {
973 l_mod = lv_left->modified; /* yes, but has it been modified ? */
976 lv_left = lv_left->next;
980 if (right->type == TRACE_IVAR){ /* is a loop variable on right side ? */
981 lv_right = ld->c_loopvars;
982 while (lv_right != NULL) {
983 if (lv_right->value == right->var) {
984 r_mod = lv_right->modified; /* yes, but has it been modified ? */
987 lv_right = lv_right->next;
991 if ((l_mod - r_mod) == 0) { /* both 1 or both 0 -> no dynamic contraints*/
992 ld->c_rightside = NULL; /* possible */
996 /* to simplify processing, make the left side the one, that contains the */
997 /* modified variable */
999 th = left; left = right; right = th;
1000 lh = lv_left; lv_left = lv_right; lv_right = lh;
1001 changed = 1; /* set changed to true */
1004 changed = 0; /* no change needed */
1006 /* make sure that right side's value does not change during loop execution */
1007 if (right->type == TRACE_UNKNOWN) {
1008 ld->c_rightside = NULL;
1012 /* determine operands: */
1013 /* for further explaination a is modified, b nonmodified var */
1014 switch (ip->opc) { /* check opcode again */
1015 case ICMD_IFEQ: /* ..., value ==> ... */
1016 case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */
1017 operand = OP_EQ; /* a == b */
1020 case ICMD_IFLE: /* ..., value ==> ... */
1021 case ICMD_IF_ICMPLE: /* ..., value, value ==> ... */
1023 operand = OP_GE; /* b<=a -> a>=b */
1025 operand = OP_LT; /* a<=b -> a<(b+1) */
1026 if (left->constant != 0)
1027 left->constant -= 1;
1029 right->constant += 1;
1033 case ICMD_IFLT: /* ..., value ==> ... */
1034 case ICMD_IF_ICMPLT: /* ..., value, value ==> ... */
1036 operand = OP_GE; /* b<a -> a>=(b+1) */
1037 if (left->constant != 0)
1038 left->constant -= 1;
1040 right->constant += 1;
1043 operand = OP_LT; /* a<b -> a<b */
1046 case ICMD_IFGT: /* ..., value ==> ... */
1047 case ICMD_IF_ICMPGT: /* ..., value, value ==> ... */
1049 operand = OP_LT; /* b>a -> a<b */
1051 operand = OP_GE; /* a>b -> a>=(b+1) */
1052 if (left->constant != 0)
1053 left->constant -= 1;
1055 right->constant += 1;
1059 case ICMD_IFGE: /* ..., value ==> ... */
1060 case ICMD_IF_ICMPGE: /* ..., value, value ==> ... */
1062 operand = OP_LT; /* b>=a -> a<(b+1) */
1063 if (left->constant != 0)
1064 left->constant -= 1;
1066 right->constant += 1;
1069 operand = OP_GE; /* a>=b -> a>=b */
1073 printf("C_ERROR: debugging error 0x00\n");
1077 /* NOW: left/lv_left -> loopVar */
1078 /* right/lv_right -> const, nonmod. var, arraylength */
1079 switch (operand) { /* check operand */
1081 lv_left->dynamic_u_v = 1; /* upper + lower bound tested */
1082 lv_left->dynamic_l_v = 1;
1084 lv_left->dynamic_l = lv_left->dynamic_u = left->constant;
1088 lv_left->dynamic_u_v = 1; /* upper bound tested */
1090 lv_left->dynamic_u = left->constant;
1094 lv_left->dynamic_l_v = 1; /* lower bound tested */
1096 lv_left->dynamic_l = left->constant;
1100 printf("C_ERROR: debugging error 0x01\n");
1103 ld->c_rightside = right;
1105 switch (ld->c_rightside->type) {
1107 ld->c_rs_needed_instr = 1;
1110 ld->c_rs_needed_instr = 2;
1113 ld->c_rs_needed_instr = 3;
1116 printf("C_ERROR: wrong right-side type\n");
1121 /* This function is needed to add and record new static tests (before loop
1122 entry) of variables to make guaratees for index variables. type states
1123 the kind of the test. arrayRef is the array, which length is tested
1124 against, varRef is the variable, that is testes and constant is the
1125 constant value, that is tested.
1128 void add_new_constraint(methodinfo *m, codegendata *cd, loopdata *ld, int type, int arrayRef, int varRef, int constant)
1130 struct Constraint *tc;
1133 case TEST_ZERO: /* a variable is tested against a const */
1135 tc = ld->c_constraints[varRef]; /* does a test already exist for this var ? */
1136 while (tc != NULL) {
1137 if (tc->type == TEST_ZERO) {
1138 if (constant < tc->constant)
1139 tc->constant = constant;
1140 return; /* yes. update constant and return */
1145 /* insert a new test for this variable */
1146 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1148 tc->type = TEST_ZERO;
1149 tc->varRef = varRef;
1150 tc->constant = constant;
1151 tc->next = ld->c_constraints[varRef];
1152 ld->c_constraints[varRef] = tc;
1153 ld->c_needed_instr += 3;
1157 case TEST_ALENGTH: /* variable is tested against array length */
1159 tc = ld->c_constraints[varRef]; /* does a test already exist for this var ? */
1160 while (tc != NULL) {
1161 if ((tc->type == TEST_ALENGTH) && (tc->arrayRef == arrayRef)) {
1162 if (constant > tc->constant)
1163 tc->constant = constant;
1164 return; /* yes. update constant and return */
1169 /* insert a new test for this variable */
1170 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1172 tc->type = TEST_ALENGTH;
1173 tc->arrayRef = arrayRef;
1174 tc->varRef = varRef;
1175 tc->constant = constant;
1176 tc->next = ld->c_constraints[varRef];
1177 ld->c_constraints[varRef] = tc;
1178 ld->c_needed_instr += 6;
1180 /* if arrayRef is not already tested against null, insert that test */
1181 if (!(ld->c_null_check[arrayRef])) {
1182 ld->c_null_check[arrayRef] = 1;
1183 ld->c_needed_instr +=2;
1188 case TEST_CONST_ZERO:
1192 case TEST_CONST_ALENGTH: /* a const is tested against array length */
1194 /* does a test already exist for this array */
1195 tc = ld->c_constraints[cd->maxlocals];
1196 while (tc != NULL) {
1197 if ((tc->type == TEST_CONST_ALENGTH) && (tc->arrayRef == arrayRef)) {
1198 if (constant > tc->constant)
1199 tc->constant = constant;
1200 return; /* yes. update constant and return */
1205 /* insert a new test for this array */
1206 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1208 tc->type = TEST_CONST_ALENGTH;
1209 tc->arrayRef = arrayRef;
1210 tc->constant = constant;
1211 tc->next = ld->c_constraints[cd->maxlocals];
1212 ld->c_constraints[cd->maxlocals] = tc;
1213 ld->c_needed_instr += 4;
1215 /* if arrayRef is not already tested against null, insert that test */
1216 if (!(ld->c_null_check[arrayRef])) {
1217 ld->c_null_check[arrayRef] = 1;
1218 ld->c_needed_instr +=2;
1223 case TEST_UNMOD_ZERO: /* test unmodified var against constant */
1225 /* search if test already exists */
1226 tc = ld->c_constraints[varRef];
1227 while (tc != NULL) {
1228 if (tc->type == TEST_UNMOD_ZERO) {
1229 if (constant < tc->constant)
1230 tc->constant = constant;
1231 return; /* yes, so update constant */
1236 /* else, a new test is inserted */
1237 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1239 tc->type = TEST_UNMOD_ZERO;
1240 tc->varRef = varRef;
1241 tc->constant = constant;
1242 tc->next = ld->c_constraints[varRef];
1243 ld->c_constraints[varRef] = tc;
1244 ld->c_needed_instr += 3;
1248 case TEST_UNMOD_ALENGTH: /* test unmodified var against array length */
1250 /* search if test alreay exists */
1251 tc = ld->c_constraints[varRef];
1252 while (tc != NULL) {
1253 if ((tc->type == TEST_UNMOD_ALENGTH) && (tc->arrayRef == arrayRef)) {
1254 if (constant > tc->constant)
1255 tc->constant = constant;
1256 return; /* yes, so modify constants */
1261 /* create new entry */
1262 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1264 tc->type = TEST_UNMOD_ALENGTH;
1265 tc->varRef = varRef;
1266 tc->arrayRef = arrayRef;
1267 tc->constant = constant;
1268 tc->next = ld->c_constraints[varRef];
1269 ld->c_constraints[varRef] = tc;
1270 ld->c_needed_instr += 6;
1272 /* if arrayRef is not already tested against null, insert that test */
1273 if (!(ld->c_null_check[arrayRef])) {
1274 ld->c_null_check[arrayRef] = 1;
1275 ld->c_needed_instr +=2;
1280 case TEST_RS_ZERO: /* test right side of the loop condition */
1281 /* against a constant - needed by dynamic */
1283 /*!! varRef -> maxlocals */
1284 /* search if test already exists */
1285 tc = ld->c_constraints[cd->maxlocals];
1286 while (tc != NULL) {
1287 if (tc->type == TEST_RS_ZERO) {
1288 if (constant < tc->constant)
1289 tc->constant = constant;
1290 return; /* yes, so modify constants */
1295 /* create new entry */
1296 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1298 tc->type = TEST_RS_ZERO;
1299 tc->constant = constant;
1300 tc->next = ld->c_constraints[cd->maxlocals];
1301 ld->c_constraints[cd->maxlocals] = tc;
1302 ld->c_needed_instr += (2 + ld->c_rs_needed_instr);
1304 /* if arrayRef on right side is not already tested against null, */
1305 /* insert that test */
1306 if ((ld->c_rightside->type == TRACE_ALENGTH) && (!(ld->c_null_check[ld->c_rightside->var]))) {
1307 ld->c_null_check[ld->c_rightside->var] = 1;
1308 ld->c_needed_instr +=2;
1313 case TEST_RS_ALENGTH: /* test right side of the loop condition */
1314 /* against array length - needed by dynamic */
1316 /*!! varRef -> maxlocals */
1317 /* search if test already exists */
1318 tc = ld->c_constraints[cd->maxlocals];
1321 if ((tc->type == TEST_RS_ALENGTH) && (tc->arrayRef == arrayRef))
1323 if (constant > tc->constant)
1324 tc->constant = constant;
1325 return; /* yes, so modify constants */
1330 /* create new entry */
1331 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1333 tc->type = TEST_RS_ALENGTH;
1334 tc->arrayRef = arrayRef;
1335 tc->constant = constant;
1336 tc->next = ld->c_constraints[cd->maxlocals];
1337 ld->c_constraints[cd->maxlocals] = tc;
1338 ld->c_needed_instr += (3 + ld->c_rs_needed_instr);
1340 /* if arrayRef is not already tested against null, insert that test */
1341 if (!(ld->c_null_check[arrayRef])) {
1342 ld->c_null_check[arrayRef] = 1;
1343 ld->c_needed_instr +=2;
1346 /* if arrayRef on right side is not already tested against null, */
1347 /* insert that test */
1348 if ((ld->c_rightside->type == TRACE_ALENGTH) && (!(ld->c_null_check[ld->c_rightside->var]))) {
1349 ld->c_null_check[ld->c_rightside->var] = 1;
1350 ld->c_needed_instr +=2;
1358 /* This functions adds new static (before loop enry) tests of variables to the
1359 program to be able to guarantee certain values for index variables in array
1360 access (to safely remove bound checks).
1363 int insert_static(methodinfo *m, codegendata *cd, loopdata *ld, int arrayRef, struct Trace *index, struct Changes *varChanges, int special)
1369 /* printf("insert static check - %d\n", arrayRef);
1371 show_change(varChanges);
1374 if (varChanges == NULL) { /* the variable hasn't changed / const */
1375 if ((varChanges = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
1377 varChanges->lower_bound = varChanges->upper_bound = 0;
1380 switch (index->type) { /* check index type */
1381 case TRACE_IVAR: /* it is a variable */
1382 if (index->neg < 0) { /* if it's a negated var, return */
1384 ld->c_stat_no_opt++;
1389 varRef = index->var;
1392 if (ld->c_var_modified[varRef]) { /* volatile var */
1394 lv = ld->c_loopvars; /* get reference to loop variable */
1396 while ((lv != NULL) && (lv->value != varRef))
1399 printf("C_ERROR: debugging error 0x02\n");
1401 /* show_varinfo(lv); */
1403 /* check existing static bounds and add new contraints on variable */
1404 /* to possibly remove bound checks */
1406 /* the var is never decremented, so we add a static test againt */
1408 if (varChanges->lower_bound > varChanges->upper_bound)
1409 add_new_constraint(m, cd, ld, TEST_ZERO, arrayRef, varRef, index->constant);
1411 add_new_constraint(m, cd, ld, TEST_ZERO, arrayRef, varRef, varChanges->lower_bound+index->constant);
1414 else if ((lv->dynamic_l_v) && (!special)) {
1415 /* the variable is decremented, but it is checked against a */
1416 /* bound in the loop condition */
1417 if (varChanges->lower_bound <= varChanges->upper_bound) {
1418 add_new_constraint(m, cd, ld, TEST_RS_ZERO, arrayRef, varRef, varChanges->lower_bound+index->constant+lv->dynamic_l);
1424 /* the var is never incremented, so we add a static test againt */
1426 if (varChanges->lower_bound > varChanges->upper_bound)
1427 add_new_constraint(m, cd, ld, TEST_ALENGTH, arrayRef, varRef, index->constant);
1429 add_new_constraint(m, cd, ld, TEST_ALENGTH, arrayRef, varRef, varChanges->upper_bound+index->constant);
1432 else if ((lv->dynamic_u_v) && (!special)) {
1433 /* the variable is decremented, but it is checked against a */
1434 /* bound in the loop condition */
1435 if (varChanges->lower_bound <= varChanges->upper_bound) {
1436 add_new_constraint(m, cd, ld, TEST_RS_ALENGTH, arrayRef, varRef, varChanges->upper_bound+index->constant+lv->dynamic_u);
1441 else { /* the var is never modified at all */
1442 add_new_constraint(m, cd, ld, TEST_UNMOD_ZERO, arrayRef, index->var, index->constant);
1443 add_new_constraint(m, cd, ld, TEST_UNMOD_ALENGTH, arrayRef, index->var, index->constant);
1447 /* if the addition of new variable tests made guarantees possible, */
1448 /* return the best possible optimization */
1449 if ((high > 0) && (low > 0)) {
1450 /* printf("fully optimzed\n"); */
1452 ld->c_stat_full_opt++;
1456 else if (high > 0) {
1457 /* printf("upper optimzed\n"); */
1459 ld->c_stat_upper_opt++;
1464 /* printf("lower optimzed\n"); */
1466 ld->c_stat_lower_opt++;
1471 /* printf("not optimzed\n"); */
1473 ld->c_stat_no_opt++;
1479 case TRACE_ICONST: /* if it is a constant, optimization is easy */
1480 if (index->constant < 0) {
1482 ld->c_stat_no_opt++;
1484 return OPT_NONE; /* negative index -> bad */
1487 add_new_constraint(m, cd, ld, TEST_CONST_ALENGTH, arrayRef, 0, index->constant);
1489 ld->c_stat_full_opt++;
1491 return OPT_FULL; /* else just test constant against array length */
1495 case TRACE_ALENGTH: /* else, no optimizations possible */
1499 ld->c_stat_no_opt++;
1504 /* keep compiler happy */
1510 /* copy a stack and return the start pointer of the newly created one
1512 stackptr copy_stack_from(stackptr source) {
1513 stackptr current, top;
1518 /* copy first element */
1519 current = DMNEW(stackelement, 1);
1520 current->type = source->type;
1521 current->flags = source->flags;
1522 current->varkind = source->varkind;
1523 current->varnum = source->varnum;
1524 current->regoff = source->regoff;
1528 /* if there exist more, then copy the rest */
1529 while (source->prev != NULL) {
1530 source = source->prev;
1531 current->prev = DMNEW(stackelement, 1);
1532 current->type = source->type;
1533 current->flags = source->flags;
1534 current->varkind = source->varkind;
1535 current->varnum = source->varnum;
1536 current->regoff = source->regoff;
1537 current = current->prev;
1540 current->prev = NULL;
1545 /* The following defines are used in the procedure void create_static_checks(...)
1546 They add a new instruction with its corresponding stack manipulation and
1547 are used to build the new loop header of an optimized loop, where we have
1548 to check certain variables and constants against values to guarantee that
1549 index values in array accesses remain with array bounds.
1551 inst: pointer to the new instruction
1552 tos: stackpointer before this operation is executed
1553 newstack: temporary stackptr
1554 stackdepth: counts the current stackdepth
1555 original start: blockpointer to the head of the new, optimized loop
1558 /* Load a local integer variable v */
1559 #define LOAD_VAR(v) { \
1560 inst->opc = ICMD_ILOAD; \
1562 newstack = DMNEW(stackelement, 1); \
1563 inst->dst = newstack; \
1564 newstack->prev = tos; \
1565 newstack->type = TYPE_INT; \
1566 newstack->flags = 0; \
1567 newstack->varkind = LOCALVAR; \
1568 newstack->varnum = v; \
1574 /* Load a constant with value c */
1575 #define LOAD_CONST(c) { \
1576 inst->opc = ICMD_ICONST; \
1578 inst->val.i = (c); \
1579 newstack = DMNEW(stackelement, 1); \
1580 newstack->prev = tos; \
1581 newstack->type = TYPE_INT; \
1582 newstack->flags = 0; \
1583 newstack->varkind = UNDEFVAR; \
1584 newstack->varnum = stackdepth; \
1591 /* Load a local reference (adress) variable a */
1592 #define LOAD_ADDR(a) { \
1593 inst->opc = ICMD_ALOAD; \
1595 newstack = DMNEW(stackelement, 1); \
1596 newstack->prev = tos; \
1597 newstack->type = TYPE_ADR; \
1598 newstack->flags = 0; \
1599 newstack->varkind = LOCALVAR; \
1600 newstack->varnum = a; \
1607 /* Insert a compare greater-or-equal and jump to the unoptimized loop, if the */
1608 /* comparison is true */
1609 #define GOTO_NOOPT_IF_GE { \
1610 inst->opc = ICMD_IF_ICMPGE; \
1611 inst->target = original_start->copied_to; \
1612 if (tos->varkind == UNDEFVAR) \
1613 tos->varkind = TEMPVAR; \
1615 if (tos->varkind == UNDEFVAR) \
1616 tos->varkind = TEMPVAR; \
1623 /* Insert a compare greater than and jump to the unoptimized loop, if the */
1624 /* comparison is true */
1625 #define GOTO_NOOPT_IF_GT { \
1626 inst->opc = ICMD_IF_ICMPGT; \
1627 inst->target = original_start->copied_to; \
1628 if (tos->varkind == UNDEFVAR) \
1629 tos->varkind = TEMPVAR; \
1631 if (tos->varkind == UNDEFVAR) \
1632 tos->varkind = TEMPVAR; \
1640 /* Insert a compare less-than and jump to the unoptimized loop, if the */
1641 /* comparison is true */
1642 #define GOTO_NOOPT_IF_LT { \
1643 inst->opc = ICMD_IF_ICMPLT; \
1644 inst->target = original_start->copied_to; \
1645 if(tos->varkind == UNDEFVAR) \
1646 tos->varkind = TEMPVAR; \
1648 if(tos->varkind == UNDEFVAR) \
1649 tos->varkind = TEMPVAR; \
1656 /* Insert a compare if-not-null and jump to the unoptimized loop, if the */
1657 /* comparison is true */
1658 #define GOTO_NOOPT_IF_NULL { \
1659 inst->opc = ICMD_IFNULL; \
1660 inst->target = original_start->copied_to; \
1661 if(tos->varkind == UNDEFVAR) \
1662 tos->varkind = TEMPVAR; \
1669 /* Insert an add instruction, that adds two integer values on top of the stack */
1672 inst->opc = ICMD_IADD; \
1673 if(tos->varkind == UNDEFVAR) \
1674 tos->varkind = TEMPVAR; \
1676 if(tos->varkind == UNDEFVAR) \
1677 tos->varkind = TEMPVAR; \
1679 newstack = DMNEW(stackelement, 1); \
1680 newstack->prev = tos; \
1681 newstack->type = TYPE_INT; \
1682 newstack->flags = 0; \
1683 newstack->varkind = UNDEFVAR; \
1684 newstack->varnum = stackdepth; \
1691 /* Insert instructions to load the arraylength of an array with reference a */
1692 /* fisrt, the reference must be loaded, then a null-pointer check is inserted */
1693 /* if not already done earlier. Finally an arraylength instruction is added */
1694 #define LOAD_ARRAYLENGTH(a) { \
1695 if (ld->c_null_check[a]) { \
1697 GOTO_NOOPT_IF_NULL; \
1698 ld->c_null_check[a] = 0; \
1701 inst->opc = ICMD_ARRAYLENGTH; \
1702 if(tos->varkind == UNDEFVAR) \
1703 tos->varkind = TEMPVAR; \
1705 newstack = DMNEW(stackelement, 1); \
1706 newstack->prev = tos; \
1707 newstack->type = TYPE_INT; \
1708 newstack->flags = 0; \
1709 newstack->varkind = UNDEFVAR; \
1710 newstack->varnum = stackdepth; \
1717 /* Inserts the instructions to load the value of the right side of comparison */
1718 /* Depending of the type of the right side, the apropriate instructions are */
1720 #define LOAD_RIGHT_SIDE { \
1721 switch (ld->c_rightside->type) { \
1722 case TRACE_ICONST: \
1723 LOAD_CONST(ld->c_rightside->constant); \
1726 LOAD_VAR(ld->c_rightside->var); \
1727 LOAD_CONST(ld->c_rightside->constant); \
1730 case TRACE_ALENGTH: \
1731 LOAD_ARRAYLENGTH(ld->c_rightside->var); \
1734 panic("C_ERROR: illegal trace on rightside of loop-header"); \
1738 /* Patch jumps in original loop and in copied loop, add gotos in copied loop.
1739 All jumps in the original loop to the loop head have to be redirected to
1740 the newly inserted one. For the copied loop, it is necessay to redirect all
1741 jumps inside that loop to the copied nodes. lc points to the current loop,
1742 loop_head is a pointer to the newly inserted head and original start was
1743 the old head and is now the head of the optimized variant of the loop.
1745 void patch_jumps(basicblock *original_start, basicblock *loop_head, struct LoopContainer *lc)
1747 /* step through all nodes of a loop */
1748 struct LoopElement *le;
1750 instruction *inst, *temp_instr;
1754 while (le != NULL) {
1756 /* do nothing for new loop head */
1757 if (le->block == loop_head) {
1762 /* for original version */
1764 inst = bptr->iinstr;
1765 for (i = 0; i < bptr->icount; ++i, ++inst) {
1766 switch (inst->opc) {
1768 case ICMD_IF_ICMPEQ:
1769 case ICMD_IF_ICMPLT:
1770 case ICMD_IF_ICMPLE:
1771 case ICMD_IF_ICMPNE:
1772 case ICMD_IF_ICMPGT:
1773 case ICMD_IF_ICMPGE:
1775 case ICMD_IF_LCMPEQ:
1776 case ICMD_IF_LCMPLT:
1777 case ICMD_IF_LCMPLE:
1778 case ICMD_IF_LCMPNE:
1779 case ICMD_IF_LCMPGT:
1780 case ICMD_IF_LCMPGE:
1782 case ICMD_IF_ACMPEQ:
1783 case ICMD_IF_ACMPNE:
1802 case ICMD_IFNONNULL:
1804 /* jump to newly inserted loopheader has to be redirected */
1805 if (((basicblock *) inst->target) == loop_head)
1806 inst->target = (void *) original_start;
1809 case ICMD_TABLESWITCH:
1814 tptr = (void **) inst->target;
1816 s4ptr = inst->val.a;
1817 l = s4ptr[1]; /* low */
1818 i = s4ptr[2]; /* high */
1822 /* jump to newly inserted loopheader has to be redirected */
1823 for (tptr = inst->target; i >= 0; --i, ++tptr) {
1824 if (((basicblock *) *tptr) == loop_head)
1825 tptr[0] = (void *) original_start;
1830 case ICMD_LOOKUPSWITCH:
1835 tptr = (void **) inst->target;
1837 s4ptr = inst->val.a;
1838 l = s4ptr[0]; /* default */
1839 i = s4ptr[1]; /* count */
1841 /* jump to newly inserted loopheader has to be redirected */
1842 for (tptr = inst->target; i >= 0; --i, ++tptr) {
1843 if (((basicblock *) *tptr) == loop_head)
1844 tptr[0] = (void *) original_start;
1851 /* if node is part of loop and has fall through to original start, that */
1852 /* must be redirected. Unfortunately the instructions have to be copied */
1854 if (bptr->next == loop_head) {
1855 temp_instr = DMNEW(instruction, bptr->icount + 1);
1856 memcpy(temp_instr, bptr->iinstr, sizeof(instruction)*bptr->icount);
1857 bptr->iinstr = temp_instr;
1859 bptr->iinstr[bptr->icount].opc = ICMD_GOTO;
1860 bptr->iinstr[bptr->icount].target = original_start;
1861 bptr->iinstr[bptr->icount].dst = NULL;
1865 /* for copied version - which gets the unoptimized variant */
1866 bptr = le->block->copied_to;
1867 inst = bptr->iinstr;
1868 for (i = 0; i < bptr->icount; ++i, ++inst) {
1870 switch (inst->opc) {
1872 case ICMD_IASTORE: /* array store */
1880 case ICMD_IALOAD: /* array load */
1889 /* undo previous optimizations in new loop */
1893 case ICMD_IF_ICMPEQ:
1894 case ICMD_IF_ICMPLT:
1895 case ICMD_IF_ICMPLE:
1896 case ICMD_IF_ICMPNE:
1897 case ICMD_IF_ICMPGT:
1898 case ICMD_IF_ICMPGE:
1900 case ICMD_IF_LCMPEQ:
1901 case ICMD_IF_LCMPLT:
1902 case ICMD_IF_LCMPLE:
1903 case ICMD_IF_LCMPNE:
1904 case ICMD_IF_LCMPGT:
1905 case ICMD_IF_LCMPGE:
1907 case ICMD_IF_ACMPEQ:
1908 case ICMD_IF_ACMPNE:
1927 case ICMD_IFNONNULL:
1929 /* jump to newly inserted loopheader has to be redirected */
1930 if (((basicblock *) inst->target) == loop_head)
1931 inst->target = (void *) original_start->copied_to;
1932 /* jump to loop internal nodes has to be redirected */
1933 else if (((basicblock *) inst->target)->lflags & LOOP_PART)
1934 inst->target = (void *) ((basicblock *) inst->target)->copied_to;
1937 case ICMD_TABLESWITCH:
1941 void **copy_ptr, *base_ptr;
1944 tptr = (void **) inst->target;
1946 s4ptr = inst->val.a;
1947 l = s4ptr[1]; /* low */
1948 i = s4ptr[2]; /* high */
1952 copy_ptr = (void**) DMNEW(void*, i+1);
1953 base_ptr = (void*) copy_ptr;
1955 /* Targets for switch instructions are stored in an extra */
1956 /* that must be copied for new inserted loop. */
1958 for (tptr = inst->target; i >= 0; --i, ++tptr, ++copy_ptr) {
1959 /* jump to newly inserted loopheader must be redirected */
1960 if (((basicblock *) *tptr) == loop_head)
1961 copy_ptr[0] = (void *) original_start->copied_to;
1962 /* jump to loop internal nodes has to be redirected */
1963 else if (((basicblock *) *tptr)->lflags & LOOP_PART)
1964 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
1966 copy_ptr[0] = tptr[0];
1969 inst->target = base_ptr;
1973 case ICMD_LOOKUPSWITCH:
1977 void **copy_ptr, **base_ptr;
1980 tptr = (void **) inst->target;
1982 s4ptr = inst->val.a;
1983 l = s4ptr[0]; /* default */
1984 i = s4ptr[1]; /* count */
1986 copy_ptr = (void**) DMNEW(void*, i+1);
1987 base_ptr = (void*) copy_ptr;
1989 /* Targets for switch instructions are stored in an extra */
1990 /* that must be copied for new inserted loop. */
1992 for (tptr = inst->target; i >= 0; --i, ++tptr, ++copy_ptr) {
1993 /* jump to newly inserted loopheader must be redirected */
1994 if (((basicblock *) *tptr) == loop_head)
1995 copy_ptr[0] = (void *) original_start->copied_to;
1996 /* jump to loop internal nodes has to be redirected */
1997 else if (((basicblock *) *tptr)->lflags & LOOP_PART)
1998 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2000 copy_ptr[0] = tptr[0];
2003 inst->target = base_ptr;
2010 /* if fall through exits loop, goto is needed */
2011 if (!(le->block->next->lflags & LOOP_PART)) {
2012 bptr->iinstr[bptr->icount].opc = ICMD_GOTO;
2013 bptr->iinstr[bptr->icount].dst = NULL;
2014 bptr->iinstr[bptr->icount].target = le->block->next;
2023 /* Add the new header node of a loop that has been duplicated to all parent
2024 loops in nesting hierarchie.
2027 void header_into_parent_loops(loopdata *ld, struct LoopContainer *lc, basicblock *to_insert, basicblock *replace, basicblock *after)
2029 /* we have to insert the node to_insert before the node after and replace */
2030 /* the pointer of to_insert by the node replace */
2032 struct LoopElement *le, *t;
2034 /* if the top of the tree is reached, then return */
2035 if ((lc == NULL) || (lc == ld->root))
2038 /* create new node, that should be inserted */
2039 t = DMNEW(struct LoopElement, 1);
2040 t->block = to_insert;
2043 /* first, find the node, that has to be replaced (= "to_insert") and */
2044 /* replace it by the node "replace" */
2046 while (le->block != to_insert)
2048 le->block = replace;
2051 if (after == to_insert)
2054 /* now find the node after and insert the newly create node before "after" */
2056 if (le->block == after) {
2057 t->next = lc->nodes;
2061 while (le->next->block != after)
2068 /* go up one hierarchie level */
2069 header_into_parent_loops(ld, lc->parent, to_insert, replace, after);
2073 /* Add a new node (not header) of a duplicated loop to all parent loops in
2077 void node_into_parent_loops(loopdata *ld, struct LoopContainer *lc, basicblock *to_insert)
2079 struct LoopElement *le, *t;
2081 /* if the top of the tree is reached, then return */
2082 if ((lc == NULL) || (lc == ld->root))
2085 /* create new node, that should be inserted */
2086 t = DNEW(LoopElement);
2087 t->block = to_insert;
2092 /* append new node to node list of loop */
2093 while (le->next != NULL)
2099 /* go up one hierarchie level */
2100 node_into_parent_loops(ld, NULL, to_insert);
2104 /* void patch_handler(...) is very similar to parts of the function patch_jumps.
2105 Its task is to redirect all jumps from the original head to the new head and
2106 to redirect internal jumps inside the exception handler to the newly
2107 created (copied) nodes.
2110 void patch_handler(struct LoopContainer *lc, basicblock *bptr, basicblock *original_head, basicblock *new_head)
2115 /* If node is not part of exception handler or has been visited, exit */
2116 if (!(bptr->lflags & HANDLER_PART) || (bptr->lflags & HANDLER_VISITED))
2119 /* mark block as visited */
2120 bptr->lflags |= HANDLER_VISITED;
2122 /* for all instructions in the copied block, do */
2123 for (i = 0, ip = bptr->copied_to->iinstr; i < bptr->copied_to->icount; ++i, ++ip) {
2134 case ICMD_IF_ICMPEQ:
2135 case ICMD_IF_ICMPLT:
2136 case ICMD_IF_ICMPLE:
2137 case ICMD_IF_ICMPNE:
2138 case ICMD_IF_ICMPGT:
2139 case ICMD_IF_ICMPGE:
2141 case ICMD_IF_LCMPEQ:
2142 case ICMD_IF_LCMPLT:
2143 case ICMD_IF_LCMPLE:
2144 case ICMD_IF_LCMPNE:
2145 case ICMD_IF_LCMPGT:
2146 case ICMD_IF_LCMPGE:
2148 case ICMD_IF_ACMPEQ:
2149 case ICMD_IF_ACMPNE:
2167 case ICMD_IFNONNULL:
2169 patch_handler(lc, bptr->next, original_head, new_head);
2175 patch_handler(lc, ip->target, original_head, new_head);
2177 /* jumps to old header have to be redirected */
2178 if (((basicblock *) ip->target) == original_head)
2179 ip->target = (void *) new_head->copied_to;
2180 /* jumps to handler internal nodes have to be redirected */
2181 else if (((basicblock *) ip->target)->lflags & HANDLER_PART)
2182 ip->target = (void *) ((basicblock *) ip->target)->copied_to;
2183 /* jumps to loop internal nodes have to be redirected */
2184 else if (((basicblock *) ip->target)->lflags & LOOP_PART)
2185 ip->target = (void *) ((basicblock *) ip->target)->copied_to;
2190 case ICMD_TABLESWITCH:
2194 void **copy_ptr, **base_ptr;
2196 tptr = (void **) ip->target;
2198 l = s4ptr[1]; /* low */
2199 i = s4ptr[2]; /* high */
2202 copy_ptr = (void**) DMNEW(void*, i+1);
2203 base_ptr = (void*) copy_ptr;
2205 for (tptr = ip->target; i >= 0; --i, ++tptr, ++copy_ptr) {
2206 patch_handler(lc, ((basicblock *) *tptr), original_head, new_head);
2207 /* jumps to old header have to be redirected */
2208 if (((basicblock *) *tptr) == original_head)
2209 copy_ptr[0] = (void *) new_head->copied_to;
2210 /* jumps to handler internal nodes have to be redirected */
2211 else if (((basicblock *) *tptr)->lflags & HANDLER_PART)
2212 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2213 /* jumps to loop internal nodes have to be redirected */
2214 else if (((basicblock *) ip->target)->lflags & LOOP_PART)
2215 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2217 copy_ptr[0] = tptr[0];
2220 ip->target = base_ptr;
2224 case ICMD_LOOKUPSWITCH:
2229 void **copy_ptr, **base_ptr;
2231 tptr = (void **) ip->target;
2233 l = s4ptr[0]; /* default */
2234 i = s4ptr[1]; /* count */
2236 copy_ptr = (void**) DMNEW(void*, i+1);
2237 base_ptr = (void*) copy_ptr;
2239 for (tptr = ip->target; i >= 0; --i, ++tptr, ++copy_ptr) {
2241 patch_handler(lc, ((basicblock *) *tptr), original_head, new_head);
2242 /* jumps to old header have to be redirected */
2243 if (((basicblock *) *tptr) == original_head)
2244 copy_ptr[0] = (void *) new_head->copied_to;
2245 /* jumps to handler internal nodes have to be redirected */
2246 else if (((basicblock *) *tptr)->lflags & HANDLER_PART)
2247 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2248 /* jumps to loop internal nodes have to be redirected */
2249 else if (((basicblock *) ip->target)->lflags & LOOP_PART)
2250 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2252 copy_ptr[0] = tptr[0];
2255 ip->target = base_ptr;
2263 /* if fall through exits loop, goto is needed */
2264 if (!(bptr->next->lflags & HANDLER_PART)) {
2265 bptr->copied_to->iinstr[bptr->copied_to->icount].opc = ICMD_GOTO;
2266 bptr->copied_to->iinstr[bptr->copied_to->icount].dst = NULL;
2267 bptr->copied_to->iinstr[bptr->copied_to->icount].target = bptr->next;
2268 bptr->copied_to->icount++;
2273 /* copy_handler ****************************************************************
2275 This function copys the exception handler and redirects all jumps from the
2276 original head to the new head in the original exception handler. All
2277 redirection in the copied exception handler is done in patch_handler(...).
2279 *******************************************************************************/
2281 void copy_handler(methodinfo *m, loopdata *ld, struct LoopContainer *lc, basicblock *bptr, basicblock *original_head, basicblock *new_head)
2286 int high, low, count;
2287 struct LoopElement *le;
2288 basicblock *new, *temp;
2290 /* If this node has already been copied, return */
2291 if (bptr->lflags & HANDLER_PART)
2294 /* The exception handler exists, when control flow enters loop again */
2296 if (bptr->lflags & LOOP_PART)
2298 for (le = lc->nodes; le != NULL; le = le->next) {
2299 if (le->block == bptr) {
2300 printf("C_PANIC: should not happen\n");
2305 /* mark block as part of handler */
2306 bptr->lflags |= HANDLER_PART;
2309 new = DMNEW(basicblock, 1);
2310 memcpy(new, bptr, sizeof(basicblock));
2311 new->debug_nr = m->c_debug_nr++;
2313 ld->c_last_block_copied = new;
2315 /* copy instructions and allow one more slot for possible GOTO */
2316 new->iinstr = DMNEW(instruction, bptr->icount + 1);
2317 memcpy(new->iinstr, bptr->iinstr, bptr->icount * sizeof(instruction));
2319 /* update original block */
2320 bptr->copied_to = new;
2322 /* append block to global list of basic blocks */
2323 temp = m->basicblocks;
2332 /* find next block to copy, depending on last instruction of BB */
2333 if (bptr->icount == 0) {
2334 copy_handler(m, ld, lc, bptr->next, original_head, new_head);
2338 ip = bptr->iinstr + (bptr->icount - 1);
2357 case ICMD_IF_LCMPEQ:
2358 case ICMD_IF_LCMPLT:
2359 case ICMD_IF_LCMPLE:
2360 case ICMD_IF_LCMPNE:
2361 case ICMD_IF_LCMPGT:
2362 case ICMD_IF_LCMPGE:
2372 case ICMD_IFNONNULL:
2374 case ICMD_IF_ICMPEQ:
2375 case ICMD_IF_ICMPNE:
2376 case ICMD_IF_ICMPLT:
2377 case ICMD_IF_ICMPGE:
2378 case ICMD_IF_ICMPGT:
2379 case ICMD_IF_ICMPLE:
2380 case ICMD_IF_ACMPEQ:
2381 case ICMD_IF_ACMPNE:
2382 copy_handler(m, ld, lc, bptr->next, original_head, new_head);
2387 /* redirect jump from original_head to new_head */
2388 if ((basicblock *) ip->target == original_head)
2389 ip->target = (void *) new_head;
2391 copy_handler(m, ld, lc, (basicblock *) (ip->target), original_head, new_head);
2395 case ICMD_TABLESWITCH:
2397 tptr = (void **) ip->target;
2399 /* default branch */
2400 if (((basicblock *) *tptr) == original_head)
2401 tptr[0] = (void *) new_head;
2403 copy_handler(m, ld, lc, (basicblock *) *tptr, original_head, new_head);
2410 count = (high-low+1);
2412 while (--count >= 0) {
2414 /* redirect jump from original_head to new_head */
2415 if (((basicblock *) *tptr) == original_head)
2416 tptr[0] = (void *) new_head;
2417 copy_handler(m, ld, lc, (basicblock *) *tptr, original_head, new_head);
2421 case ICMD_LOOKUPSWITCH:
2423 tptr = (void **) ip->target;
2425 /* default branch */
2426 if (((basicblock *) *tptr) == original_head)
2427 tptr[0] = (void *) new_head;
2429 copy_handler(m, ld, lc, (basicblock *) *tptr, original_head, new_head);
2434 while (--count >= 0) {
2436 /* redirect jump from original_head to new_head */
2437 if (((basicblock *) *tptr) == original_head)
2438 tptr[0] = (void *) new_head;
2439 copy_handler(m, ld, lc, (basicblock *) *tptr, original_head, new_head);
2444 ld->c_last_target = bptr;
2445 copy_handler(m, ld, lc, (basicblock *) (ip->target), original_head, new_head);
2449 copy_handler(m, ld, lc, ld->c_last_target->next, original_head, new_head);
2453 copy_handler(m, ld, lc, bptr->next, original_head, new_head);
2459 /* If a loop is duplicated, all exceptions, that are contained in this loops' body
2460 have to be duplicated as well. The following function together with the
2461 two helper functions copy_handler and patch_handler perform this task.
2464 void update_internal_exceptions(methodinfo *m, codegendata *cd, loopdata *ld, struct LoopContainer *lc, basicblock *original_head, basicblock *new_head)
2466 exceptiontable *ex, *new;
2467 struct LoopContainer *l;
2469 /* Bottom of tree reached -> return */
2473 /* Call update_internal for all nested (=child) loops */
2476 update_internal_exceptions(m, cd, ld, l, original_head, new_head);
2480 /* For all exceptions of this loop, do */
2481 ex = lc->exceptions;
2482 while (ex != NULL) {
2484 /* Copy the exception and patch the jumps */
2485 copy_handler(m, ld, lc, ex->handler, original_head, new_head);
2486 patch_handler(lc, ex->handler, original_head, new_head);
2488 /* Insert a new exception into the global exception table */
2489 new = DNEW(exceptiontable);
2490 memcpy(new, ex, sizeof(exceptiontable));
2492 /* Increase number of exceptions */
2493 ++cd->exceptiontablelength;
2498 /* Set new start and end point of this exception */
2499 new->start = ex->start->copied_to;
2500 new->end = ex->end->copied_to;
2502 /* Set handler pointer to copied exception handler */
2503 new->handler = ex->handler->copied_to;
2511 /* If a loop is duplicated, all exceptions that contain this loop have to be
2512 extended to the copied nodes as well. The following function checks for
2513 all exceptions of all parent loops, whether they contain the loop pointed to
2514 by lc. If so, the exceptions are extended to contain all newly created nodes.
2517 void update_external_exceptions(methodinfo *m, codegendata *cd, loopdata *ld, struct LoopContainer *lc, int loop_head)
2519 exceptiontable *ex, *new;
2521 /* Top of tree reached -> return */
2525 ex = lc->exceptions;
2527 /* For all exceptions of this loop do */
2528 while (ex != NULL) {
2530 /* It is possible that the loop contains exceptions that do not protect */
2531 /* the loop just duplicated. It must be checked, if this is the case */
2532 if ((loop_head >= m->basicblockindex[ex->startpc]) && (loop_head < m->basicblockindex[ex->endpc])) {
2534 /* loop is really inside exception, so create new exception entry */
2535 /* in global exception list */
2536 new = DNEW(exceptiontable);
2537 memcpy(new, ex, sizeof(exceptiontable));
2540 /* Increase number of exceptions */
2541 ++cd->exceptiontablelength;
2546 /* Set new start and end point of this exception */
2547 new->start = ld->c_first_block_copied;
2548 new->end = ld->c_last_block_copied;
2552 /* exception does not contain the duplicated loop -> do nothing */
2557 /* Call update_external for parent node */
2558 update_external_exceptions(m, cd, ld, lc->parent, loop_head);
2562 /* This function is needed to insert the static checks, stored in c_constraints
2563 into the intermediate code.
2566 void create_static_checks(methodinfo *m, codegendata *cd, loopdata *ld, struct LoopContainer *lc)
2568 int i, stackdepth, cnt;
2569 struct Constraint *tc1;
2570 struct LoopElement *le;
2572 /* loop_head points to the newly inserted loop_head, original_start to */
2573 /* the old loop header */
2574 basicblock *bptr, *loop_head, *original_start, *temp;
2575 instruction *inst, *tiptr;
2577 /* tos and newstack are needed by the macros, that insert instructions into */
2578 /* the new loop head */
2579 stackptr newstack, tos;
2583 /* show_loop_statistics(l); */
2586 loop_head = &m->basicblocks[ld->c_current_head];
2587 ld->c_first_block_copied = ld->c_last_block_copied = NULL;
2589 /* the loop nodes are copied */
2593 bptr = DMNEW(basicblock, 1);
2594 memcpy(bptr, le->block, sizeof(basicblock));
2595 bptr->debug_nr = m->c_debug_nr++;
2597 /* determine beginning of copied loop to extend exception handler, that */
2598 /* protect this loop */
2599 if (ld->c_first_block_copied == NULL)
2600 ld->c_first_block_copied = bptr;
2602 /* copy instructions and add one more slot for possible GOTO */
2603 bptr->iinstr = DMNEW(instruction, bptr->icount + 1);
2605 memcpy(bptr->iinstr, le->block->iinstr, (bptr->icount+1)*sizeof(instruction));
2607 le->block->copied_to = bptr;
2609 /* add block to global list of BBs */
2610 temp = m->basicblocks;
2618 node_into_parent_loops(ld, lc->parent, bptr);
2622 ld->c_last_block_copied = bptr;
2624 /* create an additional basicblock for dynamic checks */
2625 original_start = bptr = DMNEW(basicblock, 1);
2627 /* copy current loop header to new basic block */
2628 memcpy(bptr, loop_head, sizeof(basicblock));
2629 bptr->debug_nr = m->c_debug_nr++;
2631 /* insert the new basic block and move header before first loop node */
2635 /* if header is first node of loop, insert original header after it */
2636 if (temp == loop_head)
2637 loop_head->next = bptr;
2639 /* else, we have to find the predecessor of loop header */
2640 while (temp->next != loop_head)
2643 /* insert original header after newly created block */
2646 /* if predecessor is not loop part, insert a goto */
2647 if (!(temp->lflags & LOOP_PART)) {
2649 /* copy instructions and add an additional slot */
2650 tiptr = DMNEW(instruction, temp->icount + 1);
2651 memcpy(tiptr, temp->iinstr, sizeof(instruction)*temp->icount);
2653 temp->iinstr = tiptr;
2654 tiptr = temp->iinstr + temp->icount;
2656 /* add goto to loop header. If node is part of exception handler */
2657 /* jmp is automagically redirected during patch_handler and works */
2659 tiptr->opc = ICMD_GOTO;
2661 tiptr->target = (void*) loop_head;
2667 temp = m->basicblocks;
2668 /* if first loop block is first BB of global list, insert loop_head at */
2669 /* beginning of global BB list */
2670 if (temp == le->block) {
2671 if (ld->c_newstart == NULL) {
2672 ld->c_needs_redirection = true;
2673 ld->c_newstart = loop_head;
2674 loop_head->next = m->basicblocks;
2677 loop_head->next = ld->c_newstart;
2678 ld->c_newstart = loop_head;
2683 while (temp->next != le->block)
2686 loop_head->next = temp->next;
2687 temp->next = loop_head;
2689 /* to be on the safe side insert a jump from the previous instr */
2690 /* over thr new inserted node */
2692 /* special case - jump from node to loop_head: then remove */
2693 /* goto / happens rather often due to loop layout */
2694 tiptr = temp->iinstr + (temp->icount-1);
2696 if ((tiptr->opc == ICMD_GOTO) && (tiptr->target == loop_head)) {
2697 tiptr->opc = ICMD_NOP;
2702 tiptr = DMNEW(instruction, temp->icount + 1);
2703 memcpy(tiptr, temp->iinstr, sizeof(instruction)*temp->icount);
2705 temp->iinstr = tiptr;
2706 tiptr = temp->iinstr + temp->icount;
2708 tiptr->opc = ICMD_GOTO;
2710 tiptr->target = (void*) loop_head->next;
2717 /* adjust exceptions */
2718 ex = cd->exceptiontable;
2719 while (ex != NULL) {
2721 /* if an exception covers whole loop and starts at first loop node, it */
2722 /* has to be extended to cover the new first node as well */
2723 if (ex->start == le->block) {
2725 if ((lc->loop_head >= m->basicblockindex[ex->startpc]) && (lc->loop_head < m->basicblockindex[ex->endpc]))
2726 ex->start = loop_head;
2729 /* an exception that ended at the old loop header now must contains the */
2730 /* new loop header as well */
2731 if (ex->end == loop_head)
2732 ex->end = original_start;
2738 /* insert new header node into nodelists of all enclosing loops */
2739 header_into_parent_loops(ld, lc, loop_head, original_start, le->block);
2741 /* prepare instruction array to insert checks */
2742 inst = loop_head->iinstr = DMNEW(instruction, ld->c_needed_instr + 2);
2743 loop_head->icount = ld->c_needed_instr + 1;
2745 /* init instruction array */
2746 for (cnt=0; cnt<ld->c_needed_instr + 1; ++cnt) {
2747 inst[0].opc = ICMD_NOP;
2751 loop_head->copied_to = NULL;
2754 loop_head->instack = copy_stack_from(bptr->instack);
2755 loop_head->outstack = copy_stack_from(bptr->instack);
2757 tos = loop_head->instack;
2758 stackdepth = loop_head->indepth;
2760 /* step through all inserted checks and create instructions for them */
2761 for (i=0; i<cd->maxlocals+1; ++i)
2763 tc1 = ld->c_constraints[i];
2769 /* check a variable against a constant */
2771 case TEST_UNMOD_ZERO:
2774 printf("insert ZERO-test\n");
2778 /* optimize if tc1->varRef >= tc1->constant */
2779 LOAD_VAR(tc1->varRef);
2780 LOAD_CONST(tc1->constant);
2784 /* check a variable against an array length */
2786 case TEST_UNMOD_ALENGTH:
2789 /* tc1->varRef + tc1->constant < lengthOf(tc1->arrayRef) */
2791 printf("insert ALENGTH-test\n");
2795 LOAD_VAR(tc1->varRef);
2796 LOAD_CONST(tc1->constant);
2798 LOAD_ARRAYLENGTH(tc1->arrayRef);
2802 /* test right side of comparison against constant */
2806 printf("insert RS-ZERO-test\n");
2810 /* optimize if right-side >= tc1->constant */
2812 LOAD_CONST(tc1->constant);
2816 /* test right side of comparison against array length */
2817 case TEST_RS_ALENGTH:
2820 printf("insert RS-ALENGTH-test\n");
2823 /* optimize if right-side < lengthOf(arrayRef) */
2825 LOAD_ARRAYLENGTH(tc1->arrayRef);
2829 /* test unmodified variable against arraylength */
2830 case TEST_CONST_ALENGTH:
2833 printf("insert CONST ALENGTH-test\n");
2837 /* optimize if tc1->constant < lengthOf(tc1->arrayRef) */
2838 LOAD_CONST(tc1->constant);
2839 LOAD_ARRAYLENGTH(tc1->arrayRef);
2846 ld->c_constraints[i] = NULL;
2849 /* if all tests succeed, jump to optimized loop header */
2850 if (loop_head->next != original_start) {
2851 inst->opc = ICMD_GOTO;
2853 inst->target = original_start;
2856 /* redirect jumps from original loop head to newly inserted one */
2857 patch_jumps(original_start, loop_head, lc);
2859 /* if exceptions have to be correct due to loop duplication these two */
2860 /* functions perform this task. */
2861 update_internal_exceptions(m, cd, ld, lc, loop_head, original_start);
2862 update_external_exceptions(m, cd, ld, lc->parent, lc->loop_head);
2866 /* This function performs an update between two arrays of struct Changes (that
2867 reflect variable changes). The merge is performed unrstricted in the way, that
2868 all variable changes in c1 took place in a nested loop and therefore are
2869 considered to be without limit. Beside that, the merge is a simple union of the
2870 changes recorded in both arrays. A variable, which limits are undefinied, is
2871 represented by its lower bound being higher than the upper bound. The result
2872 of the union is stored in c1.
2874 struct Changes ** constraints_unrestricted_merge(codegendata *cd, struct Changes **c1, struct Changes **c2)
2878 if ((c1 == NULL) || (c2 == NULL))
2879 printf("C_ERROR: debugging error 0x03\n");
2882 for (i=0; i<cd->maxlocals; ++i) {
2883 if (c1[i] == NULL) {
2884 if (c2[i] != NULL) { /* a change in c2 is updated in c1 */
2887 c1[i]->lower_bound = c1[i]->upper_bound+1;
2891 if (c1[i]->lower_bound > c1[i]->upper_bound)
2892 continue; /* variable's bounds already undefined */
2894 if (c2[i] == NULL) { /* variable changed in c1 -> now undef. */
2896 c1[i]->lower_bound = c1[i]->upper_bound+1;
2899 if ((c1[i]->lower_bound == c2[i]->lower_bound) &&
2900 (c1[i]->upper_bound == c2[i]->upper_bound))
2901 continue; /* variable's bounds remain the same */
2904 c1[i]->lower_bound = c1[i]->upper_bound+1;
2905 } /* variable changed in c1 -> now undef. */
2916 /* This function performs an update between two arrays of struct Changes (that
2917 reflect variable changes). The merge is a simple union of the bounds
2918 changes recorded in both arrays. A variable, which limits are undefinied, is
2919 represented by its lower bound being higher than the upper bound. The result
2920 of the union is stored in c1.
2922 struct Changes ** constraints_merge(codegendata *cd, struct Changes **c1, struct Changes **c2)
2926 if ((c1 == NULL) || (c2 == NULL))
2927 printf("C_ERROR: debugging error 0x04\n");
2931 for (i=0; i<cd->maxlocals; ++i) {
2932 if (c1[i] == NULL) {
2933 if (c2[i] != NULL) { /* update changes in c2 in c1 */
2934 if ((c1[i] = (struct Changes *) malloc (sizeof(struct Changes))) == NULL)
2937 c1[i]->lower_bound = c2[i]->lower_bound;
2938 c1[i]->upper_bound = c2[i]->upper_bound;
2943 if (c2[i] != NULL) {
2945 if (c1[i]->lower_bound > c1[i]->upper_bound)
2946 continue; /* var in c1 is unrestricted */
2948 if (c1[i]->lower_bound > c2[i]->lower_bound) {
2949 c1[i]->lower_bound = c2[i]->lower_bound;
2950 changed = 1; /* write new lower bound */
2952 if (c1[i]->upper_bound < c2[i]->upper_bound) {
2953 c1[i]->upper_bound = c2[i]->upper_bound;
2954 changed = 1; /* write new higher bound */
2967 /* This function simply copies an array of changes
2969 struct Changes** constraints_clone(codegendata *cd, struct Changes **c)
2974 if ((t = (struct Changes **) malloc(cd->maxlocals * sizeof(struct Changes *))) == NULL)
2977 for (i=0; i<cd->maxlocals; ++i) { /* for all array elements (vars) do */
2981 if ((t[i] = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
2983 t[i]->lower_bound = c[i]->lower_bound;
2984 t[i]->upper_bound = c[i]->upper_bound;
2991 /* This function is used to reset the changes of a variable to the time, it was
2992 pushed onto the stack. If a variable has been modified between an instruction
2993 and a previous push onto the stack, its value in the changes array does not
2994 correctly reflect its bounds the time, it was pushed onto the stack. This
2995 function corrects the situation.
2997 struct Changes* backtrack_var(methodinfo *m, int node, int from, int to, int varRef, struct Changes *changes)
2999 struct Changes *tmp;
3004 if (changes == NULL) /* if there are no changes, immediately return */
3006 else { /* init a Changes structure with current values */
3007 if ((tmp = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
3010 tmp->upper_bound = changes->upper_bound;
3011 tmp->lower_bound = changes->lower_bound;
3014 if (tmp->upper_bound < tmp->lower_bound)
3015 return tmp; /* if it is unrestricted no backtracking can happen */
3017 bp = m->basicblocks[node];
3018 ip = bp.iinstr + to;
3020 for (; from < to; --to, --ip) { /* scan instructions backwards */
3022 case ICMD_IINC: /* a var has been modified */
3023 if (varRef != ip->op1) /* not the one, we are interested in */
3025 tmp->upper_bound -= ip->val.i; /* take back modifications */
3026 tmp->lower_bound -= ip->val.i;
3029 case ICMD_ISTORE: /* a var has been modified */
3030 if (varRef != ip->op1) /* not the one, we are interested in */
3033 /* it is our variable, so trace its origin */
3034 t = tracing(&m->basicblocks[node],to, 0);
3038 if ((t->var = ip->op1) && (t->neg > 0)) {
3039 /* it was the same var -> take back modifications */
3040 tmp->upper_bound -= t->constant;
3041 tmp->lower_bound -= t->constant;
3044 tmp->lower_bound = tmp->upper_bound+1; /* unknown */
3047 /* cannot restore it -> invalidate t */
3052 tmp->lower_bound = tmp->upper_bound+1;
3063 /* This function performs the main task of bound check removal. It removes
3064 all bound-checks in node. change is a pointer to an array of struct Changes
3065 that reflect for all local variables, how their values have changed from
3066 the start of the loop. The special flag is needed to deal with the header
3070 void remove_boundchecks(methodinfo *m, codegendata *cd, loopdata *ld, int node, int from, struct Changes **change, int special)
3074 int i, count, ignore, degrade_checks, opt_level;
3075 struct depthElement *d;
3076 struct Changes **t1, **tmp, *t;
3077 struct Trace *t_array, *t_index;
3079 /* printf("remove_bc called: %d - %d - %d\n", node, from, special); */
3081 /* a flag, that is set, when previous optimzations have to be taken back */
3084 if (ld->c_current_loop[node] > 0) { /* this node is part of the loop */
3085 if (ld->c_current_loop[node] > 1) { /* it is not the header node */
3087 /* get variable changes, already recorded for this node */
3088 t1 = ld->c_dTable[node]->changes;
3090 if (t1 != NULL) { /* it is not the first visit */
3091 if ((ld->c_nestedLoops[node] != ld->c_current_head) && (ld->c_nestedLoops[node] == ld->c_nestedLoops[from])) {
3092 /* we are looping in a nested loop, so made optimizations */
3093 /* need to be reconsidered */
3095 if (constraints_unrestricted_merge(cd, t1, change) == NULL)
3096 return; /* no changes since previous visit */
3097 /* if there have been changes, they are updated by */
3098 /* constraints_unrestricted_merge in t1 */
3101 if (constraints_merge(cd, t1, change) == NULL)
3102 return; /* no changes since previous visit */
3103 /* if there have been changes, they are updated by */
3104 /* constraints_merge in t1 */
3107 else { /* first visit */
3108 /* printf("first visit - constraints cloned\n"); */
3109 ld->c_dTable[node]->changes = constraints_clone(cd, change);
3112 /* tmp now holds a copy of the updated variable changes */
3113 tmp = constraints_clone(cd, ld->c_dTable[node]->changes);
3115 else if (special) { /* header and need special traetment */
3116 /* printf("special treatment called\n"); */
3117 /* tmp now holds a copy of the current new variable changes */
3118 tmp = constraints_clone(cd, change);
3123 bp = m->basicblocks[node]; /* scan all instructions */
3128 for (i=0; i<count; ++i, ++ip) {
3130 case ICMD_IASTORE: /* found an array store */
3139 t_index = tracing(&bp, i-1, 1); /* get index */
3140 t_array = tracing(&bp, i-1, 2); /* get array refernce */
3144 case ICMD_IALOAD: /* found an array load */
3153 t_index = tracing(&bp, i-1, 0); /* get index */
3154 t_array = tracing(&bp, i-1, 1); /* get array refernce */
3158 /* printf("Array access with params:\n");
3160 show_trace(t_array);
3162 show_trace(t_index);
3166 if (ip->op1 == OPT_UNCHECKED) { /* found new access */
3167 ld->c_stat_array_accesses++;
3169 ld->c_stat_no_opt++;
3173 /* can only optimize known arrays that do not change */
3174 if ((t_array->type != TRACE_AVAR) || (ld->c_var_modified[t_array->var]))
3177 switch (t_index->type) { /* now we look at the index */
3178 case TRACE_ICONST: /* it is a constant value or an */
3179 case TRACE_ALENGTH: /* array length */
3181 switch (ip->op1) { /* take back old optimzation */
3185 ld->c_stat_no_opt--;
3188 ld->c_stat_full_opt--;
3191 ld->c_stat_upper_opt--;
3194 ld->c_stat_lower_opt--;
3198 if (degrade_checks) /* replace existing optimization */
3199 ip->op1 = insert_static(m, cd, ld, t_array->var, t_index, NULL, special);
3201 /* Check current optimization and try to improve it by */
3202 /* inserting new checks */
3205 ip->op1 = insert_static(m, cd, ld, t_array->var, t_index, NULL, special);
3208 ip->op1 = insert_static(m, cd, ld, t_array->var, t_index, NULL, special);
3211 opt_level = insert_static(m, cd, ld, t_array->var, t_index, NULL, special);
3212 if ((opt_level == OPT_FULL) || (opt_level == OPT_LOWER))
3216 opt_level = insert_static(m, cd, ld, t_array->var, t_index, NULL, special);
3217 if ((opt_level == OPT_FULL) || (opt_level == OPT_UPPER))
3222 ld->c_stat_full_opt++;
3229 case TRACE_IVAR: /* it's a variable */
3231 /* if the variable is changed between its usage as an index */
3232 /* of the array access and its push onto the stack, we have */
3233 /* to set the changes back to the time, it is pushed onto */
3234 /* the stack as an index variable. */
3235 t = backtrack_var(m, node, t_index->nr, i-1, t_index->var, tmp[t_index->var]);
3237 switch (ip->op1) { /* take back old optimzation */
3241 ld->c_stat_no_opt--;
3244 ld->c_stat_full_opt--;
3247 ld->c_stat_upper_opt--;
3250 ld->c_stat_lower_opt--;
3255 ip->op1 = insert_static(m, cd, ld, t_array->var, t_index, t, special);
3257 /* Check current optimization and try to improve it by */
3258 /* insert new check. t reflects var changes for index */
3261 ip->op1 = insert_static(m, cd, ld, t_array->var, t_index, t, special);
3264 ip->op1 = insert_static(m, cd, ld, t_array->var, t_index, t, special);
3267 opt_level = insert_static(m, cd, ld, t_array->var, t_index, t, special);
3268 if ((opt_level == OPT_FULL) || (opt_level == OPT_LOWER))
3272 opt_level = insert_static(m, cd, ld, t_array->var, t_index, t, special);
3273 if ((opt_level == OPT_FULL) || (opt_level == OPT_UPPER))
3278 ld->c_stat_full_opt++;
3291 case ICMD_ISTORE: /* an integer value is stored */
3292 t_index = tracing(&bp, i-1, 0); /* trace back its origin */
3294 /* the struct Changes for this variable needs to be updated */
3296 if (t == NULL) { /* if it's the first one, create new entry */
3297 if ((t = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
3299 t->upper_bound = t->lower_bound = 0;
3303 switch (t_index->type) { /* check origin of store */
3305 case TRACE_ICONST: /* constant -> set bounds to const value */
3306 t->upper_bound = t->lower_bound = t_index->constant;
3309 case TRACE_IVAR: /* if it's the same variable, update consts */
3310 if ((t_index->var = ip->op1) && (t_index->neg > 0)) {
3311 t->upper_bound += t_index->constant;
3312 t->lower_bound += t_index->constant;
3315 t->lower_bound = t->upper_bound+1;
3318 case TRACE_ALENGTH: /* else -> unknown */
3321 t->lower_bound = t->upper_bound+1;
3329 /* the struct Changes for this variable needs to be updated */
3330 if ((t = tmp[ip->op1]) == NULL) { /* first one -> create new */
3331 if ((t = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
3333 t->upper_bound = t->lower_bound = ip->val.i;
3336 else { /* update changes, made by iinc */
3337 t->upper_bound += ip->val.i;
3338 t->lower_bound += ip->val.i;
3344 if (!special) { /* we are not interested in only the header */
3345 d = ld->c_dTable[node];
3346 while (d != NULL) { /* check all sucessors of current node */
3347 remove_boundchecks(m, cd, ld, d->value, node, tmp, special);
3355 /* This function calls the bound-check removal function for the header node
3356 with a special flag. It is important to notice, that no dynamic
3357 constraint hold in the header node (because the comparison is done at
3361 void remove_header_boundchecks(methodinfo *m, codegendata *cd, loopdata *ld, int node, struct Changes **changes)
3363 remove_boundchecks(m, cd, ld, node, -1, changes, BOUNDCHECK_SPECIAL);
3367 /* Marks all basicblocks that are part of the loop
3370 void mark_loop_nodes(struct LoopContainer *lc)
3372 struct LoopElement *le = lc->nodes;
3374 while (le != NULL) {
3375 le->block->lflags |= LOOP_PART;
3381 /* Clears mark for all basicblocks that are part of the loop
3383 void unmark_loop_nodes(LoopContainer *lc)
3385 LoopElement *le = lc->nodes;
3387 while (le != NULL) {
3388 le->block->lflags = 0;
3394 /* This function performs the analysis of code in detected loops and trys to
3395 identify array accesses suitable for optimization (bound check removal). The
3396 intermediate code is then modified to reflect these optimizations.
3398 void optimize_single_loop(methodinfo *m, codegendata *cd, loopdata *ld, LoopContainer *lc)
3400 struct LoopElement *le;
3401 struct depthElement *d;
3403 struct Changes **changes;
3405 if ((changes = (struct Changes **) malloc(cd->maxlocals * sizeof(struct Changes *))) == NULL)
3408 head = ld->c_current_head = lc->loop_head;
3409 ld->c_needed_instr = ld->c_rs_needed_instr = 0;
3411 /* init array for null ptr checks */
3412 for (i=0; i<cd->maxlocals; ++i)
3413 ld->c_null_check[i] = 0;
3416 /* don't optimize root node (it is the main procedure, not a loop) */
3420 /* setup variables with initial values */
3421 ld->c_loopvars = NULL;
3422 for (i=0; i < m->basicblockcount; ++i) {
3423 ld->c_toVisit[i] = 0;
3424 ld->c_current_loop[i] = -1;
3425 if ((d = ld->c_dTable[i]) != NULL)
3429 for (i=0; i < cd->maxlocals; ++i) {
3430 ld->c_var_modified[i] = 0;
3431 if (changes[i] != NULL) {
3436 for (i=0; i < (cd->maxlocals+1); ++i) {
3437 if (ld->c_constraints[i] != NULL) {
3438 ld->c_constraints[i] = NULL;
3443 while (le != NULL) {
3447 ld->c_current_loop[node] = 1; /* the header node gets 1 */
3448 else if (ld->c_nestedLoops[node] == head)
3449 ld->c_current_loop[node] = 2; /* top level nodes get 2 */
3451 ld->c_current_loop[node] = 3; /* nodes, part of nested loop get 3 */
3453 ld->c_toVisit[node] = 1;
3457 /* After setup work has been performed, start to analyse */
3459 printf("****** Starting analysis (%d)******\n", head);
3463 if (analyze_for_array_access(m, ld, head) > 0) {/* loop contains array access */
3468 printf("analyze for array access finished and found\n");
3470 lv = ld->c_loopvars;
3471 while (lv != NULL) {
3473 printf("Var --> %d\n", lv->value);
3478 /* for performance reasons the list of all interesting loop vars is */
3479 /* scaned and for all modified vars a flag in c_var_modified is set */
3480 scan_global_list(ld);
3483 printf("global list scanned\n");
3487 /* if the loop header contains or-conditions or an index variable */
3488 /* is modified in the catch-block within the loop, a conservative */
3489 /* approach is taken and optimizations are cancelled */
3490 if (analyze_or_exceptions(m, cd, ld, head, lc) > 0) {
3493 printf("Analyzed for or/exception - no problems \n");
3497 init_constraints(m, ld, head); /* analyze dynamic bounds in header */
3503 if (ld->c_rightside == NULL)
3506 /* single pass bound check removal - for all successors, do */
3507 remove_header_boundchecks(m, cd, ld, head, changes);
3509 d = ld->c_dTable[head];
3511 remove_boundchecks(m, cd, ld, d->value, -1, changes, BOUNDCHECK_REGULAR);
3516 printf("Array-bound checks finished\n");
3520 mark_loop_nodes(lc);
3523 printf("START: create static checks\n");
3527 create_static_checks(m, cd, ld, lc); /* create checks */
3530 printf("END: create static checks\n");
3533 unmark_loop_nodes(lc);
3537 printf("No array accesses found\n"); */
3540 ld->c_stat_num_loops++; /* increase number of loops */
3542 ld->c_stat_sum_accesses += ld->c_stat_array_accesses;
3543 ld->c_stat_sum_full += ld->c_stat_full_opt;
3544 ld->c_stat_sum_no += ld->c_stat_no_opt;
3545 ld->c_stat_sum_lower += ld->c_stat_lower_opt;
3546 ld->c_stat_sum_upper += ld->c_stat_upper_opt;
3547 ld->c_stat_sum_or += ld->c_stat_or;
3548 ld->c_stat_sum_exception += ld->c_stat_exception;
3550 ld->c_stat_array_accesses = 0;
3551 ld->c_stat_full_opt = 0;
3552 ld->c_stat_no_opt = 0;
3553 ld->c_stat_lower_opt = 0;
3554 ld->c_stat_upper_opt = 0;
3555 ld->c_stat_or = ld->c_stat_exception = 0;
3561 /* This function preforms necessary setup work, before the recursive function
3562 optimize_single loop can be called.
3564 void optimize_loops(methodinfo *m, codegendata *cd, loopdata *ld)
3566 LoopContainer *lc = ld->c_allLoops;
3568 /* first, merge loops with same header node - all loops with the same */
3569 /* header node are optimizied in one pass, because they all depend on the */
3570 /* same dynamic loop condition */
3573 printf("start analyze_double_headers\n");
3577 analyze_double_headers(ld);
3579 /* create array with loop nesting levels - nested loops cause problems, */
3580 /* especially, when they modify index variables used in surrounding loops */
3581 /* store results in array c_nestedLoops and c_hierarchie */
3584 printf("double done\n");
3588 analyze_nested(m,cd, ld);
3591 printf("analyze nested done\n");
3595 /* create array with entries for current loop */
3596 ld->c_current_loop = DMNEW(int, m->basicblockcount);
3597 ld->c_toVisit = DMNEW(int, m->basicblockcount);
3598 ld->c_var_modified = DMNEW(int, cd->maxlocals);
3599 ld->c_null_check = DMNEW(int, cd->maxlocals);
3601 if ((ld->c_constraints = (struct Constraint **) malloc((cd->maxlocals+1) * sizeof(struct Constraint *))) == NULL)
3605 ld->c_stat_num_loops = 0; /* set statistic vars to zero */
3606 ld->c_stat_array_accesses = ld->c_stat_sum_accesses = 0;
3607 ld->c_stat_full_opt = ld->c_stat_sum_full = 0;
3608 ld->c_stat_no_opt = ld->c_stat_sum_no = 0;
3609 ld->c_stat_lower_opt = ld->c_stat_sum_lower = 0;
3610 ld->c_stat_upper_opt = ld->c_stat_sum_upper = 0;
3611 ld->c_stat_or = ld->c_stat_sum_or = 0;
3612 ld->c_stat_exception = ld->c_stat_sum_exception = 0;
3615 /* init vars needed by all loops */
3616 ld->c_needs_redirection = false;
3617 ld->c_newstart = NULL;
3618 ld->c_old_xtablelength = cd->exceptiontablelength;
3620 /* loops have been topologically sorted */
3621 lc = ld->c_allLoops;
3622 while (lc != NULL) {
3623 optimize_single_loop(m, cd, ld, lc);
3626 printf(" *** Optimized loop *** \n");
3633 printf("---*** All loops finished ***---\n");
3637 /* if global BB list start is modified, set block to new start */
3638 if (ld->c_needs_redirection == true)
3639 m->basicblocks = ld->c_newstart;
3645 * These are local overrides for various environment variables in Emacs.
3646 * Please do not remove this and leave it at the end of the file, where
3647 * Emacs will automagically detect them.
3648 * ---------------------------------------------------------------------
3651 * indent-tabs-mode: t