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
37 $Id: analyze.c 4357 2006-01-22 23:33:38Z twisti $
51 #include "mm/memory.h"
52 #include "toolbox/logging.h"
53 #include "vm/jit/jit.h"
54 #include "vm/jit/loop/analyze.h"
55 #include "vm/jit/loop/graph.h"
56 #include "vm/jit/loop/loop.h"
57 #include "vm/jit/loop/tracing.h"
62 /* Test functions -> will be removed in final release
65 void show_trace(struct Trace *trace)
68 switch (trace->type) {
71 printf("\nNr.:\t%d", trace->var);
72 printf("\nValue:\t%d", trace->constant);
77 printf("\nNr.:\t%d", trace->var);
81 printf("array-length");
82 printf("\nNr.:\t%d", trace->var);
83 printf("\nValue:\t%d", trace->constant);
88 printf("\nValue:\t%d", trace->constant);
97 printf("Trace is null");
103 void show_change(struct Changes *c)
105 printf("*** Changes ***\n");
107 printf("Lower/Upper Bound:\t%d/%d\n", c->lower_bound, c->upper_bound);
109 printf("Unrestricted\n");
112 show_varinfo(struct LoopVar *lv)
114 printf(" *** Loop Info ***\n");
115 printf("Value:\t%d\n", lv->value);
116 printf("Static:\t\t%d/%d\n", lv->static_l, lv->static_u);
117 printf("D-Valid:\t%d/%d\n", lv->dynamic_l_v, lv->dynamic_u_v);
118 printf("Dynamic\t\t%d/%d\n", lv->dynamic_l, lv->dynamic_u);
121 void show_right_side(methodinfo *m)
124 printf("\n *** Head *** \nType:\t");
125 show_trace(m->loopdata->c_rightside);
127 printf("\n *** Nested Loops: ***\n");
128 for (i=0; i<m->basicblockcount; ++i)
129 printf("%d\t", m->loopdata->c_nestedLoops[i]);
132 printf("\n *** Hierarchie: ***\n");
133 for (i=0; i<m->basicblockcount; ++i)
134 printf("%d\t", m->loopdata->c_hierarchie[i]);
138 printf("\n *** Current Loop ***\n");
139 for (i=0; i<m->basicblockcount; ++i)
140 printf("%d\t", m->loopdata->c_current_loop[i]);
144 void resultPass3(methodinfo *m)
147 struct LoopContainer *lc = m->loopdata->c_allLoops;
149 printf("\n\n****** PASS 3 ******\n\n");
152 printf("Loop Analysis:\n");
153 printf("Optimize:\t%d\n", lc->toOpt);
154 printf("Modified Vars: ");
156 for (i=0; i<lc->num_vars; ++i)
157 printf("%d ", lc->vars[i]);
163 printf("\nNested Loops:\n");
164 for (i=0; i<m->basicblockcount; ++i)
165 printf("%d ", m->loopdata->c_nestedLoops[i]);
167 for (i=0; i<m->basicblockcount; ++i)
168 printf("%d ", m->loopdata->c_hierarchie[i]);
173 void show_tree(struct LoopContainer *lc, int tabs)
178 for (cnt = 0; cnt < tabs; ++cnt)
180 printf("%d\n", lc->loop_head);
182 show_tree(lc->tree_down, tabs+1);
190 #ifdef ENABLE_STATISTICS
192 void show_loop_statistics(loopdata *ld)
194 printf("\n\n****** LOOP STATISTICS ****** \n\n");
196 printf("Optimization cancelled by or\n");
197 else if (ld->c_stat_exception)
198 printf("Optimization cancelled by exception\n");
200 printf("Number of array accesses:\t%d\n", ld->c_stat_array_accesses);
201 if (ld->c_stat_array_accesses) {
202 printf("\nFully optimized:\t%d\n", ld->c_stat_full_opt);
203 printf("Not optimized:\t\t%d\n", ld->c_stat_no_opt);
204 printf("Upper optimized:\t%d\n", ld->c_stat_upper_opt);
205 printf("Lower optimized:\t%d\n", ld->c_stat_lower_opt);
210 void show_procedure_statistics(loopdata *ld)
212 printf("\n\n****** PROCEDURE STATISTICS ****** \n\n");
213 printf("Number of loops:\t\t%d\n", ld->c_stat_num_loops);
214 printf("Number of array accesses:\t%d\n", ld->c_stat_sum_accesses);
215 if (ld->c_stat_sum_accesses) {
216 printf("\nFully optimized:\t%d\n", ld->c_stat_sum_full);
217 printf("Not optimized:\t\t%d\n", ld->c_stat_sum_no);
218 printf("Upper optimized:\t%d\n", ld->c_stat_sum_upper);
219 printf("Lower optimized:\t%d\n", ld->c_stat_sum_lower);
221 printf("Opt. cancelled by or:\t\t%d\n", ld->c_stat_sum_or);
222 printf("Opt. cancelled by exception:\t%d\n", ld->c_stat_sum_exception);
228 /* This function is used to merge two loops with the same header together.
229 A simple merge sort of the lists nodes of both loops is performed.
231 void analyze_merge(struct LoopContainer *l1, struct LoopContainer *l2)
233 struct LoopElement *start, *last, *le1, *le2;
234 /* start and last are pointers to the newly built list, le1 and le2 step */
235 /* step through the lists, that have to be merged. */
240 /* start a simple merge sort of the nodes of both loops. These lists are */
241 /* already sorted, so merging is easy. */
242 if (le1->node < le2->node) {
246 else if (le1->node == le2->node) {
256 /* while the first loop != NULL, depending of the first element of second */
257 /* loop, add new node to result list */
258 while (le1 != NULL) {
264 if (le1->node < le2->node) {
268 else if (le1->node == le2->node) {
285 /* This function is used to merge loops with the same header node to a single
286 one. O(n^2) of number of loops. This merginig is necessary, because the loop
287 finding algorith sometimes (eg. when loopbody ends with a if-else construct)
288 reports a single loop as two loops with the same header node.
290 void analyze_double_headers(loopdata *ld)
293 LoopContainer *t1, *t2, *t3;
297 while (t1 != NULL) { /* for all loops do */
298 toCheck = t1->loop_head; /* get header node */
301 while (t2 != NULL) { /* compare it to headers of rest */
302 if (t2->loop_head == toCheck) {
304 /* found overlapping loops -> merge them together */
305 /* printf("C_INFO: found overlapping loops - merging"); */
306 analyze_merge(t1, t2);
308 /* remove second loop from the list of all loops */
310 while (t3->next != t2)
322 /* After the hierarchie of loops has been built, we have to insert the exceptions
323 into this tree. The exception ex is inserted into the subtree pointed to by
326 void insert_exception(methodinfo *m, struct LoopContainer *lc, exceptiontable *ex)
328 struct LoopContainer *temp;
329 struct LoopElement *le;
332 /* printf("insert_exception called with %d-%d and loop %d\n", ex->start->debug_nr, ex->end->debug_nr, lc->loop_head); */
335 /* if child node is reached immediately insert exception into the tree */
336 if (lc->tree_down == NULL) {
337 ex->next = lc->exceptions;
341 /* if we are inside the tree, there are two possibilities: */
342 /* 1. the exception is inside a nested loop or */
343 /* 2. in the loop body of the current loop */
345 /* check all children (= nested loops) */
346 temp = lc->tree_down;
348 while (temp != NULL) {
354 printf("%d.%d\n", le->node, block_index[ex->startpc]);
356 /* if the start of the exception is part of the loop, the */
357 /* whole exception must be part of the loop */
358 if (le->node == m->basicblockindex[ex->startpc])
363 /* Exception is part of a nested loop (Case 1) -> insert it there */
365 insert_exception(m, temp, ex);
368 else if ((temp->loop_head >= m->basicblockindex[ex->startpc]) && (temp->loop_head < m->basicblockindex[ex->endpc])) {
370 /* optimization: if nested loop is part of the exception, the */
371 /* exception cannot be part of a differnet nested loop. */
372 ex->next = lc->exceptions;
377 temp = temp->tree_right;
380 /* Exception is not contained in any nested loop (Case 2) */
382 ex->next = lc->exceptions;
389 /* This function builds a loop hierarchie. The header node of the innermost loop,
390 each basic block belongs to, is stored in the array c_nestedLoops. The array
391 c_hierarchie stores the relationship between differnt loops in as follows:
392 Each loop, that is a nested loop, stores its direct surrounding loop as a
393 parent. Top level loops have no parents.
396 void analyze_nested(methodinfo *m, codegendata *cd, loopdata *ld)
398 /* i/count/tmp are counters */
399 /* toOverwrite is used while loop hierarchie is built (see below) */
400 int i, header, toOverwrite, tmp, len;
402 /* first/last are used during topological sort to build ordered loop list */
403 struct LoopContainer *first, *last, *start, *t, *temp;
405 /* Used to step through all nodes of a loop. */
406 struct LoopElement *le;
408 /* init global structures */
409 ld->c_nestedLoops = DMNEW(int, m->basicblockcount);
410 ld->c_hierarchie = DMNEW(int, m->basicblockcount);
411 for (i=0; i<m->basicblockcount; ++i) {
412 ld->c_nestedLoops[i] = -1;
413 ld->c_hierarchie[i] = -1;
416 /* if there are no optimizable loops -> return */
417 if (ld->c_allLoops == NULL)
420 temp = ld->c_allLoops;
421 while (temp != NULL) { /* for all loops, do */
422 header = temp->loop_head;
424 /* toOverwrite is number of current parent loop (-1 if none) */
425 toOverwrite = ld->c_nestedLoops[header];
427 ld->c_hierarchie[header] = toOverwrite;
429 if (toOverwrite == header) /* check for loops with same header */
430 printf("C_ERROR: Loops have same header\n");
433 while (le != NULL) { /* for all loop nodes, do */
434 tmp = ld->c_nestedLoops[le->node];
436 /* if node is part of parent loop -> overwrite it with nested */
437 if (tmp == toOverwrite)
438 ld->c_nestedLoops[le->node] = header;
440 ld->c_hierarchie[tmp] = header;
442 /* printf("set head of %d to %d", tmp, header); */
452 /* init root of hierarchie tree */
453 ld->root = DMNEW(struct LoopContainer, 1);
454 LoopContainerInit(m, ld->root, -1);
456 /* obtain parent pointer and build hierarchie tree */
457 start = ld->c_allLoops;
458 while (start != NULL) {
460 /* look for parent of loop pointed at by start */
461 first = ld->c_allLoops;
462 while (first != NULL) {
464 /* the parent of the loop, pointed at by start has been found */
465 if (first->loop_head == ld->c_hierarchie[start->loop_head]) {
467 /* printf("set parent to pointer\n"); */
470 start->parent = first;
471 start->tree_right = first->tree_down;
472 first->tree_down = start;
479 /* no parent loop found, set parent to root */
482 /* printf("set parent to root\n"); */
485 start->parent = ld->root;
486 start->tree_right = ld->root->tree_down;
487 ld->root->tree_down = start;
489 /* if a parent exists, increase this nodes indegree */
491 start->parent->in_degree += 1;
496 /* insert exceptions into tree */
498 printf("--- Showing tree ---\n");
499 show_tree(ld->root, 0);
500 printf(" --- End ---\n");
502 for (len = 0; len < cd->exceptiontablelength; ++len)
503 insert_exception(m, ld->root, cd->exceptiontable + len);
506 /* determine sequence of loops for optimization by topological sort */
510 temp = ld->c_allLoops;
511 while (temp != NULL) {
513 /* a loops with indegree == 0 are pushed onto the stack */
514 if (temp->in_degree == 0) {
526 first = last = start;
530 printf("C_ERROR: loops are looped\n");
534 /* pop each node from the stack and decrease its parents indegree by one */
535 /* when the parents indegree reaches zero, push it onto the stack as well */
536 if ((last->parent != ld->root) && (--last->parent->in_degree == 0)) {
537 last->parent->next = start;
538 start = last->parent;
540 while (start != NULL) {
547 if ((last->parent != ld->root) && (--last->parent->in_degree == 0)) {
548 last->parent->next = start;
549 start = last->parent;
554 ld->c_allLoops = first;
557 printf("*** Hierarchie Results \n");
558 while (first != NULL) {
559 printf("%d ", first->loop_head);
568 /* This function is used to add variables that occur as index variables in
569 array accesses (ARRAY_INDEX) or as variables, that change their value (VAR_MOD)
570 to the list of interesting vars (c_loopvars) for the current loop.
573 void add_to_vars(loopdata *ld, int var, int type, int direction)
577 /* printf("Added to vars %d %d %d\n", var, type, direction); */
579 while (lv != NULL) { /* check if var has been previously added */
580 if (lv->value == var) {
581 if (type == ARRAY_INDEX)
582 lv->index = 1; /* var is used as index */
583 else if (type == VAR_MOD) {
584 lv->modified = 1; /* var is used in assignment */
585 switch (direction) { /* how was var modified ? */
587 lv->static_u = 0; /* incremented, no static upper */
588 break; /* bound can be guaranteeed */
590 lv->static_l = 0; /* decremented, no static lower */
591 break; /* bound can be guaranteeed */
593 lv->static_u = lv->static_l = 0;
594 break; /* no info at all */
596 printf("C_ERROR: unknown direction\n");
605 /* variable is not found in list -> add variable to list */
606 lv = DNEW(struct LoopVar);
608 lv->modified = lv->index = 0;
611 if (type == ARRAY_INDEX) {
613 lv->static_u = lv->static_l = 1; /* arrayindex -> var not modified */
615 else if (type == VAR_MOD) {
617 switch (direction) { /* var used in assignment -> set */
618 case D_UP: /* proper static bounds */
619 lv->static_u = 0; lv->static_l = 1;
622 lv->static_u = 1; lv->static_l = 0;
625 lv->static_u = lv->static_l = 0;
628 printf("C_ERROR: unknown direction\n");
633 /* no dynamic bounds have been determined so far */
634 lv->dynamic_l = lv->dynamic_l_v = lv->dynamic_u = lv->dynamic_u_v = 0;
636 lv->next = ld->c_loopvars; /* add var to list */
641 /* This function checks, whether a given loop with header node contains array
642 accesses. If so, it returns 1, else it returns 0 and the loops needs no
643 further consideration in the optimization process. When array accesses are
644 found, a list of all variables, that are used as array index, is built and
645 stored in c_loopvars. For all variables (integer), which values are changed,
646 a flag in c_var_modified is set.
649 int analyze_for_array_access(methodinfo *m, loopdata *ld, int node)
654 struct depthElement *d;
657 if (ld->c_toVisit[node] > 0) { /* node has not been visited yet */
658 ld->c_toVisit[node] = 0;
660 bp = m->basicblocks[node]; /* prepare an instruction scan */
664 access = 0; /* number of array accesses in loop */
666 for (i=0; i<ic; ++i, ++ip) { /* for each instruction, check opcode */
668 case ICMD_IASTORE: /* array store */
676 t = tracing(&bp, i-1, 1); /* try to identify index variable */
678 if (t->type == TRACE_IVAR) {
679 /* if it is a variable, add it to list of index variables */
680 add_to_vars(ld, t->var, ARRAY_INDEX, D_UNKNOWN);
683 else if (t->type == TRACE_ICONST)
687 case ICMD_IALOAD: /* array load */
695 t = tracing(&bp, i-1, 0); /* try to identify index variable */
697 if (t->type == TRACE_IVAR) {
698 /* if it is a variable, add it to list of index variables */
699 add_to_vars(ld, t->var, ARRAY_INDEX, D_UNKNOWN);
702 else if (t->type == TRACE_ICONST)
706 case ICMD_ISTORE: /* integer store */
707 ld->c_var_modified[ip->op1] = 1;
709 /* try to find out, how it was modified */
710 t = tracing(&bp, i-1, 0);
711 if (t->type == TRACE_IVAR) {
712 if ((t->constant > 0) && (t->var == ip->op1))
713 /* a constant was added to the same var */
714 add_to_vars(ld, t->var, VAR_MOD, D_UP);
715 else if (t->var == ip->op1)
716 /* a constant was subtracted from the same var */
717 add_to_vars(ld, t->var, VAR_MOD, D_DOWN);
719 add_to_vars(ld, t->var, VAR_MOD, D_UNKNOWN);
722 add_to_vars(ld, ip->op1, VAR_MOD, D_UNKNOWN);
725 case ICMD_IINC: /* simple add/sub of a constant */
726 ld->c_var_modified[ip->op1] = 1;
729 add_to_vars(ld, ip->op1, VAR_MOD, D_UP);
731 add_to_vars(ld, ip->op1, VAR_MOD, D_DOWN);
738 ld->c_var_modified[ip->op1] = 1;
743 d = ld->c_dTable[node];
744 while (d != NULL) { /* check all successors of block */
745 access += analyze_for_array_access(m, ld, d->value);
756 /* This function scans the exception graph structure to find modifications of
757 array index variables of the current loop. If any modifications are found,
758 1 is returned, else 0.
761 int quick_scan(methodinfo *m, loopdata *ld, int node)
767 struct depthElement *d;
769 /* printf("QS: %d - %d\n", node, ld->c_exceptionVisit[node]); */
772 if (ld->c_exceptionVisit[node] > 0) { /* node is part of exception graph */
773 ld->c_exceptionVisit[node] = -1;
775 bp = m->basicblocks[node]; /* setup scan of all instructions */
779 for (i=0; i<count; ++i, ++ip) { /* for each instruction do */
782 case ICMD_IINC: /* a variable is modified */
784 lv = ld->c_loopvars; /* is it an array index var ? */
786 if ((lv->index) && (lv->value == ip->op1))
787 return 1; /* yes, so return 1 */
794 d = ld->c_exceptionGraph[node]; /* check all successor nodes */
796 if (quick_scan(m, ld, d->value) > 0)
797 return 1; /* if an access is found return 1 */
801 return 0; /* nothing found, so return 0 */
808 /* This function returns 1, when the condition of the loop contains
809 or statements or when an array index variable is modified in any
810 catch block within the loop.
813 int analyze_or_exceptions(methodinfo *m, codegendata *cd, loopdata *ld, int head, struct LoopContainer *lc)
815 struct depthElement *d;
816 int i, k, value, flag, count;
817 struct LoopElement *le;
819 d = ld->c_dTable[head];
822 /* analyze for or-statements */
824 printf("*** Analyze for OR ... ");
828 while (d != NULL) { /* for all successor nodes check if they */
829 value = d->value; /* are part of the loop */
834 if (le->node == value)
839 if (le == NULL) /* node is not part of the loop */
846 if ((count > 1) && (flag == 0)){/* if all successors part of the loop, exit */
847 #ifdef ENABLE_STATISTICS
853 /* check for exceptions */
854 /* printf("done\n*** Analyze for EXCEPTIONS(%d) . ", cd->exceptiontablelength); */
856 if (!cd->exceptiontablelength) /* when there are no exceptions, exit */
859 if ((ld->c_exceptionGraph = (struct depthElement **) malloc(sizeof(struct depthElement *) * m->basicblockcount)) == NULL)
861 if ((ld->c_exceptionVisit = (int *) malloc(sizeof(int) * m->basicblockcount)) == NULL)
864 for (k=0; k<m->basicblockcount; ++k) {
865 ld->c_exceptionVisit[k] = -1;
866 ld->c_exceptionGraph[k] = NULL;
870 /* for all nodes that start catch block check whether they are part of loop */
871 for (i = 0; i < ld->c_old_xtablelength; i++) {
872 value = m->basicblockindex[cd->exceptiontable[i].startpc];
877 if (le->node == value) { /* exception is in loop */
879 printf("C_INFO: Loop contains exception\n");
883 /* build a graph structure, that contains all nodes that are */
884 /* part of the catc block */
885 dF_Exception(m, ld, -1, m->basicblockindex[cd->exceptiontable[i].handlerpc]);
887 /* if array index variables are modified there, return 0 */
888 if (quick_scan(m, ld, m->basicblockindex[cd->exceptiontable[i].handlerpc]) > 0) {
889 #ifdef ENABLE_STATISTICS
890 ld->c_stat_exception++;
892 /* printf("C_INFO: loopVar modified in exception\n"); */
901 printf("none ... done\n");
908 /* This function sets a flag in c_var_modified for all variables that have
909 been found as part of an assigment in the loop.
912 void scan_global_list(loopdata *ld)
919 ld->c_var_modified[lv->value] = 1;
925 /* This function analyses the condition in the loop header and trys to find
926 out, whether some dynamic guarantees can be set up.
929 void init_constraints(methodinfo *m, loopdata *ld, int head)
933 int ic, l_mod, r_mod, changed, operand;
934 struct Trace *left, *right, *th;
935 struct LoopVar *lv_left, *lv_right, *lh;
937 /* prevent some compiler warnings */
943 bp = m->basicblocks[head];
945 ip = bp.iinstr+(ic-1); /* set ip to last instruction in header node */
947 switch (ip->opc) { /* check op-code */
949 /* comparison against constant value */
950 case ICMD_IFEQ: /* ..., value ==> ... */
951 case ICMD_IFLT: /* ..., value ==> ... */
952 case ICMD_IFLE: /* ..., value ==> ... */
953 case ICMD_IFGT: /* ..., value ==> ... */
954 case ICMD_IFGE: /* ..., value ==> ... */
955 /* op1 = target JavaVM pc, val.i = constant */
957 left = tracing(&bp, ic-2, 0); /* analyse left arg., right is constant */
958 right = create_trace(TRACE_ICONST, -1, ip->val.i, 0);
961 /* standard comparison */
962 case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */
963 case ICMD_IF_ICMPLT: /* ..., value, value ==> ... */
964 case ICMD_IF_ICMPGT: /* ..., value, value ==> ... */
965 case ICMD_IF_ICMPLE: /* ..., value, value ==> ... */
966 case ICMD_IF_ICMPGE: /* ..., value, value ==> ... */
968 left = tracing(&bp, ic-2, 1); /* get left and right argument */
969 right = tracing(&bp, ic-2, 0);
972 /* other condition */
974 left = create_trace(TRACE_UNKNOWN, -1, 0, 0);
975 right = create_trace(TRACE_UNKNOWN, -1, 0, 0);
979 /* analyse left and right side of comparison */
982 if (left->type == TRACE_IVAR) { /* is a loop variable on left side ? */
983 lv_left = ld->c_loopvars;
984 while (lv_left != NULL) {
985 if (lv_left->value == left->var) {
986 l_mod = lv_left->modified; /* yes, but has it been modified ? */
989 lv_left = lv_left->next;
993 if (right->type == TRACE_IVAR){ /* is a loop variable on right side ? */
994 lv_right = ld->c_loopvars;
995 while (lv_right != NULL) {
996 if (lv_right->value == right->var) {
997 r_mod = lv_right->modified; /* yes, but has it been modified ? */
1000 lv_right = lv_right->next;
1004 if ((l_mod - r_mod) == 0) { /* both 1 or both 0 -> no dynamic contraints*/
1005 ld->c_rightside = NULL; /* possible */
1009 /* to simplify processing, make the left side the one, that contains the */
1010 /* modified variable */
1011 if (r_mod > l_mod) {
1012 th = left; left = right; right = th;
1013 lh = lv_left; lv_left = lv_right; lv_right = lh;
1014 changed = 1; /* set changed to true */
1017 changed = 0; /* no change needed */
1019 /* make sure that right side's value does not change during loop execution */
1020 if (right->type == TRACE_UNKNOWN) {
1021 ld->c_rightside = NULL;
1025 /* determine operands: */
1026 /* for further explaination a is modified, b nonmodified var */
1027 switch (ip->opc) { /* check opcode again */
1028 case ICMD_IFEQ: /* ..., value ==> ... */
1029 case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */
1030 operand = OP_EQ; /* a == b */
1033 case ICMD_IFLE: /* ..., value ==> ... */
1034 case ICMD_IF_ICMPLE: /* ..., value, value ==> ... */
1036 operand = OP_GE; /* b<=a -> a>=b */
1038 operand = OP_LT; /* a<=b -> a<(b+1) */
1039 if (left->constant != 0)
1040 left->constant -= 1;
1042 right->constant += 1;
1046 case ICMD_IFLT: /* ..., value ==> ... */
1047 case ICMD_IF_ICMPLT: /* ..., value, value ==> ... */
1049 operand = OP_GE; /* b<a -> a>=(b+1) */
1050 if (left->constant != 0)
1051 left->constant -= 1;
1053 right->constant += 1;
1056 operand = OP_LT; /* a<b -> a<b */
1059 case ICMD_IFGT: /* ..., value ==> ... */
1060 case ICMD_IF_ICMPGT: /* ..., value, value ==> ... */
1062 operand = OP_LT; /* b>a -> a<b */
1064 operand = OP_GE; /* a>b -> a>=(b+1) */
1065 if (left->constant != 0)
1066 left->constant -= 1;
1068 right->constant += 1;
1072 case ICMD_IFGE: /* ..., value ==> ... */
1073 case ICMD_IF_ICMPGE: /* ..., value, value ==> ... */
1075 operand = OP_LT; /* b>=a -> a<(b+1) */
1076 if (left->constant != 0)
1077 left->constant -= 1;
1079 right->constant += 1;
1082 operand = OP_GE; /* a>=b -> a>=b */
1086 printf("C_ERROR: debugging error 0x00\n");
1090 /* NOW: left/lv_left -> loopVar */
1091 /* right/lv_right -> const, nonmod. var, arraylength */
1092 switch (operand) { /* check operand */
1094 lv_left->dynamic_u_v = 1; /* upper + lower bound tested */
1095 lv_left->dynamic_l_v = 1;
1097 lv_left->dynamic_l = lv_left->dynamic_u = left->constant;
1101 lv_left->dynamic_u_v = 1; /* upper bound tested */
1103 lv_left->dynamic_u = left->constant;
1107 lv_left->dynamic_l_v = 1; /* lower bound tested */
1109 lv_left->dynamic_l = left->constant;
1113 printf("C_ERROR: debugging error 0x01\n");
1116 ld->c_rightside = right;
1118 switch (ld->c_rightside->type) {
1120 ld->c_rs_needed_instr = 1;
1123 ld->c_rs_needed_instr = 2;
1126 ld->c_rs_needed_instr = 3;
1129 printf("C_ERROR: wrong right-side type\n");
1134 /* This function is needed to add and record new static tests (before loop
1135 entry) of variables to make guaratees for index variables. type states
1136 the kind of the test. arrayRef is the array, which length is tested
1137 against, varRef is the variable, that is testes and constant is the
1138 constant value, that is tested.
1141 void add_new_constraint(methodinfo *m, codegendata *cd, loopdata *ld, int type, int arrayRef, int varRef, int constant)
1143 struct Constraint *tc;
1146 case TEST_ZERO: /* a variable is tested against a const */
1148 tc = ld->c_constraints[varRef]; /* does a test already exist for this var ? */
1149 while (tc != NULL) {
1150 if (tc->type == TEST_ZERO) {
1151 if (constant < tc->constant)
1152 tc->constant = constant;
1153 return; /* yes. update constant and return */
1158 /* insert a new test for this variable */
1159 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1161 tc->type = TEST_ZERO;
1162 tc->varRef = varRef;
1163 tc->constant = constant;
1164 tc->next = ld->c_constraints[varRef];
1165 ld->c_constraints[varRef] = tc;
1166 ld->c_needed_instr += 3;
1170 case TEST_ALENGTH: /* variable is tested against array length */
1172 tc = ld->c_constraints[varRef]; /* does a test already exist for this var ? */
1173 while (tc != NULL) {
1174 if ((tc->type == TEST_ALENGTH) && (tc->arrayRef == arrayRef)) {
1175 if (constant > tc->constant)
1176 tc->constant = constant;
1177 return; /* yes. update constant and return */
1182 /* insert a new test for this variable */
1183 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1185 tc->type = TEST_ALENGTH;
1186 tc->arrayRef = arrayRef;
1187 tc->varRef = varRef;
1188 tc->constant = constant;
1189 tc->next = ld->c_constraints[varRef];
1190 ld->c_constraints[varRef] = tc;
1191 ld->c_needed_instr += 6;
1193 /* if arrayRef is not already tested against null, insert that test */
1194 if (!(ld->c_null_check[arrayRef])) {
1195 ld->c_null_check[arrayRef] = 1;
1196 ld->c_needed_instr +=2;
1201 case TEST_CONST_ZERO:
1205 case TEST_CONST_ALENGTH: /* a const is tested against array length */
1207 /* does a test already exist for this array */
1208 tc = ld->c_constraints[cd->maxlocals];
1209 while (tc != NULL) {
1210 if ((tc->type == TEST_CONST_ALENGTH) && (tc->arrayRef == arrayRef)) {
1211 if (constant > tc->constant)
1212 tc->constant = constant;
1213 return; /* yes. update constant and return */
1218 /* insert a new test for this array */
1219 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1221 tc->type = TEST_CONST_ALENGTH;
1222 tc->arrayRef = arrayRef;
1223 tc->constant = constant;
1224 tc->next = ld->c_constraints[cd->maxlocals];
1225 ld->c_constraints[cd->maxlocals] = tc;
1226 ld->c_needed_instr += 4;
1228 /* if arrayRef is not already tested against null, insert that test */
1229 if (!(ld->c_null_check[arrayRef])) {
1230 ld->c_null_check[arrayRef] = 1;
1231 ld->c_needed_instr +=2;
1236 case TEST_UNMOD_ZERO: /* test unmodified var against constant */
1238 /* search if test already exists */
1239 tc = ld->c_constraints[varRef];
1240 while (tc != NULL) {
1241 if (tc->type == TEST_UNMOD_ZERO) {
1242 if (constant < tc->constant)
1243 tc->constant = constant;
1244 return; /* yes, so update constant */
1249 /* else, a new test is inserted */
1250 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1252 tc->type = TEST_UNMOD_ZERO;
1253 tc->varRef = varRef;
1254 tc->constant = constant;
1255 tc->next = ld->c_constraints[varRef];
1256 ld->c_constraints[varRef] = tc;
1257 ld->c_needed_instr += 3;
1261 case TEST_UNMOD_ALENGTH: /* test unmodified var against array length */
1263 /* search if test alreay exists */
1264 tc = ld->c_constraints[varRef];
1265 while (tc != NULL) {
1266 if ((tc->type == TEST_UNMOD_ALENGTH) && (tc->arrayRef == arrayRef)) {
1267 if (constant > tc->constant)
1268 tc->constant = constant;
1269 return; /* yes, so modify constants */
1274 /* create new entry */
1275 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1277 tc->type = TEST_UNMOD_ALENGTH;
1278 tc->varRef = varRef;
1279 tc->arrayRef = arrayRef;
1280 tc->constant = constant;
1281 tc->next = ld->c_constraints[varRef];
1282 ld->c_constraints[varRef] = tc;
1283 ld->c_needed_instr += 6;
1285 /* if arrayRef is not already tested against null, insert that test */
1286 if (!(ld->c_null_check[arrayRef])) {
1287 ld->c_null_check[arrayRef] = 1;
1288 ld->c_needed_instr +=2;
1293 case TEST_RS_ZERO: /* test right side of the loop condition */
1294 /* against a constant - needed by dynamic */
1296 /*!! varRef -> maxlocals */
1297 /* search if test already exists */
1298 tc = ld->c_constraints[cd->maxlocals];
1299 while (tc != NULL) {
1300 if (tc->type == TEST_RS_ZERO) {
1301 if (constant < tc->constant)
1302 tc->constant = constant;
1303 return; /* yes, so modify constants */
1308 /* create new entry */
1309 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1311 tc->type = TEST_RS_ZERO;
1312 tc->constant = constant;
1313 tc->next = ld->c_constraints[cd->maxlocals];
1314 ld->c_constraints[cd->maxlocals] = tc;
1315 ld->c_needed_instr += (2 + ld->c_rs_needed_instr);
1317 /* if arrayRef on right side is not already tested against null, */
1318 /* insert that test */
1319 if ((ld->c_rightside->type == TRACE_ALENGTH) && (!(ld->c_null_check[ld->c_rightside->var]))) {
1320 ld->c_null_check[ld->c_rightside->var] = 1;
1321 ld->c_needed_instr +=2;
1326 case TEST_RS_ALENGTH: /* test right side of the loop condition */
1327 /* against array length - needed by dynamic */
1329 /*!! varRef -> maxlocals */
1330 /* search if test already exists */
1331 tc = ld->c_constraints[cd->maxlocals];
1334 if ((tc->type == TEST_RS_ALENGTH) && (tc->arrayRef == arrayRef))
1336 if (constant > tc->constant)
1337 tc->constant = constant;
1338 return; /* yes, so modify constants */
1343 /* create new entry */
1344 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1346 tc->type = TEST_RS_ALENGTH;
1347 tc->arrayRef = arrayRef;
1348 tc->constant = constant;
1349 tc->next = ld->c_constraints[cd->maxlocals];
1350 ld->c_constraints[cd->maxlocals] = tc;
1351 ld->c_needed_instr += (3 + ld->c_rs_needed_instr);
1353 /* if arrayRef is not already tested against null, insert that test */
1354 if (!(ld->c_null_check[arrayRef])) {
1355 ld->c_null_check[arrayRef] = 1;
1356 ld->c_needed_instr +=2;
1359 /* if arrayRef on right side is not already tested against null, */
1360 /* insert that test */
1361 if ((ld->c_rightside->type == TRACE_ALENGTH) && (!(ld->c_null_check[ld->c_rightside->var]))) {
1362 ld->c_null_check[ld->c_rightside->var] = 1;
1363 ld->c_needed_instr +=2;
1371 /* This functions adds new static (before loop enry) tests of variables to the
1372 program to be able to guarantee certain values for index variables in array
1373 access (to safely remove bound checks).
1376 int insert_static(methodinfo *m, codegendata *cd, loopdata *ld, int arrayRef, struct Trace *index, struct Changes *varChanges, int special)
1382 /* printf("insert static check - %d\n", arrayRef);
1384 show_change(varChanges);
1387 if (varChanges == NULL) { /* the variable hasn't changed / const */
1388 if ((varChanges = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
1390 varChanges->lower_bound = varChanges->upper_bound = 0;
1393 switch (index->type) { /* check index type */
1394 case TRACE_IVAR: /* it is a variable */
1395 if (index->neg < 0) { /* if it's a negated var, return */
1396 #ifdef ENABLE_STATISTICS
1397 ld->c_stat_no_opt++;
1402 varRef = index->var;
1405 if (ld->c_var_modified[varRef]) { /* volatile var */
1407 lv = ld->c_loopvars; /* get reference to loop variable */
1409 while ((lv != NULL) && (lv->value != varRef))
1412 printf("C_ERROR: debugging error 0x02\n");
1414 /* show_varinfo(lv); */
1416 /* check existing static bounds and add new contraints on variable */
1417 /* to possibly remove bound checks */
1419 /* the var is never decremented, so we add a static test againt */
1421 if (varChanges->lower_bound > varChanges->upper_bound)
1422 add_new_constraint(m, cd, ld, TEST_ZERO, arrayRef, varRef, index->constant);
1424 add_new_constraint(m, cd, ld, TEST_ZERO, arrayRef, varRef, varChanges->lower_bound+index->constant);
1427 else if ((lv->dynamic_l_v) && (!special)) {
1428 /* the variable is decremented, but it is checked against a */
1429 /* bound in the loop condition */
1430 if (varChanges->lower_bound <= varChanges->upper_bound) {
1431 add_new_constraint(m, cd, ld, TEST_RS_ZERO, arrayRef, varRef, varChanges->lower_bound+index->constant+lv->dynamic_l);
1437 /* the var is never incremented, so we add a static test againt */
1439 if (varChanges->lower_bound > varChanges->upper_bound)
1440 add_new_constraint(m, cd, ld, TEST_ALENGTH, arrayRef, varRef, index->constant);
1442 add_new_constraint(m, cd, ld, TEST_ALENGTH, arrayRef, varRef, varChanges->upper_bound+index->constant);
1445 else if ((lv->dynamic_u_v) && (!special)) {
1446 /* the variable is decremented, but it is checked against a */
1447 /* bound in the loop condition */
1448 if (varChanges->lower_bound <= varChanges->upper_bound) {
1449 add_new_constraint(m, cd, ld, TEST_RS_ALENGTH, arrayRef, varRef, varChanges->upper_bound+index->constant+lv->dynamic_u);
1454 else { /* the var is never modified at all */
1455 add_new_constraint(m, cd, ld, TEST_UNMOD_ZERO, arrayRef, index->var, index->constant);
1456 add_new_constraint(m, cd, ld, TEST_UNMOD_ALENGTH, arrayRef, index->var, index->constant);
1460 /* if the addition of new variable tests made guarantees possible, */
1461 /* return the best possible optimization */
1462 if ((high > 0) && (low > 0)) {
1463 /* printf("fully optimzed\n"); */
1464 #ifdef ENABLE_STATISTICS
1465 ld->c_stat_full_opt++;
1469 else if (high > 0) {
1470 /* printf("upper optimzed\n"); */
1471 #ifdef ENABLE_STATISTICS
1472 ld->c_stat_upper_opt++;
1477 /* printf("lower optimzed\n"); */
1478 #ifdef ENABLE_STATISTICS
1479 ld->c_stat_lower_opt++;
1484 /* printf("not optimzed\n"); */
1485 #ifdef ENABLE_STATISTICS
1486 ld->c_stat_no_opt++;
1492 case TRACE_ICONST: /* if it is a constant, optimization is easy */
1493 if (index->constant < 0) {
1494 #ifdef ENABLE_STATISTICS
1495 ld->c_stat_no_opt++;
1497 return OPT_NONE; /* negative index -> bad */
1500 add_new_constraint(m, cd, ld, TEST_CONST_ALENGTH, arrayRef, 0, index->constant);
1501 #ifdef ENABLE_STATISTICS
1502 ld->c_stat_full_opt++;
1504 return OPT_FULL; /* else just test constant against array length */
1508 case TRACE_ALENGTH: /* else, no optimizations possible */
1511 #ifdef ENABLE_STATISTICS
1512 ld->c_stat_no_opt++;
1517 /* keep compiler happy */
1523 /* copy a stack and return the start pointer of the newly created one
1525 stackptr copy_stack_from(stackptr source) {
1526 stackptr current, top;
1531 /* copy first element */
1532 current = DMNEW(stackelement, 1);
1533 current->type = source->type;
1534 current->flags = source->flags;
1535 current->varkind = source->varkind;
1536 current->varnum = source->varnum;
1537 current->regoff = source->regoff;
1541 /* if there exist more, then copy the rest */
1542 while (source->prev != NULL) {
1543 source = source->prev;
1544 current->prev = DMNEW(stackelement, 1);
1545 current->type = source->type;
1546 current->flags = source->flags;
1547 current->varkind = source->varkind;
1548 current->varnum = source->varnum;
1549 current->regoff = source->regoff;
1550 current = current->prev;
1553 current->prev = NULL;
1558 /* The following defines are used in the procedure void create_static_checks(...)
1559 They add a new instruction with its corresponding stack manipulation and
1560 are used to build the new loop header of an optimized loop, where we have
1561 to check certain variables and constants against values to guarantee that
1562 index values in array accesses remain with array bounds.
1564 inst: pointer to the new instruction
1565 tos: stackpointer before this operation is executed
1566 newstack: temporary stackptr
1567 stackdepth: counts the current stackdepth
1568 original start: blockpointer to the head of the new, optimized loop
1571 /* Load a local integer variable v */
1572 #define LOAD_VAR(v) { \
1573 inst->opc = ICMD_ILOAD; \
1575 newstack = DMNEW(stackelement, 1); \
1576 inst->dst = newstack; \
1577 newstack->prev = tos; \
1578 newstack->type = TYPE_INT; \
1579 newstack->flags = 0; \
1580 newstack->varkind = LOCALVAR; \
1581 newstack->varnum = v; \
1587 /* Load a constant with value c */
1588 #define LOAD_CONST(c) { \
1589 inst->opc = ICMD_ICONST; \
1591 inst->val.i = (c); \
1592 newstack = DMNEW(stackelement, 1); \
1593 newstack->prev = tos; \
1594 newstack->type = TYPE_INT; \
1595 newstack->flags = 0; \
1596 newstack->varkind = UNDEFVAR; \
1597 newstack->varnum = stackdepth; \
1604 /* Load a local reference (adress) variable a */
1605 #define LOAD_ADDR(a) { \
1606 inst->opc = ICMD_ALOAD; \
1608 newstack = DMNEW(stackelement, 1); \
1609 newstack->prev = tos; \
1610 newstack->type = TYPE_ADR; \
1611 newstack->flags = 0; \
1612 newstack->varkind = LOCALVAR; \
1613 newstack->varnum = a; \
1620 /* Insert a compare greater-or-equal and jump to the unoptimized loop, if the */
1621 /* comparison is true */
1622 #define GOTO_NOOPT_IF_GE { \
1623 inst->opc = ICMD_IF_ICMPGE; \
1624 inst->target = original_start->copied_to; \
1625 if (tos->varkind == UNDEFVAR) \
1626 tos->varkind = TEMPVAR; \
1628 if (tos->varkind == UNDEFVAR) \
1629 tos->varkind = TEMPVAR; \
1636 /* Insert a compare greater than and jump to the unoptimized loop, if the */
1637 /* comparison is true */
1638 #define GOTO_NOOPT_IF_GT { \
1639 inst->opc = ICMD_IF_ICMPGT; \
1640 inst->target = original_start->copied_to; \
1641 if (tos->varkind == UNDEFVAR) \
1642 tos->varkind = TEMPVAR; \
1644 if (tos->varkind == UNDEFVAR) \
1645 tos->varkind = TEMPVAR; \
1653 /* Insert a compare less-than and jump to the unoptimized loop, if the */
1654 /* comparison is true */
1655 #define GOTO_NOOPT_IF_LT { \
1656 inst->opc = ICMD_IF_ICMPLT; \
1657 inst->target = original_start->copied_to; \
1658 if(tos->varkind == UNDEFVAR) \
1659 tos->varkind = TEMPVAR; \
1661 if(tos->varkind == UNDEFVAR) \
1662 tos->varkind = TEMPVAR; \
1669 /* Insert a compare if-not-null and jump to the unoptimized loop, if the */
1670 /* comparison is true */
1671 #define GOTO_NOOPT_IF_NULL { \
1672 inst->opc = ICMD_IFNULL; \
1673 inst->target = original_start->copied_to; \
1674 if(tos->varkind == UNDEFVAR) \
1675 tos->varkind = TEMPVAR; \
1682 /* Insert an add instruction, that adds two integer values on top of the stack */
1685 inst->opc = ICMD_IADD; \
1686 if(tos->varkind == UNDEFVAR) \
1687 tos->varkind = TEMPVAR; \
1689 if(tos->varkind == UNDEFVAR) \
1690 tos->varkind = TEMPVAR; \
1692 newstack = DMNEW(stackelement, 1); \
1693 newstack->prev = tos; \
1694 newstack->type = TYPE_INT; \
1695 newstack->flags = 0; \
1696 newstack->varkind = UNDEFVAR; \
1697 newstack->varnum = stackdepth; \
1704 /* Insert instructions to load the arraylength of an array with reference a */
1705 /* fisrt, the reference must be loaded, then a null-pointer check is inserted */
1706 /* if not already done earlier. Finally an arraylength instruction is added */
1707 #define LOAD_ARRAYLENGTH(a) { \
1708 if (ld->c_null_check[a]) { \
1710 GOTO_NOOPT_IF_NULL; \
1711 ld->c_null_check[a] = 0; \
1714 inst->opc = ICMD_ARRAYLENGTH; \
1715 if(tos->varkind == UNDEFVAR) \
1716 tos->varkind = TEMPVAR; \
1718 newstack = DMNEW(stackelement, 1); \
1719 newstack->prev = tos; \
1720 newstack->type = TYPE_INT; \
1721 newstack->flags = 0; \
1722 newstack->varkind = UNDEFVAR; \
1723 newstack->varnum = stackdepth; \
1730 /* Inserts the instructions to load the value of the right side of comparison */
1731 /* Depending of the type of the right side, the apropriate instructions are */
1733 #define LOAD_RIGHT_SIDE { \
1734 switch (ld->c_rightside->type) { \
1735 case TRACE_ICONST: \
1736 LOAD_CONST(ld->c_rightside->constant); \
1739 LOAD_VAR(ld->c_rightside->var); \
1740 LOAD_CONST(ld->c_rightside->constant); \
1743 case TRACE_ALENGTH: \
1744 LOAD_ARRAYLENGTH(ld->c_rightside->var); \
1747 log_text("C_ERROR: illegal trace on rightside of loop-header"); \
1752 /* Patch jumps in original loop and in copied loop, add gotos in copied loop.
1753 All jumps in the original loop to the loop head have to be redirected to
1754 the newly inserted one. For the copied loop, it is necessay to redirect all
1755 jumps inside that loop to the copied nodes. lc points to the current loop,
1756 loop_head is a pointer to the newly inserted head and original start was
1757 the old head and is now the head of the optimized variant of the loop.
1759 void patch_jumps(basicblock *original_start, basicblock *loop_head, struct LoopContainer *lc)
1761 /* step through all nodes of a loop */
1762 struct LoopElement *le;
1764 instruction *inst, *temp_instr;
1768 while (le != NULL) {
1770 /* do nothing for new loop head */
1771 if (le->block == loop_head) {
1776 /* for original version */
1778 inst = bptr->iinstr;
1779 for (i = 0; i < bptr->icount; ++i, ++inst) {
1780 switch (inst->opc) {
1782 case ICMD_IF_ICMPEQ:
1783 case ICMD_IF_ICMPLT:
1784 case ICMD_IF_ICMPLE:
1785 case ICMD_IF_ICMPNE:
1786 case ICMD_IF_ICMPGT:
1787 case ICMD_IF_ICMPGE:
1789 case ICMD_IF_LCMPEQ:
1790 case ICMD_IF_LCMPLT:
1791 case ICMD_IF_LCMPLE:
1792 case ICMD_IF_LCMPNE:
1793 case ICMD_IF_LCMPGT:
1794 case ICMD_IF_LCMPGE:
1796 case ICMD_IF_ACMPEQ:
1797 case ICMD_IF_ACMPNE:
1816 case ICMD_IFNONNULL:
1818 /* jump to newly inserted loopheader has to be redirected */
1819 if (((basicblock *) inst->target) == loop_head)
1820 inst->target = (void *) original_start;
1823 case ICMD_TABLESWITCH:
1828 tptr = (void **) inst->target;
1830 s4ptr = inst->val.a;
1831 l = s4ptr[1]; /* low */
1832 i = s4ptr[2]; /* high */
1836 /* jump to newly inserted loopheader has to be redirected */
1837 for (tptr = inst->target; i >= 0; --i, ++tptr) {
1838 if (((basicblock *) *tptr) == loop_head)
1839 tptr[0] = (void *) original_start;
1844 case ICMD_LOOKUPSWITCH:
1849 tptr = (void **) inst->target;
1851 s4ptr = inst->val.a;
1852 l = s4ptr[0]; /* default */
1853 i = s4ptr[1]; /* count */
1855 /* jump to newly inserted loopheader has to be redirected */
1856 for (tptr = inst->target; i >= 0; --i, ++tptr) {
1857 if (((basicblock *) *tptr) == loop_head)
1858 tptr[0] = (void *) original_start;
1865 /* if node is part of loop and has fall through to original start, that */
1866 /* must be redirected. Unfortunately the instructions have to be copied */
1868 if (bptr->next == loop_head) {
1869 temp_instr = DMNEW(instruction, bptr->icount + 1);
1870 memcpy(temp_instr, bptr->iinstr, sizeof(instruction)*bptr->icount);
1871 bptr->iinstr = temp_instr;
1873 bptr->iinstr[bptr->icount].opc = ICMD_GOTO;
1874 bptr->iinstr[bptr->icount].target = original_start;
1875 bptr->iinstr[bptr->icount].dst = NULL;
1879 /* for copied version - which gets the unoptimized variant */
1880 bptr = le->block->copied_to;
1881 inst = bptr->iinstr;
1882 for (i = 0; i < bptr->icount; ++i, ++inst) {
1884 switch (inst->opc) {
1886 case ICMD_IASTORE: /* array store */
1894 case ICMD_IALOAD: /* array load */
1903 /* undo previous optimizations in new loop */
1907 case ICMD_IF_ICMPEQ:
1908 case ICMD_IF_ICMPLT:
1909 case ICMD_IF_ICMPLE:
1910 case ICMD_IF_ICMPNE:
1911 case ICMD_IF_ICMPGT:
1912 case ICMD_IF_ICMPGE:
1914 case ICMD_IF_LCMPEQ:
1915 case ICMD_IF_LCMPLT:
1916 case ICMD_IF_LCMPLE:
1917 case ICMD_IF_LCMPNE:
1918 case ICMD_IF_LCMPGT:
1919 case ICMD_IF_LCMPGE:
1921 case ICMD_IF_ACMPEQ:
1922 case ICMD_IF_ACMPNE:
1941 case ICMD_IFNONNULL:
1943 /* jump to newly inserted loopheader has to be redirected */
1944 if (((basicblock *) inst->target) == loop_head)
1945 inst->target = (void *) original_start->copied_to;
1946 /* jump to loop internal nodes has to be redirected */
1947 else if (((basicblock *) inst->target)->lflags & LOOP_PART)
1948 inst->target = (void *) ((basicblock *) inst->target)->copied_to;
1951 case ICMD_TABLESWITCH:
1955 void **copy_ptr, *base_ptr;
1958 tptr = (void **) inst->target;
1960 s4ptr = inst->val.a;
1961 l = s4ptr[1]; /* low */
1962 i = s4ptr[2]; /* high */
1966 copy_ptr = (void**) DMNEW(void*, i+1);
1967 base_ptr = (void*) copy_ptr;
1969 /* Targets for switch instructions are stored in an extra */
1970 /* that must be copied for new inserted loop. */
1972 for (tptr = inst->target; i >= 0; --i, ++tptr, ++copy_ptr) {
1973 /* jump to newly inserted loopheader must be redirected */
1974 if (((basicblock *) *tptr) == loop_head)
1975 copy_ptr[0] = (void *) original_start->copied_to;
1976 /* jump to loop internal nodes has to be redirected */
1977 else if (((basicblock *) *tptr)->lflags & LOOP_PART)
1978 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
1980 copy_ptr[0] = tptr[0];
1983 inst->target = base_ptr;
1987 case ICMD_LOOKUPSWITCH:
1991 void **copy_ptr, **base_ptr;
1994 tptr = (void **) inst->target;
1996 s4ptr = inst->val.a;
1997 l = s4ptr[0]; /* default */
1998 i = s4ptr[1]; /* count */
2000 copy_ptr = (void**) DMNEW(void*, i+1);
2001 base_ptr = (void*) copy_ptr;
2003 /* Targets for switch instructions are stored in an extra */
2004 /* that must be copied for new inserted loop. */
2006 for (tptr = inst->target; i >= 0; --i, ++tptr, ++copy_ptr) {
2007 /* jump to newly inserted loopheader must be redirected */
2008 if (((basicblock *) *tptr) == loop_head)
2009 copy_ptr[0] = (void *) original_start->copied_to;
2010 /* jump to loop internal nodes has to be redirected */
2011 else if (((basicblock *) *tptr)->lflags & LOOP_PART)
2012 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2014 copy_ptr[0] = tptr[0];
2017 inst->target = base_ptr;
2024 /* if fall through exits loop, goto is needed */
2025 if (!(le->block->next->lflags & LOOP_PART)) {
2026 bptr->iinstr[bptr->icount].opc = ICMD_GOTO;
2027 bptr->iinstr[bptr->icount].dst = NULL;
2028 bptr->iinstr[bptr->icount].target = le->block->next;
2037 /* Add the new header node of a loop that has been duplicated to all parent
2038 loops in nesting hierarchie.
2041 void header_into_parent_loops(loopdata *ld, struct LoopContainer *lc, basicblock *to_insert, basicblock *replace, basicblock *after)
2043 /* we have to insert the node to_insert before the node after and replace */
2044 /* the pointer of to_insert by the node replace */
2046 struct LoopElement *le, *t;
2048 /* if the top of the tree is reached, then return */
2049 if ((lc == NULL) || (lc == ld->root))
2052 /* create new node, that should be inserted */
2053 t = DMNEW(struct LoopElement, 1);
2054 t->block = to_insert;
2057 /* first, find the node, that has to be replaced (= "to_insert") and */
2058 /* replace it by the node "replace" */
2060 while (le->block != to_insert)
2062 le->block = replace;
2065 if (after == to_insert)
2068 /* now find the node after and insert the newly create node before "after" */
2070 if (le->block == after) {
2071 t->next = lc->nodes;
2075 while (le->next->block != after)
2082 /* go up one hierarchie level */
2083 header_into_parent_loops(ld, lc->parent, to_insert, replace, after);
2087 /* Add a new node (not header) of a duplicated loop to all parent loops in
2091 void node_into_parent_loops(loopdata *ld, struct LoopContainer *lc, basicblock *to_insert)
2093 struct LoopElement *le, *t;
2095 /* if the top of the tree is reached, then return */
2096 if ((lc == NULL) || (lc == ld->root))
2099 /* create new node, that should be inserted */
2100 t = DNEW(LoopElement);
2101 t->block = to_insert;
2106 /* append new node to node list of loop */
2107 while (le->next != NULL)
2113 /* go up one hierarchie level */
2114 node_into_parent_loops(ld, NULL, to_insert);
2118 /* void patch_handler(...) is very similar to parts of the function patch_jumps.
2119 Its task is to redirect all jumps from the original head to the new head and
2120 to redirect internal jumps inside the exception handler to the newly
2121 created (copied) nodes.
2124 void patch_handler(struct LoopContainer *lc, basicblock *bptr, basicblock *original_head, basicblock *new_head)
2129 /* If node is not part of exception handler or has been visited, exit */
2130 if (!(bptr->lflags & HANDLER_PART) || (bptr->lflags & HANDLER_VISITED))
2133 /* mark block as visited */
2134 bptr->lflags |= HANDLER_VISITED;
2136 /* for all instructions in the copied block, do */
2137 for (i = 0, ip = bptr->copied_to->iinstr; i < bptr->copied_to->icount; ++i, ++ip) {
2148 case ICMD_IF_ICMPEQ:
2149 case ICMD_IF_ICMPLT:
2150 case ICMD_IF_ICMPLE:
2151 case ICMD_IF_ICMPNE:
2152 case ICMD_IF_ICMPGT:
2153 case ICMD_IF_ICMPGE:
2155 case ICMD_IF_LCMPEQ:
2156 case ICMD_IF_LCMPLT:
2157 case ICMD_IF_LCMPLE:
2158 case ICMD_IF_LCMPNE:
2159 case ICMD_IF_LCMPGT:
2160 case ICMD_IF_LCMPGE:
2162 case ICMD_IF_ACMPEQ:
2163 case ICMD_IF_ACMPNE:
2181 case ICMD_IFNONNULL:
2183 patch_handler(lc, bptr->next, original_head, new_head);
2189 patch_handler(lc, ip->target, original_head, new_head);
2191 /* jumps to old header have to be redirected */
2192 if (((basicblock *) ip->target) == original_head)
2193 ip->target = (void *) new_head->copied_to;
2194 /* jumps to handler internal nodes have to be redirected */
2195 else if (((basicblock *) ip->target)->lflags & HANDLER_PART)
2196 ip->target = (void *) ((basicblock *) ip->target)->copied_to;
2197 /* jumps to loop internal nodes have to be redirected */
2198 else if (((basicblock *) ip->target)->lflags & LOOP_PART)
2199 ip->target = (void *) ((basicblock *) ip->target)->copied_to;
2204 case ICMD_TABLESWITCH:
2208 void **copy_ptr, **base_ptr;
2210 tptr = (void **) ip->target;
2212 l = s4ptr[1]; /* low */
2213 i = s4ptr[2]; /* high */
2216 copy_ptr = (void**) DMNEW(void*, i+1);
2217 base_ptr = (void*) copy_ptr;
2219 for (tptr = ip->target; i >= 0; --i, ++tptr, ++copy_ptr) {
2220 patch_handler(lc, ((basicblock *) *tptr), original_head, new_head);
2221 /* jumps to old header have to be redirected */
2222 if (((basicblock *) *tptr) == original_head)
2223 copy_ptr[0] = (void *) new_head->copied_to;
2224 /* jumps to handler internal nodes have to be redirected */
2225 else if (((basicblock *) *tptr)->lflags & HANDLER_PART)
2226 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2227 /* jumps to loop internal nodes have to be redirected */
2228 else if (((basicblock *) ip->target)->lflags & LOOP_PART)
2229 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2231 copy_ptr[0] = tptr[0];
2234 ip->target = base_ptr;
2238 case ICMD_LOOKUPSWITCH:
2243 void **copy_ptr, **base_ptr;
2245 tptr = (void **) ip->target;
2247 l = s4ptr[0]; /* default */
2248 i = s4ptr[1]; /* count */
2250 copy_ptr = (void**) DMNEW(void*, i+1);
2251 base_ptr = (void*) copy_ptr;
2253 for (tptr = ip->target; i >= 0; --i, ++tptr, ++copy_ptr) {
2255 patch_handler(lc, ((basicblock *) *tptr), original_head, new_head);
2256 /* jumps to old header have to be redirected */
2257 if (((basicblock *) *tptr) == original_head)
2258 copy_ptr[0] = (void *) new_head->copied_to;
2259 /* jumps to handler internal nodes have to be redirected */
2260 else if (((basicblock *) *tptr)->lflags & HANDLER_PART)
2261 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2262 /* jumps to loop internal nodes have to be redirected */
2263 else if (((basicblock *) ip->target)->lflags & LOOP_PART)
2264 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2266 copy_ptr[0] = tptr[0];
2269 ip->target = base_ptr;
2277 /* if fall through exits loop, goto is needed */
2278 if (!(bptr->next->lflags & HANDLER_PART)) {
2279 bptr->copied_to->iinstr[bptr->copied_to->icount].opc = ICMD_GOTO;
2280 bptr->copied_to->iinstr[bptr->copied_to->icount].dst = NULL;
2281 bptr->copied_to->iinstr[bptr->copied_to->icount].target = bptr->next;
2282 bptr->copied_to->icount++;
2287 /* copy_handler ****************************************************************
2289 This function copys the exception handler and redirects all jumps from the
2290 original head to the new head in the original exception handler. All
2291 redirection in the copied exception handler is done in patch_handler(...).
2293 *******************************************************************************/
2295 void copy_handler(methodinfo *m, loopdata *ld, struct LoopContainer *lc, basicblock *bptr, basicblock *original_head, basicblock *new_head)
2300 int high, low, count;
2301 struct LoopElement *le;
2302 basicblock *new, *temp;
2304 /* If this node has already been copied, return */
2305 if (bptr->lflags & HANDLER_PART)
2308 /* The exception handler exists, when control flow enters loop again */
2310 if (bptr->lflags & LOOP_PART)
2312 for (le = lc->nodes; le != NULL; le = le->next) {
2313 if (le->block == bptr) {
2314 printf("C_PANIC: should not happen\n");
2319 /* mark block as part of handler */
2320 bptr->lflags |= HANDLER_PART;
2323 new = DMNEW(basicblock, 1);
2324 memcpy(new, bptr, sizeof(basicblock));
2325 new->debug_nr = m->c_debug_nr++;
2327 ld->c_last_block_copied = new;
2329 /* copy instructions and allow one more slot for possible GOTO */
2330 new->iinstr = DMNEW(instruction, bptr->icount + 1);
2331 memcpy(new->iinstr, bptr->iinstr, bptr->icount * sizeof(instruction));
2333 /* update original block */
2334 bptr->copied_to = new;
2336 /* append block to global list of basic blocks */
2337 temp = m->basicblocks;
2346 /* find next block to copy, depending on last instruction of BB */
2347 if (bptr->icount == 0) {
2348 copy_handler(m, ld, lc, bptr->next, original_head, new_head);
2352 ip = bptr->iinstr + (bptr->icount - 1);
2371 case ICMD_IF_LCMPEQ:
2372 case ICMD_IF_LCMPLT:
2373 case ICMD_IF_LCMPLE:
2374 case ICMD_IF_LCMPNE:
2375 case ICMD_IF_LCMPGT:
2376 case ICMD_IF_LCMPGE:
2386 case ICMD_IFNONNULL:
2388 case ICMD_IF_ICMPEQ:
2389 case ICMD_IF_ICMPNE:
2390 case ICMD_IF_ICMPLT:
2391 case ICMD_IF_ICMPGE:
2392 case ICMD_IF_ICMPGT:
2393 case ICMD_IF_ICMPLE:
2394 case ICMD_IF_ACMPEQ:
2395 case ICMD_IF_ACMPNE:
2396 copy_handler(m, ld, lc, bptr->next, original_head, new_head);
2401 /* redirect jump from original_head to new_head */
2402 if ((basicblock *) ip->target == original_head)
2403 ip->target = (void *) new_head;
2405 copy_handler(m, ld, lc, (basicblock *) (ip->target), original_head, new_head);
2409 case ICMD_TABLESWITCH:
2411 tptr = (void **) ip->target;
2413 /* default branch */
2414 if (((basicblock *) *tptr) == original_head)
2415 tptr[0] = (void *) new_head;
2417 copy_handler(m, ld, lc, (basicblock *) *tptr, original_head, new_head);
2424 count = (high-low+1);
2426 while (--count >= 0) {
2428 /* redirect jump from original_head to new_head */
2429 if (((basicblock *) *tptr) == original_head)
2430 tptr[0] = (void *) new_head;
2431 copy_handler(m, ld, lc, (basicblock *) *tptr, original_head, new_head);
2435 case ICMD_LOOKUPSWITCH:
2437 tptr = (void **) ip->target;
2439 /* default branch */
2440 if (((basicblock *) *tptr) == original_head)
2441 tptr[0] = (void *) new_head;
2443 copy_handler(m, ld, lc, (basicblock *) *tptr, original_head, new_head);
2448 while (--count >= 0) {
2450 /* redirect jump from original_head to new_head */
2451 if (((basicblock *) *tptr) == original_head)
2452 tptr[0] = (void *) new_head;
2453 copy_handler(m, ld, lc, (basicblock *) *tptr, original_head, new_head);
2458 ld->c_last_target = bptr;
2459 copy_handler(m, ld, lc, (basicblock *) (ip->target), original_head, new_head);
2463 copy_handler(m, ld, lc, ld->c_last_target->next, original_head, new_head);
2467 copy_handler(m, ld, lc, bptr->next, original_head, new_head);
2473 /* If a loop is duplicated, all exceptions, that are contained in this loops' body
2474 have to be duplicated as well. The following function together with the
2475 two helper functions copy_handler and patch_handler perform this task.
2478 void update_internal_exceptions(methodinfo *m, codegendata *cd, loopdata *ld, struct LoopContainer *lc, basicblock *original_head, basicblock *new_head)
2480 exceptiontable *ex, *new;
2481 struct LoopContainer *l;
2483 /* Bottom of tree reached -> return */
2487 /* Call update_internal for all nested (=child) loops */
2490 update_internal_exceptions(m, cd, ld, l, original_head, new_head);
2494 /* For all exceptions of this loop, do */
2495 ex = lc->exceptions;
2496 while (ex != NULL) {
2498 /* Copy the exception and patch the jumps */
2499 copy_handler(m, ld, lc, ex->handler, original_head, new_head);
2500 patch_handler(lc, ex->handler, original_head, new_head);
2502 /* Insert a new exception into the global exception table */
2503 new = DNEW(exceptiontable);
2504 memcpy(new, ex, sizeof(exceptiontable));
2506 /* Increase number of exceptions */
2507 ++cd->exceptiontablelength;
2512 /* Set new start and end point of this exception */
2513 new->start = ex->start->copied_to;
2514 new->end = ex->end->copied_to;
2516 /* Set handler pointer to copied exception handler */
2517 new->handler = ex->handler->copied_to;
2525 /* If a loop is duplicated, all exceptions that contain this loop have to be
2526 extended to the copied nodes as well. The following function checks for
2527 all exceptions of all parent loops, whether they contain the loop pointed to
2528 by lc. If so, the exceptions are extended to contain all newly created nodes.
2531 void update_external_exceptions(methodinfo *m, codegendata *cd, loopdata *ld, struct LoopContainer *lc, int loop_head)
2533 exceptiontable *ex, *new;
2535 /* Top of tree reached -> return */
2539 ex = lc->exceptions;
2541 /* For all exceptions of this loop do */
2542 while (ex != NULL) {
2544 /* It is possible that the loop contains exceptions that do not protect */
2545 /* the loop just duplicated. It must be checked, if this is the case */
2546 if ((loop_head >= m->basicblockindex[ex->startpc]) && (loop_head < m->basicblockindex[ex->endpc])) {
2548 /* loop is really inside exception, so create new exception entry */
2549 /* in global exception list */
2550 new = DNEW(exceptiontable);
2551 memcpy(new, ex, sizeof(exceptiontable));
2554 /* Increase number of exceptions */
2555 ++cd->exceptiontablelength;
2560 /* Set new start and end point of this exception */
2561 new->start = ld->c_first_block_copied;
2562 new->end = ld->c_last_block_copied;
2566 /* exception does not contain the duplicated loop -> do nothing */
2571 /* Call update_external for parent node */
2572 update_external_exceptions(m, cd, ld, lc->parent, loop_head);
2576 /* This function is needed to insert the static checks, stored in c_constraints
2577 into the intermediate code.
2580 void create_static_checks(methodinfo *m, codegendata *cd, loopdata *ld, struct LoopContainer *lc)
2582 int i, stackdepth, cnt;
2583 struct Constraint *tc1;
2584 struct LoopElement *le;
2586 /* loop_head points to the newly inserted loop_head, original_start to */
2587 /* the old loop header */
2588 basicblock *bptr, *loop_head, *original_start, *temp;
2589 instruction *inst, *tiptr;
2591 /* tos and newstack are needed by the macros, that insert instructions into */
2592 /* the new loop head */
2593 stackptr newstack, tos;
2596 /* prevent some compiler warnings */
2600 #ifdef ENABLE_STATISTICS
2601 /* show_loop_statistics(l); */
2604 loop_head = &m->basicblocks[ld->c_current_head];
2605 ld->c_first_block_copied = ld->c_last_block_copied = NULL;
2607 /* the loop nodes are copied */
2611 bptr = DMNEW(basicblock, 1);
2612 memcpy(bptr, le->block, sizeof(basicblock));
2613 bptr->debug_nr = m->c_debug_nr++;
2615 /* determine beginning of copied loop to extend exception handler, that */
2616 /* protect this loop */
2617 if (ld->c_first_block_copied == NULL)
2618 ld->c_first_block_copied = bptr;
2620 /* copy instructions and add one more slot for possible GOTO */
2621 bptr->iinstr = DMNEW(instruction, bptr->icount + 1);
2623 memcpy(bptr->iinstr, le->block->iinstr, (bptr->icount+1)*sizeof(instruction));
2625 le->block->copied_to = bptr;
2627 /* add block to global list of BBs */
2628 temp = m->basicblocks;
2636 node_into_parent_loops(ld, lc->parent, bptr);
2640 ld->c_last_block_copied = bptr;
2642 /* create an additional basicblock for dynamic checks */
2643 original_start = bptr = DMNEW(basicblock, 1);
2645 /* copy current loop header to new basic block */
2646 memcpy(bptr, loop_head, sizeof(basicblock));
2647 bptr->debug_nr = m->c_debug_nr++;
2649 /* insert the new basic block and move header before first loop node */
2653 /* if header is first node of loop, insert original header after it */
2654 if (temp == loop_head)
2655 loop_head->next = bptr;
2657 /* else, we have to find the predecessor of loop header */
2658 while (temp->next != loop_head)
2661 /* insert original header after newly created block */
2664 /* if predecessor is not loop part, insert a goto */
2665 if (!(temp->lflags & LOOP_PART)) {
2667 /* copy instructions and add an additional slot */
2668 tiptr = DMNEW(instruction, temp->icount + 1);
2669 memcpy(tiptr, temp->iinstr, sizeof(instruction)*temp->icount);
2671 temp->iinstr = tiptr;
2672 tiptr = temp->iinstr + temp->icount;
2674 /* add goto to loop header. If node is part of exception handler */
2675 /* jmp is automagically redirected during patch_handler and works */
2677 tiptr->opc = ICMD_GOTO;
2679 tiptr->target = (void*) loop_head;
2685 temp = m->basicblocks;
2686 /* if first loop block is first BB of global list, insert loop_head at */
2687 /* beginning of global BB list */
2688 if (temp == le->block) {
2689 if (ld->c_newstart == NULL) {
2690 ld->c_needs_redirection = true;
2691 ld->c_newstart = loop_head;
2692 loop_head->next = m->basicblocks;
2695 loop_head->next = ld->c_newstart;
2696 ld->c_newstart = loop_head;
2701 while (temp->next != le->block)
2704 loop_head->next = temp->next;
2705 temp->next = loop_head;
2707 /* to be on the safe side insert a jump from the previous instr */
2708 /* over thr new inserted node */
2710 /* special case - jump from node to loop_head: then remove */
2711 /* goto / happens rather often due to loop layout */
2712 tiptr = temp->iinstr + (temp->icount-1);
2714 if ((tiptr->opc == ICMD_GOTO) && (tiptr->target == loop_head)) {
2715 tiptr->opc = ICMD_NOP;
2720 tiptr = DMNEW(instruction, temp->icount + 1);
2721 memcpy(tiptr, temp->iinstr, sizeof(instruction)*temp->icount);
2723 temp->iinstr = tiptr;
2724 tiptr = temp->iinstr + temp->icount;
2726 tiptr->opc = ICMD_GOTO;
2728 tiptr->target = (void*) loop_head->next;
2735 /* adjust exceptions */
2736 ex = cd->exceptiontable;
2737 while (ex != NULL) {
2739 /* if an exception covers whole loop and starts at first loop node, it */
2740 /* has to be extended to cover the new first node as well */
2741 if (ex->start == le->block) {
2743 if ((lc->loop_head >= m->basicblockindex[ex->startpc]) && (lc->loop_head < m->basicblockindex[ex->endpc]))
2744 ex->start = loop_head;
2747 /* an exception that ended at the old loop header now must contains the */
2748 /* new loop header as well */
2749 if (ex->end == loop_head)
2750 ex->end = original_start;
2756 /* insert new header node into nodelists of all enclosing loops */
2757 header_into_parent_loops(ld, lc, loop_head, original_start, le->block);
2759 /* prepare instruction array to insert checks */
2760 inst = loop_head->iinstr = DMNEW(instruction, ld->c_needed_instr + 2);
2761 loop_head->icount = ld->c_needed_instr + 1;
2763 /* init instruction array */
2764 for (cnt=0; cnt<ld->c_needed_instr + 1; ++cnt) {
2765 inst[0].opc = ICMD_NOP;
2769 loop_head->copied_to = NULL;
2772 loop_head->instack = copy_stack_from(bptr->instack);
2773 loop_head->outstack = copy_stack_from(bptr->instack);
2775 tos = loop_head->instack;
2776 stackdepth = loop_head->indepth;
2778 /* step through all inserted checks and create instructions for them */
2779 for (i=0; i<cd->maxlocals+1; ++i)
2781 tc1 = ld->c_constraints[i];
2787 /* check a variable against a constant */
2789 case TEST_UNMOD_ZERO:
2792 printf("insert ZERO-test\n");
2796 /* optimize if tc1->varRef >= tc1->constant */
2797 LOAD_VAR(tc1->varRef);
2798 LOAD_CONST(tc1->constant);
2802 /* check a variable against an array length */
2804 case TEST_UNMOD_ALENGTH:
2807 /* tc1->varRef + tc1->constant < lengthOf(tc1->arrayRef) */
2809 printf("insert ALENGTH-test\n");
2813 LOAD_VAR(tc1->varRef);
2814 LOAD_CONST(tc1->constant);
2816 LOAD_ARRAYLENGTH(tc1->arrayRef);
2820 /* test right side of comparison against constant */
2824 printf("insert RS-ZERO-test\n");
2828 /* optimize if right-side >= tc1->constant */
2830 LOAD_CONST(tc1->constant);
2834 /* test right side of comparison against array length */
2835 case TEST_RS_ALENGTH:
2838 printf("insert RS-ALENGTH-test\n");
2841 /* optimize if right-side < lengthOf(arrayRef) */
2843 LOAD_ARRAYLENGTH(tc1->arrayRef);
2847 /* test unmodified variable against arraylength */
2848 case TEST_CONST_ALENGTH:
2851 printf("insert CONST ALENGTH-test\n");
2855 /* optimize if tc1->constant < lengthOf(tc1->arrayRef) */
2856 LOAD_CONST(tc1->constant);
2857 LOAD_ARRAYLENGTH(tc1->arrayRef);
2864 ld->c_constraints[i] = NULL;
2867 /* if all tests succeed, jump to optimized loop header */
2868 if (loop_head->next != original_start) {
2869 inst->opc = ICMD_GOTO;
2871 inst->target = original_start;
2874 /* redirect jumps from original loop head to newly inserted one */
2875 patch_jumps(original_start, loop_head, lc);
2877 /* if exceptions have to be correct due to loop duplication these two */
2878 /* functions perform this task. */
2879 update_internal_exceptions(m, cd, ld, lc, loop_head, original_start);
2880 update_external_exceptions(m, cd, ld, lc->parent, lc->loop_head);
2884 /* This function performs an update between two arrays of struct Changes (that
2885 reflect variable changes). The merge is performed unrstricted in the way, that
2886 all variable changes in c1 took place in a nested loop and therefore are
2887 considered to be without limit. Beside that, the merge is a simple union of the
2888 changes recorded in both arrays. A variable, which limits are undefinied, is
2889 represented by its lower bound being higher than the upper bound. The result
2890 of the union is stored in c1.
2892 struct Changes ** constraints_unrestricted_merge(codegendata *cd, struct Changes **c1, struct Changes **c2)
2896 if ((c1 == NULL) || (c2 == NULL))
2897 printf("C_ERROR: debugging error 0x03\n");
2900 for (i=0; i<cd->maxlocals; ++i) {
2901 if (c1[i] == NULL) {
2902 if (c2[i] != NULL) { /* a change in c2 is updated in c1 */
2905 c1[i]->lower_bound = c1[i]->upper_bound+1;
2909 if (c1[i]->lower_bound > c1[i]->upper_bound)
2910 continue; /* variable's bounds already undefined */
2912 if (c2[i] == NULL) { /* variable changed in c1 -> now undef. */
2914 c1[i]->lower_bound = c1[i]->upper_bound+1;
2917 if ((c1[i]->lower_bound == c2[i]->lower_bound) &&
2918 (c1[i]->upper_bound == c2[i]->upper_bound))
2919 continue; /* variable's bounds remain the same */
2922 c1[i]->lower_bound = c1[i]->upper_bound+1;
2923 } /* variable changed in c1 -> now undef. */
2934 /* This function performs an update between two arrays of struct Changes (that
2935 reflect variable changes). The merge is a simple union of the bounds
2936 changes recorded in both arrays. A variable, which limits are undefinied, is
2937 represented by its lower bound being higher than the upper bound. The result
2938 of the union is stored in c1.
2940 struct Changes ** constraints_merge(codegendata *cd, struct Changes **c1, struct Changes **c2)
2944 if ((c1 == NULL) || (c2 == NULL))
2945 printf("C_ERROR: debugging error 0x04\n");
2949 for (i=0; i<cd->maxlocals; ++i) {
2950 if (c1[i] == NULL) {
2951 if (c2[i] != NULL) { /* update changes in c2 in c1 */
2952 if ((c1[i] = (struct Changes *) malloc (sizeof(struct Changes))) == NULL)
2955 c1[i]->lower_bound = c2[i]->lower_bound;
2956 c1[i]->upper_bound = c2[i]->upper_bound;
2961 if (c2[i] != NULL) {
2963 if (c1[i]->lower_bound > c1[i]->upper_bound)
2964 continue; /* var in c1 is unrestricted */
2966 if (c1[i]->lower_bound > c2[i]->lower_bound) {
2967 c1[i]->lower_bound = c2[i]->lower_bound;
2968 changed = 1; /* write new lower bound */
2970 if (c1[i]->upper_bound < c2[i]->upper_bound) {
2971 c1[i]->upper_bound = c2[i]->upper_bound;
2972 changed = 1; /* write new higher bound */
2985 /* This function simply copies an array of changes
2987 struct Changes** constraints_clone(codegendata *cd, struct Changes **c)
2992 if ((t = (struct Changes **) malloc(cd->maxlocals * sizeof(struct Changes *))) == NULL)
2995 for (i=0; i<cd->maxlocals; ++i) { /* for all array elements (vars) do */
2999 if ((t[i] = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
3001 t[i]->lower_bound = c[i]->lower_bound;
3002 t[i]->upper_bound = c[i]->upper_bound;
3009 /* This function is used to reset the changes of a variable to the time, it was
3010 pushed onto the stack. If a variable has been modified between an instruction
3011 and a previous push onto the stack, its value in the changes array does not
3012 correctly reflect its bounds the time, it was pushed onto the stack. This
3013 function corrects the situation.
3015 struct Changes* backtrack_var(methodinfo *m, int node, int from, int to, int varRef, struct Changes *changes)
3017 struct Changes *tmp;
3022 if (changes == NULL) /* if there are no changes, immediately return */
3024 else { /* init a Changes structure with current values */
3025 if ((tmp = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
3028 tmp->upper_bound = changes->upper_bound;
3029 tmp->lower_bound = changes->lower_bound;
3032 if (tmp->upper_bound < tmp->lower_bound)
3033 return tmp; /* if it is unrestricted no backtracking can happen */
3035 bp = m->basicblocks[node];
3036 ip = bp.iinstr + to;
3038 for (; from < to; --to, --ip) { /* scan instructions backwards */
3040 case ICMD_IINC: /* a var has been modified */
3041 if (varRef != ip->op1) /* not the one, we are interested in */
3043 tmp->upper_bound -= ip->val.i; /* take back modifications */
3044 tmp->lower_bound -= ip->val.i;
3047 case ICMD_ISTORE: /* a var has been modified */
3048 if (varRef != ip->op1) /* not the one, we are interested in */
3051 /* it is our variable, so trace its origin */
3052 t = tracing(&m->basicblocks[node],to, 0);
3056 if ((t->var = ip->op1) && (t->neg > 0)) {
3057 /* it was the same var -> take back modifications */
3058 tmp->upper_bound -= t->constant;
3059 tmp->lower_bound -= t->constant;
3062 tmp->lower_bound = tmp->upper_bound+1; /* unknown */
3065 /* cannot restore it -> invalidate t */
3070 tmp->lower_bound = tmp->upper_bound+1;
3081 /* This function performs the main task of bound check removal. It removes
3082 all bound-checks in node. change is a pointer to an array of struct Changes
3083 that reflect for all local variables, how their values have changed from
3084 the start of the loop. The special flag is needed to deal with the header
3088 void remove_boundchecks(methodinfo *m, codegendata *cd, loopdata *ld, int node, int from, struct Changes **change, int special)
3092 int i, count, ignore, degrade_checks, opt_level;
3093 struct depthElement *d;
3094 struct Changes **t1, **tmp, *t;
3095 struct Trace *t_array, *t_index;
3097 /* prevent some compiler warnings */
3102 /* printf("remove_bc called: %d - %d - %d\n", node, from, special); */
3104 /* a flag, that is set, when previous optimzations have to be taken back */
3107 if (ld->c_current_loop[node] > 0) { /* this node is part of the loop */
3108 if (ld->c_current_loop[node] > 1) { /* it is not the header node */
3110 /* get variable changes, already recorded for this node */
3111 t1 = ld->c_dTable[node]->changes;
3113 if (t1 != NULL) { /* it is not the first visit */
3114 if ((ld->c_nestedLoops[node] != ld->c_current_head) && (ld->c_nestedLoops[node] == ld->c_nestedLoops[from])) {
3115 /* we are looping in a nested loop, so made optimizations */
3116 /* need to be reconsidered */
3118 if (constraints_unrestricted_merge(cd, t1, change) == NULL)
3119 return; /* no changes since previous visit */
3120 /* if there have been changes, they are updated by */
3121 /* constraints_unrestricted_merge in t1 */
3124 if (constraints_merge(cd, t1, change) == NULL)
3125 return; /* no changes since previous visit */
3126 /* if there have been changes, they are updated by */
3127 /* constraints_merge in t1 */
3130 else { /* first visit */
3131 /* printf("first visit - constraints cloned\n"); */
3132 ld->c_dTable[node]->changes = constraints_clone(cd, change);
3135 /* tmp now holds a copy of the updated variable changes */
3136 tmp = constraints_clone(cd, ld->c_dTable[node]->changes);
3138 else if (special) { /* header and need special traetment */
3139 /* printf("special treatment called\n"); */
3140 /* tmp now holds a copy of the current new variable changes */
3141 tmp = constraints_clone(cd, change);
3146 bp = m->basicblocks[node]; /* scan all instructions */
3151 for (i=0; i<count; ++i, ++ip) {
3153 case ICMD_IASTORE: /* found an array store */
3162 t_index = tracing(&bp, i-1, 1); /* get index */
3163 t_array = tracing(&bp, i-1, 2); /* get array refernce */
3167 case ICMD_IALOAD: /* found an array load */
3176 t_index = tracing(&bp, i-1, 0); /* get index */
3177 t_array = tracing(&bp, i-1, 1); /* get array refernce */
3181 /* printf("Array access with params:\n");
3183 show_trace(t_array);
3185 show_trace(t_index);
3188 #ifdef ENABLE_STATISTICS
3189 if (ip->op1 == OPT_UNCHECKED) { /* found new access */
3190 ld->c_stat_array_accesses++;
3192 ld->c_stat_no_opt++;
3196 /* can only optimize known arrays that do not change */
3197 if ((t_array->type != TRACE_AVAR) || (ld->c_var_modified[t_array->var]))
3200 switch (t_index->type) { /* now we look at the index */
3201 case TRACE_ICONST: /* it is a constant value or an */
3202 case TRACE_ALENGTH: /* array length */
3203 #ifdef ENABLE_STATISTICS
3204 switch (ip->op1) { /* take back old optimzation */
3208 ld->c_stat_no_opt--;
3211 ld->c_stat_full_opt--;
3214 ld->c_stat_upper_opt--;
3217 ld->c_stat_lower_opt--;
3221 if (degrade_checks) /* replace existing optimization */
3222 ip->op1 = insert_static(m, cd, ld, t_array->var, t_index, NULL, special);
3224 /* Check current optimization and try to improve it by */
3225 /* inserting new checks */
3228 ip->op1 = insert_static(m, cd, ld, t_array->var, t_index, NULL, special);
3231 ip->op1 = insert_static(m, cd, ld, t_array->var, t_index, NULL, special);
3234 opt_level = insert_static(m, cd, ld, t_array->var, t_index, NULL, special);
3235 if ((opt_level == OPT_FULL) || (opt_level == OPT_LOWER))
3239 opt_level = insert_static(m, cd, ld, t_array->var, t_index, NULL, special);
3240 if ((opt_level == OPT_FULL) || (opt_level == OPT_UPPER))
3244 #ifdef ENABLE_STATISTICS
3245 ld->c_stat_full_opt++;
3252 case TRACE_IVAR: /* it's a variable */
3254 /* if the variable is changed between its usage as an index */
3255 /* of the array access and its push onto the stack, we have */
3256 /* to set the changes back to the time, it is pushed onto */
3257 /* the stack as an index variable. */
3258 t = backtrack_var(m, node, t_index->nr, i-1, t_index->var, tmp[t_index->var]);
3259 #ifdef ENABLE_STATISTICS
3260 switch (ip->op1) { /* take back old optimzation */
3264 ld->c_stat_no_opt--;
3267 ld->c_stat_full_opt--;
3270 ld->c_stat_upper_opt--;
3273 ld->c_stat_lower_opt--;
3278 ip->op1 = insert_static(m, cd, ld, t_array->var, t_index, t, special);
3280 /* Check current optimization and try to improve it by */
3281 /* insert new check. t reflects var changes for index */
3284 ip->op1 = insert_static(m, cd, ld, t_array->var, t_index, t, special);
3287 ip->op1 = insert_static(m, cd, ld, t_array->var, t_index, t, special);
3290 opt_level = insert_static(m, cd, ld, t_array->var, t_index, t, special);
3291 if ((opt_level == OPT_FULL) || (opt_level == OPT_LOWER))
3295 opt_level = insert_static(m, cd, ld, t_array->var, t_index, t, special);
3296 if ((opt_level == OPT_FULL) || (opt_level == OPT_UPPER))
3300 #ifdef ENABLE_STATISTICS
3301 ld->c_stat_full_opt++;
3314 case ICMD_ISTORE: /* an integer value is stored */
3315 t_index = tracing(&bp, i-1, 0); /* trace back its origin */
3317 /* the struct Changes for this variable needs to be updated */
3319 if (t == NULL) { /* if it's the first one, create new entry */
3320 if ((t = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
3322 t->upper_bound = t->lower_bound = 0;
3326 switch (t_index->type) { /* check origin of store */
3328 case TRACE_ICONST: /* constant -> set bounds to const value */
3329 t->upper_bound = t->lower_bound = t_index->constant;
3332 case TRACE_IVAR: /* if it's the same variable, update consts */
3333 if ((t_index->var = ip->op1) && (t_index->neg > 0)) {
3334 t->upper_bound += t_index->constant;
3335 t->lower_bound += t_index->constant;
3338 t->lower_bound = t->upper_bound+1;
3341 case TRACE_ALENGTH: /* else -> unknown */
3344 t->lower_bound = t->upper_bound+1;
3352 /* the struct Changes for this variable needs to be updated */
3353 if ((t = tmp[ip->op1]) == NULL) { /* first one -> create new */
3354 if ((t = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
3356 t->upper_bound = t->lower_bound = ip->val.i;
3359 else { /* update changes, made by iinc */
3360 t->upper_bound += ip->val.i;
3361 t->lower_bound += ip->val.i;
3367 if (!special) { /* we are not interested in only the header */
3368 d = ld->c_dTable[node];
3369 while (d != NULL) { /* check all sucessors of current node */
3370 remove_boundchecks(m, cd, ld, d->value, node, tmp, special);
3378 /* This function calls the bound-check removal function for the header node
3379 with a special flag. It is important to notice, that no dynamic
3380 constraint hold in the header node (because the comparison is done at
3384 void remove_header_boundchecks(methodinfo *m, codegendata *cd, loopdata *ld, int node, struct Changes **changes)
3386 remove_boundchecks(m, cd, ld, node, -1, changes, BOUNDCHECK_SPECIAL);
3390 /* Marks all basicblocks that are part of the loop
3393 void mark_loop_nodes(struct LoopContainer *lc)
3395 struct LoopElement *le = lc->nodes;
3397 while (le != NULL) {
3398 le->block->lflags |= LOOP_PART;
3404 /* Clears mark for all basicblocks that are part of the loop
3406 void unmark_loop_nodes(LoopContainer *lc)
3408 LoopElement *le = lc->nodes;
3410 while (le != NULL) {
3411 le->block->lflags = 0;
3417 /* This function performs the analysis of code in detected loops and trys to
3418 identify array accesses suitable for optimization (bound check removal). The
3419 intermediate code is then modified to reflect these optimizations.
3421 void optimize_single_loop(methodinfo *m, codegendata *cd, loopdata *ld, LoopContainer *lc)
3423 struct LoopElement *le;
3424 struct depthElement *d;
3426 struct Changes **changes;
3428 if ((changes = (struct Changes **) malloc(cd->maxlocals * sizeof(struct Changes *))) == NULL)
3431 head = ld->c_current_head = lc->loop_head;
3432 ld->c_needed_instr = ld->c_rs_needed_instr = 0;
3434 /* init array for null ptr checks */
3435 for (i=0; i<cd->maxlocals; ++i)
3436 ld->c_null_check[i] = 0;
3439 /* don't optimize root node (it is the main procedure, not a loop) */
3443 /* setup variables with initial values */
3444 ld->c_loopvars = NULL;
3445 for (i=0; i < m->basicblockcount; ++i) {
3446 ld->c_toVisit[i] = 0;
3447 ld->c_current_loop[i] = -1;
3448 if ((d = ld->c_dTable[i]) != NULL)
3452 for (i=0; i < cd->maxlocals; ++i) {
3453 ld->c_var_modified[i] = 0;
3454 if (changes[i] != NULL) {
3459 for (i=0; i < (cd->maxlocals+1); ++i) {
3460 if (ld->c_constraints[i] != NULL) {
3461 ld->c_constraints[i] = NULL;
3466 while (le != NULL) {
3470 ld->c_current_loop[node] = 1; /* the header node gets 1 */
3471 else if (ld->c_nestedLoops[node] == head)
3472 ld->c_current_loop[node] = 2; /* top level nodes get 2 */
3474 ld->c_current_loop[node] = 3; /* nodes, part of nested loop get 3 */
3476 ld->c_toVisit[node] = 1;
3480 /* After setup work has been performed, start to analyse */
3482 printf("****** Starting analysis (%d)******\n", head);
3486 if (analyze_for_array_access(m, ld, head) > 0) {/* loop contains array access */
3491 printf("analyze for array access finished and found\n");
3493 lv = ld->c_loopvars;
3494 while (lv != NULL) {
3496 printf("Var --> %d\n", lv->value);
3501 /* for performance reasons the list of all interesting loop vars is */
3502 /* scaned and for all modified vars a flag in c_var_modified is set */
3503 scan_global_list(ld);
3506 printf("global list scanned\n");
3510 /* if the loop header contains or-conditions or an index variable */
3511 /* is modified in the catch-block within the loop, a conservative */
3512 /* approach is taken and optimizations are cancelled */
3513 if (analyze_or_exceptions(m, cd, ld, head, lc) > 0) {
3516 printf("Analyzed for or/exception - no problems \n");
3520 init_constraints(m, ld, head); /* analyze dynamic bounds in header */
3526 if (ld->c_rightside == NULL)
3529 /* single pass bound check removal - for all successors, do */
3530 remove_header_boundchecks(m, cd, ld, head, changes);
3532 d = ld->c_dTable[head];
3534 remove_boundchecks(m, cd, ld, d->value, -1, changes, BOUNDCHECK_REGULAR);
3539 printf("Array-bound checks finished\n");
3543 mark_loop_nodes(lc);
3546 printf("START: create static checks\n");
3550 create_static_checks(m, cd, ld, lc); /* create checks */
3553 printf("END: create static checks\n");
3556 unmark_loop_nodes(lc);
3560 printf("No array accesses found\n"); */
3562 #ifdef ENABLE_STATISTICS
3563 ld->c_stat_num_loops++; /* increase number of loops */
3565 ld->c_stat_sum_accesses += ld->c_stat_array_accesses;
3566 ld->c_stat_sum_full += ld->c_stat_full_opt;
3567 ld->c_stat_sum_no += ld->c_stat_no_opt;
3568 ld->c_stat_sum_lower += ld->c_stat_lower_opt;
3569 ld->c_stat_sum_upper += ld->c_stat_upper_opt;
3570 ld->c_stat_sum_or += ld->c_stat_or;
3571 ld->c_stat_sum_exception += ld->c_stat_exception;
3573 ld->c_stat_array_accesses = 0;
3574 ld->c_stat_full_opt = 0;
3575 ld->c_stat_no_opt = 0;
3576 ld->c_stat_lower_opt = 0;
3577 ld->c_stat_upper_opt = 0;
3578 ld->c_stat_or = ld->c_stat_exception = 0;
3584 /* This function preforms necessary setup work, before the recursive function
3585 optimize_single loop can be called.
3587 void optimize_loops(methodinfo *m, codegendata *cd, loopdata *ld)
3589 LoopContainer *lc = ld->c_allLoops;
3591 /* first, merge loops with same header node - all loops with the same */
3592 /* header node are optimizied in one pass, because they all depend on the */
3593 /* same dynamic loop condition */
3596 printf("start analyze_double_headers\n");
3600 analyze_double_headers(ld);
3602 /* create array with loop nesting levels - nested loops cause problems, */
3603 /* especially, when they modify index variables used in surrounding loops */
3604 /* store results in array c_nestedLoops and c_hierarchie */
3607 printf("double done\n");
3611 analyze_nested(m,cd, ld);
3614 printf("analyze nested done\n");
3618 /* create array with entries for current loop */
3619 ld->c_current_loop = DMNEW(int, m->basicblockcount);
3620 ld->c_toVisit = DMNEW(int, m->basicblockcount);
3621 ld->c_var_modified = DMNEW(int, cd->maxlocals);
3622 ld->c_null_check = DMNEW(int, cd->maxlocals);
3624 if ((ld->c_constraints = (struct Constraint **) malloc((cd->maxlocals+1) * sizeof(struct Constraint *))) == NULL)
3627 #ifdef ENABLE_STATISTICS
3628 ld->c_stat_num_loops = 0; /* set statistic vars to zero */
3629 ld->c_stat_array_accesses = ld->c_stat_sum_accesses = 0;
3630 ld->c_stat_full_opt = ld->c_stat_sum_full = 0;
3631 ld->c_stat_no_opt = ld->c_stat_sum_no = 0;
3632 ld->c_stat_lower_opt = ld->c_stat_sum_lower = 0;
3633 ld->c_stat_upper_opt = ld->c_stat_sum_upper = 0;
3634 ld->c_stat_or = ld->c_stat_sum_or = 0;
3635 ld->c_stat_exception = ld->c_stat_sum_exception = 0;
3638 /* init vars needed by all loops */
3639 ld->c_needs_redirection = false;
3640 ld->c_newstart = NULL;
3641 ld->c_old_xtablelength = cd->exceptiontablelength;
3643 /* loops have been topologically sorted */
3644 lc = ld->c_allLoops;
3645 while (lc != NULL) {
3646 optimize_single_loop(m, cd, ld, lc);
3649 printf(" *** Optimized loop *** \n");
3656 printf("---*** All loops finished ***---\n");
3660 /* if global BB list start is modified, set block to new start */
3661 if (ld->c_needs_redirection == true)
3662 m->basicblocks = ld->c_newstart;
3668 * These are local overrides for various environment variables in Emacs.
3669 * Please do not remove this and leave it at the end of the file, where
3670 * Emacs will automagically detect them.
3671 * ---------------------------------------------------------------------
3674 * indent-tabs-mode: t