1 /* jit/loop/analyze.c - bound check removal functions
3 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
4 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
5 M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
6 P. Tomsich, J. Wenninger
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 1203 2004-06-22 23:14:55Z twisti $
43 #include "jit/loop/analyze.h"
45 #include "jit/loop/loop.h"
46 #include "jit/loop/graph.h"
47 #include "jit/loop/tracing.h"
48 #include "toolbox/logging.h"
49 #include "toolbox/memory.h"
54 /* Test functions -> will be removed in final release
57 void show_trace(struct Trace *trace)
60 switch (trace->type) {
63 printf("\nNr.:\t%d", trace->var);
64 printf("\nValue:\t%d", trace->constant);
69 printf("\nNr.:\t%d", trace->var);
73 printf("array-length");
74 printf("\nNr.:\t%d", trace->var);
75 printf("\nValue:\t%d", trace->constant);
80 printf("\nValue:\t%d", trace->constant);
89 printf("Trace is null");
95 void show_change(struct Changes *c)
97 printf("*** Changes ***\n");
99 printf("Lower/Upper Bound:\t%d/%d\n", c->lower_bound, c->upper_bound);
101 printf("Unrestricted\n");
104 show_varinfo(struct LoopVar *lv)
106 printf(" *** Loop Info ***\n");
107 printf("Value:\t%d\n", lv->value);
108 printf("Static:\t\t%d/%d\n", lv->static_l, lv->static_u);
109 printf("D-Valid:\t%d/%d\n", lv->dynamic_l_v, lv->dynamic_u_v);
110 printf("Dynamic\t\t%d/%d\n", lv->dynamic_l, lv->dynamic_u);
113 void show_right_side()
116 printf("\n *** Head *** \nType:\t");
117 show_trace(c_rightside);
119 printf("\n *** Nested Loops: ***\n");
120 for (i=0; i<m->basicblockcount; ++i)
121 printf("%d\t", c_nestedLoops[i]);
124 printf("\n *** Hierarchie: ***\n");
125 for (i=0; i<m->basicblockcount; ++i)
126 printf("%d\t", c_hierarchie[i]);
130 printf("\n *** Current Loop ***\n");
131 for (i=0; i<m->basicblockcount; ++i)
132 printf("%d\t", c_current_loop[i]);
139 struct LoopContainer *lc = c_allLoops;
141 printf("\n\n****** PASS 3 ******\n\n");
144 printf("Loop Analysis:\n");
145 printf("Optimize:\t%d\n", lc->toOpt);
146 printf("Modified Vars: ");
148 for (i=0; i<lc->num_vars; ++i)
149 printf("%d ", lc->vars[i]);
155 printf("\nNested Loops:\n");
156 for (i=0; i<m->basicblockcount; ++i)
157 printf("%d ", c_nestedLoops[i]);
159 for (i=0; i<m->basicblockcount; ++i)
160 printf("%d ", c_hierarchie[i]);
165 void show_tree(struct LoopContainer *lc, int tabs)
170 for (cnt = 0; cnt < tabs; ++cnt)
172 printf("%d\n", lc->loop_head);
174 show_tree(lc->tree_down, tabs+1);
184 void show_loop_statistics()
186 printf("\n\n****** LOOP STATISTICS ****** \n\n");
188 printf("Optimization cancelled by or\n");
189 else if (c_stat_exception)
190 printf("Optimization cancelled by exception\n");
192 printf("Number of array accesses:\t%d\n", c_stat_array_accesses);
193 if (c_stat_array_accesses) {
194 printf("\nFully optimized:\t%d\n", c_stat_full_opt);
195 printf("Not optimized:\t\t%d\n", c_stat_no_opt);
196 printf("Upper optimized:\t%d\n", c_stat_upper_opt);
197 printf("Lower optimized:\t%d\n", c_stat_lower_opt);
202 void show_procedure_statistics()
204 printf("\n\n****** PROCEDURE STATISTICS ****** \n\n");
205 printf("Number of loops:\t\t%d\n", c_stat_num_loops);
206 printf("Number of array accesses:\t%d\n", c_stat_sum_accesses);
207 if (c_stat_sum_accesses) {
208 printf("\nFully optimized:\t%d\n", c_stat_sum_full);
209 printf("Not optimized:\t\t%d\n", c_stat_sum_no);
210 printf("Upper optimized:\t%d\n", c_stat_sum_upper);
211 printf("Lower optimized:\t%d\n", c_stat_sum_lower);
213 printf("Opt. cancelled by or:\t\t%d\n", c_stat_sum_or);
214 printf("Opt. cancelled by exception:\t%d\n", c_stat_sum_exception);
220 /* This function is used to merge two loops with the same header together.
221 A simple merge sort of the lists nodes of both loops is performed.
223 void analyze_merge(struct LoopContainer *l1, struct LoopContainer *l2)
225 struct LoopElement *start, *last, *le1, *le2;
226 /* start and last are pointers to the newly built list, le1 and le2 step */
227 /* step through the lists, that have to be merged. */
232 /* start a simple merge sort of the nodes of both loops. These lists are */
233 /* already sorted, so merging is easy. */
234 if (le1->node < le2->node) {
238 else if (le1->node == le2->node) {
248 /* while the first loop != NULL, depending of the first element of second */
249 /* loop, add new node to result list */
250 while (le1 != NULL) {
256 if (le1->node < le2->node) {
260 else if (le1->node == le2->node) {
277 /* This function is used to merge loops with the same header node to a single
278 one. O(n^2) of number of loops. This merginig is necessary, because the loop
279 finding algorith sometimes (eg. when loopbody ends with a if-else construct)
280 reports a single loop as two loops with the same header node.
282 void analyze_double_headers()
285 struct LoopContainer *t1, *t2, *t3;
289 while (t1 != NULL) { /* for all loops do */
290 toCheck = t1->loop_head; /* get header node */
293 while (t2 != NULL) { /* compare it to headers of rest */
294 if (t2->loop_head == toCheck) {
296 /* found overlapping loops -> merge them together */
297 /* printf("C_INFO: found overlapping loops - merging"); */
298 analyze_merge(t1, t2);
300 /* remove second loop from the list of all loops */
302 while (t3->next != t2)
314 /* After the hierarchie of loops has been built, we have to insert the exceptions
315 into this tree. The exception ex is inserted into the subtree pointed to by
318 void insert_exception(methodinfo *m, struct LoopContainer *lc, exceptiontable *ex)
320 struct LoopContainer *temp;
321 struct LoopElement *le;
324 /* printf("insert_exception called with %d-%d and loop %d\n", ex->start->debug_nr, ex->end->debug_nr, lc->loop_head); */
327 /* if child node is reached immediately insert exception into the tree */
328 if (lc->tree_down == NULL) {
329 ex->next = lc->exceptions;
333 /* if we are inside the tree, there are two possibilities: */
334 /* 1. the exception is inside a nested loop or */
335 /* 2. in the loop body of the current loop */
337 /* check all children (= nested loops) */
338 temp = lc->tree_down;
340 while (temp != NULL) {
346 printf("%d.%d\n", le->node, block_index[ex->startpc]);
348 /* if the start of the exception is part of the loop, the */
349 /* whole exception must be part of the loop */
350 if (le->node == m->basicblockindex[ex->startpc])
355 /* Exception is part of a nested loop (Case 1) -> insert it there */
357 insert_exception(m, temp, ex);
360 else if ((temp->loop_head >= m->basicblockindex[ex->startpc]) && (temp->loop_head < m->basicblockindex[ex->endpc])) {
362 /* optimization: if nested loop is part of the exception, the */
363 /* exception cannot be part of a differnet nested loop. */
364 ex->next = lc->exceptions;
369 temp = temp->tree_right;
372 /* Exception is not contained in any nested loop (Case 2) */
374 ex->next = lc->exceptions;
381 /* This function builds a loop hierarchie. The header node of the innermost loop,
382 each basic block belongs to, is stored in the array c_nestedLoops. The array
383 c_hierarchie stores the relationship between differnt loops in as follows:
384 Each loop, that is a nested loop, stores its direct surrounding loop as a
385 parent. Top level loops have no parents.
387 void analyze_nested(methodinfo *m)
389 /* i/count/tmp are counters */
390 /* toOverwrite is used while loop hierarchie is built (see below) */
391 int i, header, toOverwrite, tmp, len;
393 /* first/last are used during topological sort to build ordered loop list */
394 struct LoopContainer *first, *last, *start, *t, *temp;
396 /* Used to step through all nodes of a loop. */
397 struct LoopElement *le;
399 /* init global structures */
400 c_nestedLoops = DMNEW(int, m->basicblockcount);
401 c_hierarchie = DMNEW(int, m->basicblockcount);
402 for (i=0; i<m->basicblockcount; ++i) {
403 c_nestedLoops[i] = -1;
404 c_hierarchie[i] = -1;
407 /* if there are no optimizable loops -> return */
408 if (c_allLoops == NULL)
412 while (temp != NULL) { /* for all loops, do */
413 header = temp->loop_head;
415 /* toOverwrite is number of current parent loop (-1 if none) */
416 toOverwrite = c_nestedLoops[header];
418 c_hierarchie[header] = toOverwrite;
420 if (toOverwrite == header) /* check for loops with same header */
421 printf("C_ERROR: Loops have same header\n");
424 while (le != NULL) { /* for all loop nodes, do */
425 tmp = c_nestedLoops[le->node];
427 /* if node is part of parent loop -> overwrite it with nested */
428 if (tmp == toOverwrite)
429 c_nestedLoops[le->node] = header;
431 c_hierarchie[tmp] = header;
433 /* printf("set head of %d to %d", tmp, header); */
443 /* init root of hierarchie tree */
444 root = DMNEW(struct LoopContainer, 1);
445 LoopContainerInit(m, root, -1);
447 /* obtain parent pointer and build hierarchie tree */
449 while (start != NULL) {
451 /* look for parent of loop pointed at by start */
453 while (first != NULL) {
455 /* the parent of the loop, pointed at by start has been found */
456 if (first->loop_head == c_hierarchie[start->loop_head]) {
458 /* printf("set parent to pointer\n"); */
461 start->parent = first;
462 start->tree_right = first->tree_down;
463 first->tree_down = start;
470 /* no parent loop found, set parent to root */
473 /* printf("set parent to root\n"); */
476 start->parent = root;
477 start->tree_right = root->tree_down;
478 root->tree_down = start;
480 /* if a parent exists, increase this nodes indegree */
482 start->parent->in_degree += 1;
487 /* insert exceptions into tree */
489 printf("--- Showing tree ---\n");
491 printf(" --- End ---\n");
493 for (len = 0; len < m->exceptiontablelength; ++len)
494 insert_exception(m, root, m->exceptiontable + len);
497 /* determine sequence of loops for optimization by topological sort */
502 while (temp != NULL) {
504 /* a loops with indegree == 0 are pushed onto the stack */
505 if (temp->in_degree == 0) {
517 first = last = start;
521 printf("C_ERROR: loops are looped\n");
525 /* pop each node from the stack and decrease its parents indegree by one */
526 /* when the parents indegree reaches zero, push it onto the stack as well */
527 if ((last->parent != root) && (--last->parent->in_degree == 0)) {
528 last->parent->next = start;
529 start = last->parent;
531 while (start != NULL) {
538 if ((last->parent != root) && (--last->parent->in_degree == 0)) {
539 last->parent->next = start;
540 start = last->parent;
548 printf("*** Hierarchie Results \n");
549 while (first != NULL) {
550 printf("%d ", first->loop_head);
558 /* This function is used to add variables that occur as index variables in
559 array accesses (ARRAY_INDEX) or as variables, that change their value (VAR_MOD)
560 to the list of interesting vars (c_loopvars) for the current loop.
562 void add_to_vars(int var, int type, int direction)
566 /* printf("Added to vars %d %d %d\n", var, type, direction); */
568 while (lv != NULL) { /* check if var has been previously added */
569 if (lv->value == var) {
570 if (type == ARRAY_INDEX)
571 lv->index = 1; /* var is used as index */
572 else if (type == VAR_MOD) {
573 lv->modified = 1; /* var is used in assignment */
574 switch (direction) { /* how was var modified ? */
576 lv->static_u = 0; /* incremented, no static upper */
577 break; /* bound can be guaranteeed */
579 lv->static_l = 0; /* decremented, no static lower */
580 break; /* bound can be guaranteeed */
582 lv->static_u = lv->static_l = 0;
583 break; /* no info at all */
585 printf("C_ERROR: unknown direction\n");
594 /* variable is not found in list -> add variable to list */
595 lv = DNEW(struct LoopVar);
597 lv->modified = lv->index = 0;
600 if (type == ARRAY_INDEX) {
602 lv->static_u = lv->static_l = 1; /* arrayindex -> var not modified */
604 else if (type == VAR_MOD) {
606 switch (direction) { /* var used in assignment -> set */
607 case D_UP: /* proper static bounds */
608 lv->static_u = 0; lv->static_l = 1;
611 lv->static_u = 1; lv->static_l = 0;
614 lv->static_u = lv->static_l = 0;
617 printf("C_ERROR: unknown direction\n");
622 /* no dynamic bounds have been determined so far */
623 lv->dynamic_l = lv->dynamic_l_v = lv->dynamic_u = lv->dynamic_u_v = 0;
625 lv->next = c_loopvars; /* add var to list */
629 /* This function checks, whether a given loop with header node contains array
630 accesses. If so, it returns 1, else it returns 0 and the loops needs no
631 further consideration in the optimization process. When array accesses are
632 found, a list of all variables, that are used as array index, is built and
633 stored in c_loopvars. For all variables (integer), which values are changed,
634 a flag in c_var_modified is set.
636 int analyze_for_array_access(methodinfo *m, int node)
641 struct depthElement *d;
644 if (c_toVisit[node] > 0) { /* node has not been visited yet */
647 bp = m->basicblocks[node]; /* prepare an instruction scan */
651 access = 0; /* number of array accesses in loop */
653 for (i=0; i<ic; ++i, ++ip) { /* for each instruction, check opcode */
655 case ICMD_IASTORE: /* array store */
663 t = tracing(&bp, i-1, 1); /* try to identify index variable */
665 if (t->type == TRACE_IVAR) {
666 /* if it is a variable, add it to list of index variables */
667 add_to_vars(t->var, ARRAY_INDEX, D_UNKNOWN);
670 else if (t->type == TRACE_ICONST)
674 case ICMD_IALOAD: /* array load */
682 t = tracing(&bp, i-1, 0); /* try to identify index variable */
684 if (t->type == TRACE_IVAR) {
685 /* if it is a variable, add it to list of index variables */
686 add_to_vars(t->var, ARRAY_INDEX, D_UNKNOWN);
689 else if (t->type == TRACE_ICONST)
693 case ICMD_ISTORE: /* integer store */
694 c_var_modified[ip->op1] = 1;
696 /* try to find out, how it was modified */
697 t = tracing(&bp, i-1, 0);
698 if (t->type == TRACE_IVAR) {
699 if ((t->constant > 0) && (t->var == ip->op1))
700 /* a constant was added to the same var */
701 add_to_vars(t->var, VAR_MOD, D_UP);
702 else if (t->var == ip->op1)
703 /* a constant was subtracted from the same var */
704 add_to_vars(t->var, VAR_MOD, D_DOWN);
706 add_to_vars(t->var, VAR_MOD, D_UNKNOWN);
709 add_to_vars(ip->op1, VAR_MOD, D_UNKNOWN);
712 case ICMD_IINC: /* simple add/sub of a constant */
713 c_var_modified[ip->op1] = 1;
716 add_to_vars(ip->op1, VAR_MOD, D_UP);
718 add_to_vars(ip->op1, VAR_MOD, D_DOWN);
725 c_var_modified[ip->op1] = 1;
731 while (d != NULL) { /* check all successors of block */
732 access += analyze_for_array_access(m, d->value);
742 /* This function scans the exception graph structure to find modifications of
743 array index variables of the current loop. If any modifications are found,
744 1 is returned, else 0.
746 int quick_scan(methodinfo *m, int node)
752 struct depthElement *d;
754 /* printf("QS: %d - %d\n", node, c_exceptionVisit[node]); */
757 if (c_exceptionVisit[node] > 0) { /* node is part of exception graph */
758 c_exceptionVisit[node] = -1;
760 bp = m->basicblocks[node]; /* setup scan of all instructions */
764 for (i=0; i<count; ++i, ++ip) { /* for each instruction do */
767 case ICMD_IINC: /* a variable is modified */
769 lv = c_loopvars; /* is it an array index var ? */
771 if ((lv->index) && (lv->value == ip->op1))
772 return 1; /* yes, so return 1 */
779 d = c_exceptionGraph[node]; /* check all successor nodes */
781 if (quick_scan(m, d->value) > 0)
782 return 1; /* if an access is found return 1 */
786 return 0; /* nothing found, so return 0 */
792 /* This function returns 1, when the condition of the loop contains
793 or statements or when an array index variable is modified in any
794 catch block within the loop.
796 int analyze_or_exceptions(methodinfo *m, int head, struct LoopContainer *lc)
798 struct depthElement *d;
799 int i, k, value, flag, count;
800 struct LoopElement *le;
805 /* analyze for or-statements */
807 printf("*** Analyze for OR ... ");
811 while (d != NULL) { /* for all successor nodes check if they */
812 value = d->value; /* are part of the loop */
817 if (le->node == value)
822 if (le == NULL) /* node is not part of the loop */
829 if ((count > 1) && (flag == 0)){/* if all successors part of the loop, exit */
836 /* check for exceptions */
837 /* printf("done\n*** Analyze for EXCEPTIONS(%d) . ", m->exceptiontablelength); */
839 if (!m->exceptiontablelength) /* when there are no exceptions, exit */
842 if ((c_exceptionGraph = (struct depthElement **) malloc(sizeof(struct depthElement *) * m->basicblockcount)) == NULL)
844 if ((c_exceptionVisit = (int *) malloc(sizeof(int) * m->basicblockcount)) == NULL)
847 for (k=0; k<m->basicblockcount; ++k) {
848 c_exceptionVisit[k] = -1;
849 c_exceptionGraph[k] = NULL;
853 /* for all nodes that start catch block check whether they are part of loop */
854 for (i = 0; i < c_old_xtablelength; i++) {
855 value = m->basicblockindex[m->exceptiontable[i].startpc];
860 if (le->node == value) { /* exception is in loop */
862 printf("C_INFO: Loop contains exception\n");
866 /* build a graph structure, that contains all nodes that are */
867 /* part of the catc block */
868 dF_Exception(m, -1, m->basicblockindex[m->exceptiontable[i].handlerpc]);
870 /* if array index variables are modified there, return 0 */
871 if (quick_scan(m, m->basicblockindex[m->exceptiontable[i].handlerpc]) > 0) {
875 /* printf("C_INFO: loopVar modified in exception\n"); */
884 printf("none ... done\n");
890 /* This function sets a flag in c_var_modified for all variables that have
891 been found as part of an assigment in the loop.
893 void scan_global_list()
900 c_var_modified[lv->value] = 1;
905 /* This function analyses the condition in the loop header and trys to find
906 out, whether some dynamic guarantees can be set up.
908 void init_constraints(methodinfo *m, int head)
912 int ic, l_mod, r_mod, changed, operand;
913 struct Trace *left, *right, *th;
914 struct LoopVar *lv_left, *lv_right, *lh;
916 bp = m->basicblocks[head];
918 ip = bp.iinstr+(ic-1); /* set ip to last instruction in header node */
920 switch (ip->opc) { /* check op-code */
922 /* comparison against constant value */
923 case ICMD_IFEQ: /* ..., value ==> ... */
924 case ICMD_IFLT: /* ..., value ==> ... */
925 case ICMD_IFLE: /* ..., value ==> ... */
926 case ICMD_IFGT: /* ..., value ==> ... */
927 case ICMD_IFGE: /* ..., value ==> ... */
928 /* op1 = target JavaVM pc, val.i = constant */
930 left = tracing(&bp, ic-2, 0); /* analyse left arg., right is constant */
931 right = create_trace(TRACE_ICONST, -1, ip->val.i, 0);
934 /* standard comparison */
935 case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */
936 case ICMD_IF_ICMPLT: /* ..., value, value ==> ... */
937 case ICMD_IF_ICMPGT: /* ..., value, value ==> ... */
938 case ICMD_IF_ICMPLE: /* ..., value, value ==> ... */
939 case ICMD_IF_ICMPGE: /* ..., value, value ==> ... */
941 left = tracing(&bp, ic-2, 1); /* get left and right argument */
942 right = tracing(&bp, ic-2, 0);
945 /* other condition */
947 left = create_trace(TRACE_UNKNOWN, -1, 0, 0);
948 right = create_trace(TRACE_UNKNOWN, -1, 0, 0);
952 /* analyse left and right side of comparison */
955 if (left->type == TRACE_IVAR) { /* is a loop variable on left side ? */
956 lv_left = c_loopvars;
957 while (lv_left != NULL) {
958 if (lv_left->value == left->var) {
959 l_mod = lv_left->modified; /* yes, but has it been modified ? */
962 lv_left = lv_left->next;
966 if (right->type == TRACE_IVAR){ /* is a loop variable on right side ? */
967 lv_right = c_loopvars;
968 while (lv_right != NULL) {
969 if (lv_right->value == right->var) {
970 r_mod = lv_right->modified; /* yes, but has it been modified ? */
973 lv_right = lv_right->next;
977 if ((l_mod - r_mod) == 0) { /* both 1 or both 0 -> no dynamic contraints*/
978 c_rightside = NULL; /* possible */
982 /* to simplify processing, make the left side the one, that contains the */
983 /* modified variable */
985 th = left; left = right; right = th;
986 lh = lv_left; lv_left = lv_right; lv_right = lh;
987 changed = 1; /* set changed to true */
990 changed = 0; /* no change needed */
992 /* make sure that right side's value does not change during loop execution */
993 if (right->type == TRACE_UNKNOWN) {
998 /* determine operands: */
999 /* for further explaination a is modified, b nonmodified var */
1000 switch (ip->opc) { /* check opcode again */
1001 case ICMD_IFEQ: /* ..., value ==> ... */
1002 case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */
1003 operand = OP_EQ; /* a == b */
1006 case ICMD_IFLE: /* ..., value ==> ... */
1007 case ICMD_IF_ICMPLE: /* ..., value, value ==> ... */
1009 operand = OP_GE; /* b<=a -> a>=b */
1011 operand = OP_LT; /* a<=b -> a<(b+1) */
1012 if (left->constant != 0)
1013 left->constant -= 1;
1015 right->constant += 1;
1019 case ICMD_IFLT: /* ..., value ==> ... */
1020 case ICMD_IF_ICMPLT: /* ..., value, value ==> ... */
1022 operand = OP_GE; /* b<a -> a>=(b+1) */
1023 if (left->constant != 0)
1024 left->constant -= 1;
1026 right->constant += 1;
1029 operand = OP_LT; /* a<b -> a<b */
1032 case ICMD_IFGT: /* ..., value ==> ... */
1033 case ICMD_IF_ICMPGT: /* ..., value, value ==> ... */
1035 operand = OP_LT; /* b>a -> a<b */
1037 operand = OP_GE; /* a>b -> a>=(b+1) */
1038 if (left->constant != 0)
1039 left->constant -= 1;
1041 right->constant += 1;
1045 case ICMD_IFGE: /* ..., value ==> ... */
1046 case ICMD_IF_ICMPGE: /* ..., value, value ==> ... */
1048 operand = OP_LT; /* b>=a -> a<(b+1) */
1049 if (left->constant != 0)
1050 left->constant -= 1;
1052 right->constant += 1;
1055 operand = OP_GE; /* a>=b -> a>=b */
1059 printf("C_ERROR: debugging error 0x00\n");
1063 /* NOW: left/lv_left -> loopVar */
1064 /* right/lv_right -> const, nonmod. var, arraylength */
1065 switch (operand) { /* check operand */
1067 lv_left->dynamic_u_v = 1; /* upper + lower bound tested */
1068 lv_left->dynamic_l_v = 1;
1070 lv_left->dynamic_l = lv_left->dynamic_u = left->constant;
1074 lv_left->dynamic_u_v = 1; /* upper bound tested */
1076 lv_left->dynamic_u = left->constant;
1080 lv_left->dynamic_l_v = 1; /* lower bound tested */
1082 lv_left->dynamic_l = left->constant;
1086 printf("C_ERROR: debugging error 0x01\n");
1089 c_rightside = right;
1091 switch (c_rightside->type) {
1093 c_rs_needed_instr = 1;
1096 c_rs_needed_instr = 2;
1099 c_rs_needed_instr = 3;
1102 printf("C_ERROR: wrong right-side type\n");
1106 /* This function is needed to add and record new static tests (before loop
1107 entry) of variables to make guaratees for index variables. type states
1108 the kind of the test. arrayRef is the array, which length is tested
1109 against, varRef is the variable, that is testes and constant is the
1110 constant value, that is tested.
1112 void add_new_constraint(methodinfo *m, int type, int arrayRef, int varRef, int constant)
1114 struct Constraint *tc;
1117 case TEST_ZERO: /* a variable is tested against a const */
1119 tc = c_constraints[varRef]; /* does a test already exist for this var ? */
1120 while (tc != NULL) {
1121 if (tc->type == TEST_ZERO) {
1122 if (constant < tc->constant)
1123 tc->constant = constant;
1124 return; /* yes. update constant and return */
1129 /* insert a new test for this variable */
1130 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1132 tc->type = TEST_ZERO;
1133 tc->varRef = varRef;
1134 tc->constant = constant;
1135 tc->next = c_constraints[varRef];
1136 c_constraints[varRef] = tc;
1137 c_needed_instr += 3;
1141 case TEST_ALENGTH: /* variable is tested against array length */
1143 tc = c_constraints[varRef]; /* does a test already exist for this var ? */
1144 while (tc != NULL) {
1145 if ((tc->type == TEST_ALENGTH) && (tc->arrayRef == arrayRef)) {
1146 if (constant > tc->constant)
1147 tc->constant = constant;
1148 return; /* yes. update constant and return */
1153 /* insert a new test for this variable */
1154 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1156 tc->type = TEST_ALENGTH;
1157 tc->arrayRef = arrayRef;
1158 tc->varRef = varRef;
1159 tc->constant = constant;
1160 tc->next = c_constraints[varRef];
1161 c_constraints[varRef] = tc;
1162 c_needed_instr += 6;
1164 /* if arrayRef is not already tested against null, insert that test */
1165 if (!(c_null_check[arrayRef])) {
1166 c_null_check[arrayRef] = 1;
1172 case TEST_CONST_ZERO:
1176 case TEST_CONST_ALENGTH: /* a const is tested against array length */
1178 /* does a test already exist for this array */
1179 tc = c_constraints[m->maxlocals];
1180 while (tc != NULL) {
1181 if ((tc->type == TEST_CONST_ALENGTH) && (tc->arrayRef == arrayRef)) {
1182 if (constant > tc->constant)
1183 tc->constant = constant;
1184 return; /* yes. update constant and return */
1189 /* insert a new test for this array */
1190 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1192 tc->type = TEST_CONST_ALENGTH;
1193 tc->arrayRef = arrayRef;
1194 tc->constant = constant;
1195 tc->next = c_constraints[m->maxlocals];
1196 c_constraints[m->maxlocals] = tc;
1197 c_needed_instr += 4;
1199 /* if arrayRef is not already tested against null, insert that test */
1200 if (!(c_null_check[arrayRef])) {
1201 c_null_check[arrayRef] = 1;
1207 case TEST_UNMOD_ZERO: /* test unmodified var against constant */
1209 /* search if test already exists */
1210 tc = c_constraints[varRef];
1211 while (tc != NULL) {
1212 if (tc->type == TEST_UNMOD_ZERO) {
1213 if (constant < tc->constant)
1214 tc->constant = constant;
1215 return; /* yes, so update constant */
1220 /* else, a new test is inserted */
1221 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1223 tc->type = TEST_UNMOD_ZERO;
1224 tc->varRef = varRef;
1225 tc->constant = constant;
1226 tc->next = c_constraints[varRef];
1227 c_constraints[varRef] = tc;
1228 c_needed_instr += 3;
1232 case TEST_UNMOD_ALENGTH: /* test unmodified var against array length */
1234 /* search if test alreay exists */
1235 tc = c_constraints[varRef];
1236 while (tc != NULL) {
1237 if ((tc->type == TEST_UNMOD_ALENGTH) && (tc->arrayRef == arrayRef)) {
1238 if (constant > tc->constant)
1239 tc->constant = constant;
1240 return; /* yes, so modify constants */
1245 /* create new entry */
1246 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1248 tc->type = TEST_UNMOD_ALENGTH;
1249 tc->varRef = varRef;
1250 tc->arrayRef = arrayRef;
1251 tc->constant = constant;
1252 tc->next = c_constraints[varRef];
1253 c_constraints[varRef] = tc;
1254 c_needed_instr += 6;
1256 /* if arrayRef is not already tested against null, insert that test */
1257 if (!(c_null_check[arrayRef])) {
1258 c_null_check[arrayRef] = 1;
1264 case TEST_RS_ZERO: /* test right side of the loop condition */
1265 /* against a constant - needed by dynamic */
1267 /*!! varRef -> maxlocals */
1268 /* search if test already exists */
1269 tc = c_constraints[m->maxlocals];
1270 while (tc != NULL) {
1271 if (tc->type == TEST_RS_ZERO) {
1272 if (constant < tc->constant)
1273 tc->constant = constant;
1274 return; /* yes, so modify constants */
1279 /* create new entry */
1280 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1282 tc->type = TEST_RS_ZERO;
1283 tc->constant = constant;
1284 tc->next = c_constraints[m->maxlocals];
1285 c_constraints[m->maxlocals] = tc;
1286 c_needed_instr += (2 + c_rs_needed_instr);
1288 /* if arrayRef on right side is not already tested against null, */
1289 /* insert that test */
1290 if ((c_rightside->type == TRACE_ALENGTH) && (!(c_null_check[c_rightside->var]))) {
1291 c_null_check[c_rightside->var] = 1;
1297 case TEST_RS_ALENGTH: /* test right side of the loop condition */
1298 /* against array length - needed by dynamic */
1300 /*!! varRef -> maxlocals */
1301 /* search if test already exists */
1302 tc = c_constraints[m->maxlocals];
1305 if ((tc->type == TEST_RS_ALENGTH) && (tc->arrayRef == arrayRef))
1307 if (constant > tc->constant)
1308 tc->constant = constant;
1309 return; /* yes, so modify constants */
1314 /* create new entry */
1315 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1317 tc->type = TEST_RS_ALENGTH;
1318 tc->arrayRef = arrayRef;
1319 tc->constant = constant;
1320 tc->next = c_constraints[m->maxlocals];
1321 c_constraints[m->maxlocals] = tc;
1322 c_needed_instr += (3 + c_rs_needed_instr);
1324 /* if arrayRef is not already tested against null, insert that test */
1325 if (!(c_null_check[arrayRef])) {
1326 c_null_check[arrayRef] = 1;
1330 /* if arrayRef on right side is not already tested against null, */
1331 /* insert that test */
1332 if ((c_rightside->type == TRACE_ALENGTH) && (!(c_null_check[c_rightside->var]))) {
1333 c_null_check[c_rightside->var] = 1;
1341 /* This functions adds new static (before loop enry) tests of variables to the
1342 program to be able to guarantee certain values for index variables in array
1343 access (to safely remove bound checks).
1345 int insert_static(methodinfo *m, int arrayRef, struct Trace *index, struct Changes *varChanges, int special)
1351 /* printf("insert static check - %d\n", arrayRef);
1353 show_change(varChanges);
1356 if (varChanges == NULL) { /* the variable hasn't changed / const */
1357 if ((varChanges = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
1359 varChanges->lower_bound = varChanges->upper_bound = 0;
1362 switch (index->type) { /* check index type */
1363 case TRACE_IVAR: /* it is a variable */
1364 if (index->neg < 0) { /* if it's a negated var, return */
1371 varRef = index->var;
1374 if (c_var_modified[varRef]) { /* volatile var */
1376 lv = c_loopvars; /* get reference to loop variable */
1378 while ((lv != NULL) && (lv->value != varRef))
1381 printf("C_ERROR: debugging error 0x02\n");
1383 /* show_varinfo(lv); */
1385 /* check existing static bounds and add new contraints on variable */
1386 /* to possibly remove bound checks */
1388 /* the var is never decremented, so we add a static test againt */
1390 if (varChanges->lower_bound > varChanges->upper_bound)
1391 add_new_constraint(m, TEST_ZERO, arrayRef, varRef, index->constant);
1393 add_new_constraint(m, TEST_ZERO, arrayRef, varRef, varChanges->lower_bound+index->constant);
1396 else if ((lv->dynamic_l_v) && (!special)) {
1397 /* the variable is decremented, but it is checked against a */
1398 /* bound in the loop condition */
1399 if (varChanges->lower_bound <= varChanges->upper_bound) {
1400 add_new_constraint(m, TEST_RS_ZERO, arrayRef, varRef, varChanges->lower_bound+index->constant+lv->dynamic_l);
1406 /* the var is never incremented, so we add a static test againt */
1408 if (varChanges->lower_bound > varChanges->upper_bound)
1409 add_new_constraint(m, TEST_ALENGTH, arrayRef, varRef, index->constant);
1411 add_new_constraint(m, TEST_ALENGTH, arrayRef, varRef, varChanges->upper_bound+index->constant);
1414 else if ((lv->dynamic_u_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, TEST_RS_ALENGTH, arrayRef, varRef, varChanges->upper_bound+index->constant+lv->dynamic_u);
1423 else { /* the var is never modified at all */
1424 add_new_constraint(m, TEST_UNMOD_ZERO, arrayRef, index->var, index->constant);
1425 add_new_constraint(m, TEST_UNMOD_ALENGTH, arrayRef, index->var, index->constant);
1429 /* if the addition of new variable tests made guarantees possible, */
1430 /* return the best possible optimization */
1431 if ((high > 0) && (low > 0)) {
1432 /* printf("fully optimzed\n"); */
1438 else if (high > 0) {
1439 /* printf("upper optimzed\n"); */
1446 /* printf("lower optimzed\n"); */
1453 /* printf("not optimzed\n"); */
1461 case TRACE_ICONST: /* if it is a constant, optimization is easy */
1462 if (index->constant < 0) {
1466 return OPT_NONE; /* negative index -> bad */
1469 add_new_constraint(m, TEST_CONST_ALENGTH, arrayRef, 0, index->constant);
1473 return OPT_FULL; /* else just test constant against array length */
1477 case TRACE_ALENGTH: /* else, no optimizations possible */
1486 /* keep compiler happy */
1492 /* copy a stack and return the start pointer of the newly created one
1494 stackptr copy_stack_from(stackptr source) {
1495 stackptr current, top;
1500 /* copy first element */
1501 current = DMNEW(stackelement, 1);
1502 current->type = source->type;
1503 current->flags = source->flags;
1504 current->varkind = source->varkind;
1505 current->varnum = source->varnum;
1506 current->regoff = source->regoff;
1510 /* if there exist more, then copy the rest */
1511 while (source->prev != NULL) {
1512 source = source->prev;
1513 current->prev = DMNEW(stackelement, 1);
1514 current->type = source->type;
1515 current->flags = source->flags;
1516 current->varkind = source->varkind;
1517 current->varnum = source->varnum;
1518 current->regoff = source->regoff;
1519 current = current->prev;
1522 current->prev = NULL;
1527 /* The following defines are used in the procedure void create_static_checks(...)
1528 They add a new instruction with its corresponding stack manipulation and
1529 are used to build the new loop header of an optimized loop, where we have
1530 to check certain variables and constants against values to guarantee that
1531 index values in array accesses remain with array bounds.
1533 inst: pointer to the new instruction
1534 tos: stackpointer before this operation is executed
1535 newstack: temporary stackptr
1536 stackdepth: counts the current stackdepth
1537 original start: blockpointer to the head of the new, optimized loop
1540 /* Load a local integer variable v */
1541 #define LOAD_VAR(v) { \
1542 inst->opc = ICMD_ILOAD; \
1544 newstack = DMNEW(stackelement, 1); \
1545 inst->dst = newstack; \
1546 newstack->prev = tos; \
1547 newstack->type = TYPE_INT; \
1548 newstack->flags = 0; \
1549 newstack->varkind = LOCALVAR; \
1550 newstack->varnum = v; \
1556 /* Load a constant with value c */
1557 #define LOAD_CONST(c) { \
1558 inst->opc = ICMD_ICONST; \
1560 inst->val.i = (c); \
1561 newstack = DMNEW(stackelement, 1); \
1562 newstack->prev = tos; \
1563 newstack->type = TYPE_INT; \
1564 newstack->flags = 0; \
1565 newstack->varkind = UNDEFVAR; \
1566 newstack->varnum = stackdepth; \
1573 /* Load a local reference (adress) variable a */
1574 #define LOAD_ADDR(a) { \
1575 inst->opc = ICMD_ALOAD; \
1577 newstack = DMNEW(stackelement, 1); \
1578 newstack->prev = tos; \
1579 newstack->type = TYPE_ADR; \
1580 newstack->flags = 0; \
1581 newstack->varkind = LOCALVAR; \
1582 newstack->varnum = a; \
1589 /* Insert a compare greater-or-equal and jump to the unoptimized loop, if the */
1590 /* comparison is true */
1591 #define GOTO_NOOPT_IF_GE { \
1592 inst->opc = ICMD_IF_ICMPGE; \
1593 inst->target = original_start->copied_to; \
1594 if (tos->varkind == UNDEFVAR) \
1595 tos->varkind = TEMPVAR; \
1597 if (tos->varkind == UNDEFVAR) \
1598 tos->varkind = TEMPVAR; \
1605 /* Insert a compare greater than and jump to the unoptimized loop, if the */
1606 /* comparison is true */
1607 #define GOTO_NOOPT_IF_GT { \
1608 inst->opc = ICMD_IF_ICMPGT; \
1609 inst->target = original_start->copied_to; \
1610 if (tos->varkind == UNDEFVAR) \
1611 tos->varkind = TEMPVAR; \
1613 if (tos->varkind == UNDEFVAR) \
1614 tos->varkind = TEMPVAR; \
1622 /* Insert a compare less-than and jump to the unoptimized loop, if the */
1623 /* comparison is true */
1624 #define GOTO_NOOPT_IF_LT { \
1625 inst->opc = ICMD_IF_ICMPLT; \
1626 inst->target = original_start->copied_to; \
1627 if(tos->varkind == UNDEFVAR) \
1628 tos->varkind = TEMPVAR; \
1630 if(tos->varkind == UNDEFVAR) \
1631 tos->varkind = TEMPVAR; \
1638 /* Insert a compare if-not-null and jump to the unoptimized loop, if the */
1639 /* comparison is true */
1640 #define GOTO_NOOPT_IF_NULL { \
1641 inst->opc = ICMD_IFNULL; \
1642 inst->target = original_start->copied_to; \
1643 if(tos->varkind == UNDEFVAR) \
1644 tos->varkind = TEMPVAR; \
1651 /* Insert an add instruction, that adds two integer values on top of the stack */
1654 inst->opc = ICMD_IADD; \
1655 if(tos->varkind == UNDEFVAR) \
1656 tos->varkind = TEMPVAR; \
1658 if(tos->varkind == UNDEFVAR) \
1659 tos->varkind = TEMPVAR; \
1661 newstack = DMNEW(stackelement, 1); \
1662 newstack->prev = tos; \
1663 newstack->type = TYPE_INT; \
1664 newstack->flags = 0; \
1665 newstack->varkind = UNDEFVAR; \
1666 newstack->varnum = stackdepth; \
1673 /* Insert instructions to load the arraylength of an array with reference a */
1674 /* fisrt, the reference must be loaded, then a null-pointer check is inserted */
1675 /* if not already done earlier. Finally an arraylength instruction is added */
1676 #define LOAD_ARRAYLENGTH(a) { \
1677 if (c_null_check[a]) { \
1679 GOTO_NOOPT_IF_NULL; \
1680 c_null_check[a] = 0; \
1683 inst->opc = ICMD_ARRAYLENGTH; \
1684 if(tos->varkind == UNDEFVAR) \
1685 tos->varkind = TEMPVAR; \
1687 newstack = DMNEW(stackelement, 1); \
1688 newstack->prev = tos; \
1689 newstack->type = TYPE_INT; \
1690 newstack->flags = 0; \
1691 newstack->varkind = UNDEFVAR; \
1692 newstack->varnum = stackdepth; \
1699 /* Inserts the instructions to load the value of the right side of comparison */
1700 /* Depending of the type of the right side, the apropriate instructions are */
1702 #define LOAD_RIGHT_SIDE { \
1703 switch (c_rightside->type) { \
1704 case TRACE_ICONST: \
1705 LOAD_CONST(c_rightside->constant); \
1708 LOAD_VAR(c_rightside->var); \
1709 LOAD_CONST(c_rightside->constant); \
1712 case TRACE_ALENGTH: \
1713 LOAD_ARRAYLENGTH(c_rightside->var); \
1716 panic("C_ERROR: illegal trace on rightside of loop-header"); \
1720 /* Patch jumps in original loop and in copied loop, add gotos in copied loop.
1721 All jumps in the original loop to the loop head have to be redirected to
1722 the newly inserted one. For the copied loop, it is necessay to redirect all
1723 jumps inside that loop to the copied nodes. lc points to the current loop,
1724 loop_head is a pointer to the newly inserted head and original start was
1725 the old head and is now the head of the optimized variant of the loop.
1727 void patch_jumps(basicblock *original_start, basicblock *loop_head, struct LoopContainer *lc)
1729 /* step through all nodes of a loop */
1730 struct LoopElement *le;
1732 instruction *inst, *temp_instr;
1736 while (le != NULL) {
1738 /* do nothing for new loop head */
1739 if (le->block == loop_head) {
1744 /* for original version */
1746 inst = bptr->iinstr;
1747 for (i = 0; i < bptr->icount; ++i, ++inst) {
1748 switch (inst->opc) {
1750 case ICMD_IF_ICMPEQ:
1751 case ICMD_IF_ICMPLT:
1752 case ICMD_IF_ICMPLE:
1753 case ICMD_IF_ICMPNE:
1754 case ICMD_IF_ICMPGT:
1755 case ICMD_IF_ICMPGE:
1757 case ICMD_IF_LCMPEQ:
1758 case ICMD_IF_LCMPLT:
1759 case ICMD_IF_LCMPLE:
1760 case ICMD_IF_LCMPNE:
1761 case ICMD_IF_LCMPGT:
1762 case ICMD_IF_LCMPGE:
1764 case ICMD_IF_ACMPEQ:
1765 case ICMD_IF_ACMPNE:
1784 case ICMD_IFNONNULL:
1786 /* jump to newly inserted loopheader has to be redirected */
1787 if (((basicblock *) inst->target) == loop_head)
1788 inst->target = (void *) original_start;
1791 case ICMD_TABLESWITCH:
1796 tptr = (void **) inst->target;
1798 s4ptr = inst->val.a;
1799 l = s4ptr[1]; /* low */
1800 i = s4ptr[2]; /* high */
1804 /* jump to newly inserted loopheader has to be redirected */
1805 for (tptr = inst->target; i >= 0; --i, ++tptr) {
1806 if (((basicblock *) *tptr) == loop_head)
1807 tptr[0] = (void *) original_start;
1812 case ICMD_LOOKUPSWITCH:
1817 tptr = (void **) inst->target;
1819 s4ptr = inst->val.a;
1820 l = s4ptr[0]; /* default */
1821 i = s4ptr[1]; /* count */
1823 /* jump to newly inserted loopheader has to be redirected */
1824 for (tptr = inst->target; i >= 0; --i, ++tptr) {
1825 if (((basicblock *) *tptr) == loop_head)
1826 tptr[0] = (void *) original_start;
1833 /* if node is part of loop and has fall through to original start, that */
1834 /* must be redirected. Unfortunately the instructions have to be copied */
1836 if (bptr->next == loop_head) {
1837 temp_instr = DMNEW(instruction, bptr->icount + 1);
1838 memcpy(temp_instr, bptr->iinstr, sizeof(instruction)*bptr->icount);
1839 bptr->iinstr = temp_instr;
1841 bptr->iinstr[bptr->icount].opc = ICMD_GOTO;
1842 bptr->iinstr[bptr->icount].target = original_start;
1843 bptr->iinstr[bptr->icount].dst = NULL;
1847 /* for copied version - which gets the unoptimized variant */
1848 bptr = le->block->copied_to;
1849 inst = bptr->iinstr;
1850 for (i = 0; i < bptr->icount; ++i, ++inst) {
1852 switch (inst->opc) {
1854 case ICMD_IASTORE: /* array store */
1862 case ICMD_IALOAD: /* array load */
1871 /* undo previous optimizations in new loop */
1875 case ICMD_IF_ICMPEQ:
1876 case ICMD_IF_ICMPLT:
1877 case ICMD_IF_ICMPLE:
1878 case ICMD_IF_ICMPNE:
1879 case ICMD_IF_ICMPGT:
1880 case ICMD_IF_ICMPGE:
1882 case ICMD_IF_LCMPEQ:
1883 case ICMD_IF_LCMPLT:
1884 case ICMD_IF_LCMPLE:
1885 case ICMD_IF_LCMPNE:
1886 case ICMD_IF_LCMPGT:
1887 case ICMD_IF_LCMPGE:
1889 case ICMD_IF_ACMPEQ:
1890 case ICMD_IF_ACMPNE:
1909 case ICMD_IFNONNULL:
1911 /* jump to newly inserted loopheader has to be redirected */
1912 if (((basicblock *) inst->target) == loop_head)
1913 inst->target = (void *) original_start->copied_to;
1914 /* jump to loop internal nodes has to be redirected */
1915 else if (((basicblock *) inst->target)->lflags & LOOP_PART)
1916 inst->target = (void *) ((basicblock *) inst->target)->copied_to;
1919 case ICMD_TABLESWITCH:
1923 void **copy_ptr, *base_ptr;
1926 tptr = (void **) inst->target;
1928 s4ptr = inst->val.a;
1929 l = s4ptr[1]; /* low */
1930 i = s4ptr[2]; /* high */
1934 copy_ptr = (void**) DMNEW(void*, i+1);
1935 base_ptr = (void*) copy_ptr;
1937 /* Targets for switch instructions are stored in an extra */
1938 /* that must be copied for new inserted loop. */
1940 for (tptr = inst->target; i >= 0; --i, ++tptr, ++copy_ptr) {
1941 /* jump to newly inserted loopheader must be redirected */
1942 if (((basicblock *) *tptr) == loop_head)
1943 copy_ptr[0] = (void *) original_start->copied_to;
1944 /* jump to loop internal nodes has to be redirected */
1945 else if (((basicblock *) *tptr)->lflags & LOOP_PART)
1946 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
1948 copy_ptr[0] = tptr[0];
1951 inst->target = base_ptr;
1955 case ICMD_LOOKUPSWITCH:
1959 void **copy_ptr, **base_ptr;
1962 tptr = (void **) inst->target;
1964 s4ptr = inst->val.a;
1965 l = s4ptr[0]; /* default */
1966 i = s4ptr[1]; /* count */
1968 copy_ptr = (void**) DMNEW(void*, i+1);
1969 base_ptr = (void*) copy_ptr;
1971 /* Targets for switch instructions are stored in an extra */
1972 /* that must be copied for new inserted loop. */
1974 for (tptr = inst->target; i >= 0; --i, ++tptr, ++copy_ptr) {
1975 /* jump to newly inserted loopheader must be redirected */
1976 if (((basicblock *) *tptr) == loop_head)
1977 copy_ptr[0] = (void *) original_start->copied_to;
1978 /* jump to loop internal nodes has to be redirected */
1979 else if (((basicblock *) *tptr)->lflags & LOOP_PART)
1980 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
1982 copy_ptr[0] = tptr[0];
1985 inst->target = base_ptr;
1992 /* if fall through exits loop, goto is needed */
1993 if (!(le->block->next->lflags & LOOP_PART)) {
1994 bptr->iinstr[bptr->icount].opc = ICMD_GOTO;
1995 bptr->iinstr[bptr->icount].dst = NULL;
1996 bptr->iinstr[bptr->icount].target = le->block->next;
2004 /* Add the new header node of a loop that has been duplicated to all parent
2005 loops in nesting hierarchie.
2007 void header_into_parent_loops(struct LoopContainer *lc, basicblock *to_insert, basicblock *replace, basicblock *after)
2009 /* we have to insert the node to_insert before the node after and replace */
2010 /* the pointer of to_insert by the node replace */
2012 struct LoopElement *le, *t;
2014 /* if the top of the tree is reached, then return */
2015 if ((lc == NULL) || (lc == root))
2018 /* create new node, that should be inserted */
2019 t = DMNEW(struct LoopElement, 1);
2020 t->block = to_insert;
2023 /* first, find the node, that has to be replaced (= "to_insert") and */
2024 /* replace it by the node "replace" */
2026 while (le->block != to_insert)
2028 le->block = replace;
2031 if (after == to_insert)
2034 /* now find the node after and insert the newly create node before "after" */
2036 if (le->block == after) {
2037 t->next = lc->nodes;
2041 while (le->next->block != after)
2048 /* go up one hierarchie level */
2049 header_into_parent_loops(lc->parent, to_insert, replace, after);
2052 /* Add a new node (not header) of a duplicated loop to all parent loops in
2055 void node_into_parent_loops(struct LoopContainer *lc, basicblock *to_insert)
2057 struct LoopElement *le, *t;
2059 /* if the top of the tree is reached, then return */
2060 if ((lc == NULL) || (lc == root))
2063 /* create new node, that should be inserted */
2064 t = DMNEW(struct LoopElement, 1);
2065 t->block = to_insert;
2070 /* append new node to node list of loop */
2071 while (le->next != NULL)
2077 /* go up one hierarchie level */
2078 node_into_parent_loops(NULL, to_insert);
2082 /* void patch_handler(...) is very similar to parts of the function patch_jumps.
2083 Its task is to redirect all jumps from the original head to the new head and
2084 to redirect internal jumps inside the exception handler to the newly
2085 created (copied) nodes.
2087 void patch_handler(struct LoopContainer *lc, basicblock *bptr, basicblock *original_head, basicblock *new_head)
2092 /* If node is not part of exception handler or has been visited, exit */
2093 if (!(bptr->lflags & HANDLER_PART) || (bptr->lflags & HANDLER_VISITED))
2096 /* mark block as visited */
2097 bptr->lflags |= HANDLER_VISITED;
2099 /* for all instructions in the copied block, do */
2100 for (i = 0, ip = bptr->copied_to->iinstr; i < bptr->copied_to->icount; ++i, ++ip) {
2111 case ICMD_IF_ICMPEQ:
2112 case ICMD_IF_ICMPLT:
2113 case ICMD_IF_ICMPLE:
2114 case ICMD_IF_ICMPNE:
2115 case ICMD_IF_ICMPGT:
2116 case ICMD_IF_ICMPGE:
2118 case ICMD_IF_LCMPEQ:
2119 case ICMD_IF_LCMPLT:
2120 case ICMD_IF_LCMPLE:
2121 case ICMD_IF_LCMPNE:
2122 case ICMD_IF_LCMPGT:
2123 case ICMD_IF_LCMPGE:
2125 case ICMD_IF_ACMPEQ:
2126 case ICMD_IF_ACMPNE:
2144 case ICMD_IFNONNULL:
2146 patch_handler(lc, bptr->next, original_head, new_head);
2152 patch_handler(lc, ip->target, original_head, new_head);
2154 /* jumps to old header have to be redirected */
2155 if (((basicblock *) ip->target) == original_head)
2156 ip->target = (void *) new_head->copied_to;
2157 /* jumps to handler internal nodes have to be redirected */
2158 else if (((basicblock *) ip->target)->lflags & HANDLER_PART)
2159 ip->target = (void *) ((basicblock *) ip->target)->copied_to;
2160 /* jumps to loop internal nodes have to be redirected */
2161 else if (((basicblock *) ip->target)->lflags & LOOP_PART)
2162 ip->target = (void *) ((basicblock *) ip->target)->copied_to;
2167 case ICMD_TABLESWITCH:
2171 void **copy_ptr, **base_ptr;
2173 tptr = (void **) ip->target;
2175 l = s4ptr[1]; /* low */
2176 i = s4ptr[2]; /* high */
2179 copy_ptr = (void**) DMNEW(void*, i+1);
2180 base_ptr = (void*) copy_ptr;
2182 for (tptr = ip->target; i >= 0; --i, ++tptr, ++copy_ptr) {
2183 patch_handler(lc, ((basicblock *) *tptr), original_head, new_head);
2184 /* jumps to old header have to be redirected */
2185 if (((basicblock *) *tptr) == original_head)
2186 copy_ptr[0] = (void *) new_head->copied_to;
2187 /* jumps to handler internal nodes have to be redirected */
2188 else if (((basicblock *) *tptr)->lflags & HANDLER_PART)
2189 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2190 /* jumps to loop internal nodes have to be redirected */
2191 else if (((basicblock *) ip->target)->lflags & LOOP_PART)
2192 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2194 copy_ptr[0] = tptr[0];
2197 ip->target = base_ptr;
2201 case ICMD_LOOKUPSWITCH:
2206 void **copy_ptr, **base_ptr;
2208 tptr = (void **) ip->target;
2210 l = s4ptr[0]; /* default */
2211 i = s4ptr[1]; /* count */
2213 copy_ptr = (void**) DMNEW(void*, i+1);
2214 base_ptr = (void*) copy_ptr;
2216 for (tptr = ip->target; i >= 0; --i, ++tptr, ++copy_ptr) {
2218 patch_handler(lc, ((basicblock *) *tptr), original_head, new_head);
2219 /* jumps to old header have to be redirected */
2220 if (((basicblock *) *tptr) == original_head)
2221 copy_ptr[0] = (void *) new_head->copied_to;
2222 /* jumps to handler internal nodes have to be redirected */
2223 else if (((basicblock *) *tptr)->lflags & HANDLER_PART)
2224 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2225 /* jumps to loop internal nodes have to be redirected */
2226 else if (((basicblock *) ip->target)->lflags & LOOP_PART)
2227 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2229 copy_ptr[0] = tptr[0];
2232 ip->target = base_ptr;
2240 /* if fall through exits loop, goto is needed */
2241 if (!(bptr->next->lflags & HANDLER_PART)) {
2242 bptr->copied_to->iinstr[bptr->copied_to->icount].opc = ICMD_GOTO;
2243 bptr->copied_to->iinstr[bptr->copied_to->icount].dst = NULL;
2244 bptr->copied_to->iinstr[bptr->copied_to->icount].target = bptr->next;
2245 bptr->copied_to->icount++;
2250 /* This function copys the exception handler and redirects all jumps from the
2251 original head to the new head in the original exception handler. All
2252 redirection in the copied exception handler is done in patch_handler(...).
2254 void copy_handler(methodinfo *m, struct LoopContainer *lc, basicblock *bptr, basicblock *original_head, basicblock *new_head)
2259 int high, low, count;
2260 struct LoopElement *le;
2261 basicblock *new, *temp;
2263 /* If this node has already been copied, return */
2264 if (bptr->lflags & HANDLER_PART)
2267 /* The exception handler exists, when control flow enters loop again */
2269 if (bptr->lflags & LOOP_PART)
2271 for (le = lc->nodes; le != NULL; le = le->next) {
2272 if (le->block == bptr) {
2273 printf("C_PANIC: should not happen\n");
2278 /* mark block as part of handler */
2279 bptr->lflags |= HANDLER_PART;
2282 new = DMNEW(basicblock, 1);
2283 memcpy(new, bptr, sizeof(basicblock));
2284 new->debug_nr = c_debug_nr++;
2286 c_last_block_copied = new;
2288 /* copy instructions and allow one more slot for possible GOTO */
2289 new->iinstr = DMNEW(instruction, bptr->icount + 1);
2290 memcpy(new->iinstr, bptr->iinstr, bptr->icount*sizeof(instruction));
2292 /* update original block */
2293 bptr->copied_to = new;
2295 /* append block to global list of basic blocks */
2296 temp = m->basicblocks;
2305 /* find next block to copy, depending on last instruction of BB */
2306 if (bptr->icount == 0) {
2307 copy_handler(m, lc, bptr->next, original_head, new_head);
2311 ip = bptr->iinstr + (bptr->icount - 1);
2330 case ICMD_IF_LCMPEQ:
2331 case ICMD_IF_LCMPLT:
2332 case ICMD_IF_LCMPLE:
2333 case ICMD_IF_LCMPNE:
2334 case ICMD_IF_LCMPGT:
2335 case ICMD_IF_LCMPGE:
2345 case ICMD_IFNONNULL:
2347 case ICMD_IF_ICMPEQ:
2348 case ICMD_IF_ICMPNE:
2349 case ICMD_IF_ICMPLT:
2350 case ICMD_IF_ICMPGE:
2351 case ICMD_IF_ICMPGT:
2352 case ICMD_IF_ICMPLE:
2353 case ICMD_IF_ACMPEQ:
2354 case ICMD_IF_ACMPNE:
2355 copy_handler(m, lc, bptr->next, original_head, new_head);
2360 /* redirect jump from original_head to new_head */
2361 if ((basicblock *) ip->target == original_head)
2362 ip->target = (void *) new_head;
2364 copy_handler(m, lc, (basicblock *) (ip->target), original_head, new_head);
2368 case ICMD_TABLESWITCH:
2370 tptr = (void **) ip->target;
2372 /* default branch */
2373 if (((basicblock *) *tptr) == original_head)
2374 tptr[0] = (void *) new_head;
2376 copy_handler(m, lc, (basicblock *) *tptr, original_head, new_head);
2383 count = (high-low+1);
2385 while (--count >= 0) {
2387 /* redirect jump from original_head to new_head */
2388 if (((basicblock *) *tptr) == original_head)
2389 tptr[0] = (void *) new_head;
2390 copy_handler(m, lc, (basicblock *) *tptr, original_head, new_head);
2394 case ICMD_LOOKUPSWITCH:
2396 tptr = (void **) ip->target;
2398 /* default branch */
2399 if (((basicblock *) *tptr) == original_head)
2400 tptr[0] = (void *) new_head;
2402 copy_handler(m, lc, (basicblock *) *tptr, original_head, new_head);
2407 while (--count >= 0) {
2409 /* redirect jump from original_head to new_head */
2410 if (((basicblock *) *tptr) == original_head)
2411 tptr[0] = (void *) new_head;
2412 copy_handler(m, lc, (basicblock *) *tptr, original_head, new_head);
2417 c_last_target = bptr;
2418 copy_handler(m, lc, (basicblock *) (ip->target), original_head, new_head);
2422 copy_handler(m, lc, c_last_target->next, original_head, new_head);
2426 copy_handler(m, lc, bptr->next, original_head, new_head);
2433 /* If a loop is duplicated, all exceptions, that are contained in this loops' body
2434 have to be duplicated as well. The following function together with the
2435 two helper functions copy_handler and patch_handler perform this task.
2437 void update_internal_exceptions(methodinfo *m, struct LoopContainer *lc, basicblock *original_head, basicblock *new_head)
2439 exceptiontable *ex, *new;
2440 struct LoopContainer *l;
2442 /* Bottom of tree reached -> return */
2446 /* Call update_internal for all nested (=child) loops */
2449 update_internal_exceptions(m, l, original_head, new_head);
2453 /* For all exceptions of this loop, do */
2454 ex = lc->exceptions;
2455 while (ex != NULL) {
2457 /* Copy the exception and patch the jumps */
2458 copy_handler(m, lc, ex->handler, original_head, new_head);
2459 patch_handler(lc, ex->handler, original_head, new_head);
2461 /* Insert a new exception into the global exception table */
2462 new = DNEW(exceptiontable);
2463 memcpy(new, ex, sizeof(exceptiontable));
2465 /* Increase number of exceptions */
2466 ++m->exceptiontablelength;
2471 /* Set new start and end point of this exception */
2472 new->start = ex->start->copied_to;
2473 new->end = ex->end->copied_to;
2475 /* Set handler pointer to copied exception handler */
2476 new->handler = ex->handler->copied_to;
2483 /* If a loop is duplicated, all exceptions that contain this loop have to be
2484 extended to the copied nodes as well. The following function checks for
2485 all exceptions of all parent loops, whether they contain the loop pointed to
2486 by lc. If so, the exceptions are extended to contain all newly created nodes.
2488 void update_external_exceptions(methodinfo *m, struct LoopContainer *lc, int loop_head)
2490 exceptiontable *ex, *new;
2492 /* Top of tree reached -> return */
2496 ex = lc->exceptions;
2498 /* For all exceptions of this loop do */
2499 while (ex != NULL) {
2501 /* It is possible that the loop contains exceptions that do not protect */
2502 /* the loop just duplicated. It must be checked, if this is the case */
2503 if ((loop_head >= m->basicblockindex[ex->startpc]) && (loop_head < m->basicblockindex[ex->endpc])) {
2505 /* loop is really inside exception, so create new exception entry */
2506 /* in global exception list */
2507 new = DNEW(exceptiontable);
2508 memcpy(new, ex, sizeof(exceptiontable));
2511 /* Increase number of exceptions */
2512 ++m->exceptiontablelength;
2517 /* Set new start and end point of this exception */
2518 new->start = c_first_block_copied;
2519 new->end = c_last_block_copied;
2523 /* exception does not contain the duplicated loop -> do nothing */
2528 /* Call update_external for parent node */
2529 update_external_exceptions(m, lc->parent, loop_head);
2534 /* This function is needed to insert the static checks, stored in c_constraints
2535 into the intermediate code.
2537 void create_static_checks(methodinfo *m, struct LoopContainer *lc)
2539 int i, stackdepth, cnt;
2540 struct Constraint *tc1;
2541 struct LoopElement *le;
2543 /* loop_head points to the newly inserted loop_head, original_start to */
2544 /* the old loop header */
2545 basicblock *bptr, *loop_head, *original_start, *temp;
2546 instruction *inst, *tiptr;
2548 /* tos and newstack are needed by the macros, that insert instructions into */
2549 /* the new loop head */
2550 stackptr newstack, tos;
2554 /* show_loop_statistics(); */
2557 loop_head = &m->basicblocks[c_current_head];
2558 c_first_block_copied = c_last_block_copied = NULL;
2560 /* the loop nodes are copied */
2564 bptr = DMNEW(basicblock, 1);
2565 memcpy(bptr, le->block, sizeof(basicblock));
2566 bptr->debug_nr = c_debug_nr++;
2568 /* determine beginning of copied loop to extend exception handler, that */
2569 /* protect this loop */
2570 if (c_first_block_copied == NULL)
2571 c_first_block_copied = bptr;
2573 /* copy instructions and add one more slot for possible GOTO */
2574 bptr->iinstr = DMNEW(instruction, bptr->icount + 1);
2576 memcpy(bptr->iinstr, le->block->iinstr, (bptr->icount+1)*sizeof(instruction));
2578 le->block->copied_to = bptr;
2580 /* add block to global list of BBs */
2581 temp = m->basicblocks;
2589 node_into_parent_loops(lc->parent, bptr);
2593 c_last_block_copied = bptr;
2595 /* create an additional basicblock for dynamic checks */
2596 original_start = bptr = DMNEW(basicblock, 1);
2598 /* copy current loop header to new basic block */
2599 memcpy(bptr, loop_head, sizeof(basicblock));
2600 bptr->debug_nr = c_debug_nr++;
2602 /* insert the new basic block and move header before first loop node */
2606 /* if header is first node of loop, insert original header after it */
2607 if (temp == loop_head)
2608 loop_head->next = bptr;
2610 /* else, we have to find the predecessor of loop header */
2611 while (temp->next != loop_head)
2614 /* insert original header after newly created block */
2617 /* if predecessor is not loop part, insert a goto */
2618 if (!(temp->lflags & LOOP_PART)) {
2620 /* copy instructions and add an additional slot */
2621 tiptr = DMNEW(instruction, temp->icount + 1);
2622 memcpy(tiptr, temp->iinstr, sizeof(instruction)*temp->icount);
2624 temp->iinstr = tiptr;
2625 tiptr = temp->iinstr + temp->icount;
2627 /* add goto to loop header. If node is part of exception handler */
2628 /* jmp is automagically redirected during patch_handler and works */
2630 tiptr->opc = ICMD_GOTO;
2632 tiptr->target = (void*) loop_head;
2638 temp = m->basicblocks;
2639 /* if first loop block is first BB of global list, insert loop_head at */
2640 /* beginning of global BB list */
2641 if (temp == le->block) {
2642 if (c_newstart == NULL) {
2643 c_needs_redirection = true;
2644 c_newstart = loop_head;
2645 loop_head->next = m->basicblocks;
2648 loop_head->next = c_newstart;
2649 c_newstart = loop_head;
2654 while (temp->next != le->block)
2657 loop_head->next = temp->next;
2658 temp->next = loop_head;
2660 /* to be on the safe side insert a jump from the previous instr */
2661 /* over thr new inserted node */
2663 /* special case - jump from node to loop_head: then remove */
2664 /* goto / happens rather often due to loop layout */
2665 tiptr = temp->iinstr + (temp->icount-1);
2667 if ((tiptr->opc == ICMD_GOTO) && (tiptr->target == loop_head)) {
2668 tiptr->opc = ICMD_NOP;
2673 tiptr = DMNEW(instruction, temp->icount + 1);
2674 memcpy(tiptr, temp->iinstr, sizeof(instruction)*temp->icount);
2676 temp->iinstr = tiptr;
2677 tiptr = temp->iinstr + temp->icount;
2679 tiptr->opc = ICMD_GOTO;
2681 tiptr->target = (void*) loop_head->next;
2688 /* adjust exceptions */
2689 ex = m->exceptiontable;
2690 while (ex != NULL) {
2692 /* if an exception covers whole loop and starts at first loop node, it */
2693 /* has to be extended to cover the new first node as well */
2694 if (ex->start == le->block) {
2696 if ((lc->loop_head >= m->basicblockindex[ex->startpc]) && (lc->loop_head < m->basicblockindex[ex->endpc]))
2697 ex->start = loop_head;
2700 /* an exception that ended at the old loop header now must contains the */
2701 /* new loop header as well */
2702 if (ex->end == loop_head)
2703 ex->end = original_start;
2709 /* insert new header node into nodelists of all enclosing loops */
2710 header_into_parent_loops(lc, loop_head, original_start, le->block);
2712 /* prepare instruction array to insert checks */
2713 inst = loop_head->iinstr = DMNEW(instruction, c_needed_instr + 2);
2714 loop_head->icount = c_needed_instr + 1;
2716 /* init instruction array */
2717 for (cnt=0; cnt<c_needed_instr + 1; ++cnt) {
2718 inst[0].opc = ICMD_NOP;
2722 loop_head->copied_to = NULL;
2725 loop_head->instack = copy_stack_from(bptr->instack);
2726 loop_head->outstack = copy_stack_from(bptr->instack);
2728 tos = loop_head->instack;
2729 stackdepth = loop_head->indepth;
2731 /* step through all inserted checks and create instructions for them */
2732 for (i=0; i<m->maxlocals+1; ++i)
2734 tc1 = c_constraints[i];
2740 /* check a variable against a constant */
2742 case TEST_UNMOD_ZERO:
2745 printf("insert ZERO-test\n");
2749 /* optimize if tc1->varRef >= tc1->constant */
2750 LOAD_VAR(tc1->varRef);
2751 LOAD_CONST(tc1->constant);
2755 /* check a variable against an array length */
2757 case TEST_UNMOD_ALENGTH:
2760 /* tc1->varRef + tc1->constant < lengthOf(tc1->arrayRef) */
2762 printf("insert ALENGTH-test\n");
2766 LOAD_VAR(tc1->varRef);
2767 LOAD_CONST(tc1->constant);
2769 LOAD_ARRAYLENGTH(tc1->arrayRef);
2773 /* test right side of comparison against constant */
2777 printf("insert RS-ZERO-test\n");
2781 /* optimize if right-side >= tc1->constant */
2783 LOAD_CONST(tc1->constant);
2787 /* test right side of comparison against array length */
2788 case TEST_RS_ALENGTH:
2791 printf("insert RS-ALENGTH-test\n");
2794 /* optimize if right-side < lengthOf(arrayRef) */
2796 LOAD_ARRAYLENGTH(tc1->arrayRef);
2800 /* test unmodified variable against arraylength */
2801 case TEST_CONST_ALENGTH:
2804 printf("insert CONST ALENGTH-test\n");
2808 /* optimize if tc1->constant < lengthOf(tc1->arrayRef) */
2809 LOAD_CONST(tc1->constant);
2810 LOAD_ARRAYLENGTH(tc1->arrayRef);
2817 c_constraints[i] = NULL;
2820 /* if all tests succeed, jump to optimized loop header */
2821 if (loop_head->next != original_start) {
2822 inst->opc = ICMD_GOTO;
2824 inst->target = original_start;
2827 /* redirect jumps from original loop head to newly inserted one */
2828 patch_jumps(original_start, loop_head, lc);
2830 /* if exceptions have to be correct due to loop duplication these two */
2831 /* functions perform this task. */
2832 update_internal_exceptions(m, lc, loop_head, original_start);
2833 update_external_exceptions(m, lc->parent, lc->loop_head);
2837 /* This function performs an update between two arrays of struct Changes (that
2838 reflect variable changes). The merge is performed unrstricted in the way, that
2839 all variable changes in c1 took place in a nested loop and therefore are
2840 considered to be without limit. Beside that, the merge is a simple union of the
2841 changes recorded in both arrays. A variable, which limits are undefinied, is
2842 represented by its lower bound being higher than the upper bound. The result
2843 of the union is stored in c1.
2845 struct Changes ** constraints_unrestricted_merge(methodinfo *m, struct Changes **c1, struct Changes **c2)
2849 if ((c1 == NULL) || (c2 == NULL))
2850 printf("C_ERROR: debugging error 0x03\n");
2853 for (i=0; i<m->maxlocals; ++i) {
2854 if (c1[i] == NULL) {
2855 if (c2[i] != NULL) { /* a change in c2 is updated in c1 */
2858 c1[i]->lower_bound = c1[i]->upper_bound+1;
2862 if (c1[i]->lower_bound > c1[i]->upper_bound)
2863 continue; /* variable's bounds already undefined */
2865 if (c2[i] == NULL) { /* variable changed in c1 -> now undef. */
2867 c1[i]->lower_bound = c1[i]->upper_bound+1;
2870 if ((c1[i]->lower_bound == c2[i]->lower_bound) &&
2871 (c1[i]->upper_bound == c2[i]->upper_bound))
2872 continue; /* variable's bounds remain the same */
2875 c1[i]->lower_bound = c1[i]->upper_bound+1;
2876 } /* variable changed in c1 -> now undef. */
2887 /* This function performs an update between two arrays of struct Changes (that
2888 reflect variable changes). The merge is a simple union of the bounds
2889 changes recorded in both arrays. A variable, which limits are undefinied, is
2890 represented by its lower bound being higher than the upper bound. The result
2891 of the union is stored in c1.
2893 struct Changes ** constraints_merge(methodinfo *m, struct Changes **c1, struct Changes **c2)
2897 if ((c1 == NULL) || (c2 == NULL))
2898 printf("C_ERROR: debugging error 0x04\n");
2902 for (i=0; i<m->maxlocals; ++i) {
2903 if (c1[i] == NULL) {
2904 if (c2[i] != NULL) { /* update changes in c2 in c1 */
2905 if ((c1[i] = (struct Changes *) malloc (sizeof(struct Changes))) == NULL)
2908 c1[i]->lower_bound = c2[i]->lower_bound;
2909 c1[i]->upper_bound = c2[i]->upper_bound;
2914 if (c2[i] != NULL) {
2916 if (c1[i]->lower_bound > c1[i]->upper_bound)
2917 continue; /* var in c1 is unrestricted */
2919 if (c1[i]->lower_bound > c2[i]->lower_bound) {
2920 c1[i]->lower_bound = c2[i]->lower_bound;
2921 changed = 1; /* write new lower bound */
2923 if (c1[i]->upper_bound < c2[i]->upper_bound) {
2924 c1[i]->upper_bound = c2[i]->upper_bound;
2925 changed = 1; /* write new higher bound */
2938 /* This function simply copies an array of changes
2940 struct Changes** constraints_clone(methodinfo *m, struct Changes **c)
2945 if ((t = (struct Changes **) malloc(m->maxlocals * sizeof(struct Changes *))) == NULL)
2948 for (i=0; i<m->maxlocals; ++i) { /* for all array elements (vars) do */
2952 if ((t[i] = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
2954 t[i]->lower_bound = c[i]->lower_bound;
2955 t[i]->upper_bound = c[i]->upper_bound;
2962 /* This function is used to reset the changes of a variable to the time, it was
2963 pushed onto the stack. If a variable has been modified between an instruction
2964 and a previous push onto the stack, its value in the changes array does not
2965 correctly reflect its bounds the time, it was pushed onto the stack. This
2966 function corrects the situation.
2968 struct Changes* backtrack_var(methodinfo *m, int node, int from, int to, int varRef, struct Changes *changes)
2970 struct Changes *tmp;
2975 if (changes == NULL) /* if there are no changes, immediately return */
2977 else { /* init a Changes structure with current values */
2978 if ((tmp = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
2981 tmp->upper_bound = changes->upper_bound;
2982 tmp->lower_bound = changes->lower_bound;
2985 if (tmp->upper_bound < tmp->lower_bound)
2986 return tmp; /* if it is unrestricted no backtracking can happen */
2988 bp = m->basicblocks[node];
2989 ip = bp.iinstr + to;
2991 for (; from < to; --to, --ip) { /* scan instructions backwards */
2993 case ICMD_IINC: /* a var has been modified */
2994 if (varRef != ip->op1) /* not the one, we are interested in */
2996 tmp->upper_bound -= ip->val.i; /* take back modifications */
2997 tmp->lower_bound -= ip->val.i;
3000 case ICMD_ISTORE: /* a var has been modified */
3001 if (varRef != ip->op1) /* not the one, we are interested in */
3004 /* it is our variable, so trace its origin */
3005 t = tracing(&m->basicblocks[node],to, 0);
3009 if ((t->var = ip->op1) && (t->neg > 0)) {
3010 /* it was the same var -> take back modifications */
3011 tmp->upper_bound -= t->constant;
3012 tmp->lower_bound -= t->constant;
3015 tmp->lower_bound = tmp->upper_bound+1; /* unknown */
3018 /* cannot restore it -> invalidate t */
3023 tmp->lower_bound = tmp->upper_bound+1;
3033 /* This function performs the main task of bound check removal. It removes
3034 all bound-checks in node. change is a pointer to an array of struct Changes
3035 that reflect for all local variables, how their values have changed from
3036 the start of the loop. The special flag is needed to deal with the header
3039 void remove_boundchecks(methodinfo *m, int node, int from, struct Changes **change, int special)
3043 int i, count, ignore, degrade_checks, opt_level;
3044 struct depthElement *d;
3045 struct Changes **t1, **tmp, *t;
3046 struct Trace *t_array, *t_index;
3048 /* printf("remove_bc called: %d - %d - %d\n", node, from, special); */
3050 /* a flag, that is set, when previous optimzations have to be taken back */
3053 if (c_current_loop[node] > 0) { /* this node is part of the loop */
3054 if (c_current_loop[node] > 1) { /* it is not the header node */
3056 /* get variable changes, already recorded for this node */
3057 t1 = c_dTable[node]->changes;
3059 if (t1 != NULL) { /* it is not the first visit */
3060 if ((c_nestedLoops[node] != c_current_head) && (c_nestedLoops[node] == c_nestedLoops[from])) {
3061 /* we are looping in a nested loop, so made optimizations */
3062 /* need to be reconsidered */
3064 if (constraints_unrestricted_merge(m, t1, change) == NULL)
3065 return; /* no changes since previous visit */
3066 /* if there have been changes, they are updated by */
3067 /* constraints_unrestricted_merge in t1 */
3070 if (constraints_merge(m, t1, change) == NULL)
3071 return; /* no changes since previous visit */
3072 /* if there have been changes, they are updated by */
3073 /* constraints_merge in t1 */
3076 else { /* first visit */
3077 /* printf("first visit - constraints cloned\n"); */
3078 c_dTable[node]->changes = constraints_clone(m, change);
3081 /* tmp now holds a copy of the updated variable changes */
3082 tmp = constraints_clone(m, c_dTable[node]->changes);
3084 else if (special) { /* header and need special traetment */
3085 /* printf("special treatment called\n"); */
3086 /* tmp now holds a copy of the current new variable changes */
3087 tmp = constraints_clone(m, change);
3092 bp = m->basicblocks[node]; /* scan all instructions */
3097 for (i=0; i<count; ++i, ++ip) {
3099 case ICMD_IASTORE: /* found an array store */
3108 t_index = tracing(&bp, i-1, 1); /* get index */
3109 t_array = tracing(&bp, i-1, 2); /* get array refernce */
3113 case ICMD_IALOAD: /* found an array load */
3122 t_index = tracing(&bp, i-1, 0); /* get index */
3123 t_array = tracing(&bp, i-1, 1); /* get array refernce */
3127 /* printf("Array access with params:\n");
3129 show_trace(t_array);
3131 show_trace(t_index);
3135 if (ip->op1 == OPT_UNCHECKED) { /* found new access */
3136 c_stat_array_accesses++;
3142 /* can only optimize known arrays that do not change */
3143 if ((t_array->type != TRACE_AVAR) || (c_var_modified[t_array->var]))
3146 switch (t_index->type) { /* now we look at the index */
3147 case TRACE_ICONST: /* it is a constant value or an */
3148 case TRACE_ALENGTH: /* array length */
3150 switch (ip->op1) { /* take back old optimzation */
3167 if (degrade_checks) /* replace existing optimization */
3168 ip->op1 = insert_static(m, t_array->var, t_index, NULL, special);
3170 /* Check current optimization and try to improve it by */
3171 /* inserting new checks */
3174 ip->op1 = insert_static(m, t_array->var, t_index, NULL, special);
3177 ip->op1 = insert_static(m, t_array->var, t_index, NULL, special);
3180 opt_level = insert_static(m, t_array->var, t_index, NULL, special);
3181 if ((opt_level == OPT_FULL) || (opt_level == OPT_LOWER))
3185 opt_level = insert_static(m, t_array->var, t_index, NULL, special);
3186 if ((opt_level == OPT_FULL) || (opt_level == OPT_UPPER))
3198 case TRACE_IVAR: /* it's a variable */
3200 /* if the variable is changed between its usage as an index */
3201 /* of the array access and its push onto the stack, we have */
3202 /* to set the changes back to the time, it is pushed onto */
3203 /* the stack as an index variable. */
3204 t = backtrack_var(m, node, t_index->nr, i-1, t_index->var, tmp[t_index->var]);
3206 switch (ip->op1) { /* take back old optimzation */
3224 ip->op1 = insert_static(m, t_array->var, t_index, t, special);
3226 /* Check current optimization and try to improve it by */
3227 /* insert new check. t reflects var changes for index */
3230 ip->op1 = insert_static(m, t_array->var, t_index, t, special);
3233 ip->op1 = insert_static(m, t_array->var, t_index, t, special);
3236 opt_level = insert_static(m, t_array->var, t_index, t, special);
3237 if ((opt_level == OPT_FULL) || (opt_level == OPT_LOWER))
3241 opt_level = insert_static(m, t_array->var, t_index, t, special);
3242 if ((opt_level == OPT_FULL) || (opt_level == OPT_UPPER))
3260 case ICMD_ISTORE: /* an integer value is stored */
3261 t_index = tracing(&bp, i-1, 0); /* trace back its origin */
3263 /* the struct Changes for this variable needs to be updated */
3265 if (t == NULL) { /* if it's the first one, create new entry */
3266 if ((t = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
3268 t->upper_bound = t->lower_bound = 0;
3272 switch (t_index->type) { /* check origin of store */
3274 case TRACE_ICONST: /* constant -> set bounds to const value */
3275 t->upper_bound = t->lower_bound = t_index->constant;
3278 case TRACE_IVAR: /* if it's the same variable, update consts */
3279 if ((t_index->var = ip->op1) && (t_index->neg > 0)) {
3280 t->upper_bound += t_index->constant;
3281 t->lower_bound += t_index->constant;
3284 t->lower_bound = t->upper_bound+1;
3287 case TRACE_ALENGTH: /* else -> unknown */
3290 t->lower_bound = t->upper_bound+1;
3298 /* the struct Changes for this variable needs to be updated */
3299 if ((t = tmp[ip->op1]) == NULL) { /* first one -> create new */
3300 if ((t = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
3302 t->upper_bound = t->lower_bound = ip->val.i;
3305 else { /* update changes, made by iinc */
3306 t->upper_bound += ip->val.i;
3307 t->lower_bound += ip->val.i;
3313 if (!special) { /* we are not interested in only the header */
3315 while (d != NULL) { /* check all sucessors of current node */
3316 remove_boundchecks(m, d->value, node, tmp, special);
3323 /* This function calls the bound-check removal function for the header node
3324 with a special flag. It is important to notice, that no dynamic
3325 constraint hold in the header node (because the comparison is done at
3328 void remove_header_boundchecks(methodinfo *m, int node, struct Changes **changes)
3330 remove_boundchecks(m, node, -1, changes, BOUNDCHECK_SPECIAL);
3333 /* Marks all basicblocks that are part of the loop
3335 void mark_loop_nodes(struct LoopContainer *lc)
3337 struct LoopElement *le = lc->nodes;
3339 while (le != NULL) {
3340 le->block->lflags |= LOOP_PART;
3345 /* Clears mark for all basicblocks that are part of the loop
3347 void unmark_loop_nodes(struct LoopContainer *lc)
3349 struct LoopElement *le = lc->nodes;
3351 while (le != NULL) {
3352 le->block->lflags = 0;
3358 /* This function performs the analysis of code in detected loops and trys to
3359 identify array accesses suitable for optimization (bound check removal). The
3360 intermediate code is then modified to reflect these optimizations.
3362 void optimize_single_loop(methodinfo *m, struct LoopContainer *lc)
3364 struct LoopElement *le;
3365 struct depthElement *d;
3367 struct Changes **changes;
3369 if ((changes = (struct Changes **) malloc(m->maxlocals * sizeof(struct Changes *))) == NULL)
3372 head = c_current_head = lc->loop_head;
3373 c_needed_instr = c_rs_needed_instr = 0;
3375 /* init array for null ptr checks */
3376 for (i=0; i<m->maxlocals; ++i)
3377 c_null_check[i] = 0;
3380 /* don't optimize root node (it is the main procedure, not a loop) */
3384 /* setup variables with initial values */
3386 for (i=0; i < m->basicblockcount; ++i) {
3388 c_current_loop[i] = -1;
3389 if ((d = c_dTable[i]) != NULL)
3393 for (i=0; i < m->maxlocals; ++i) {
3394 c_var_modified[i] = 0;
3395 if (changes[i] != NULL) {
3400 for (i=0; i < (m->maxlocals+1); ++i) {
3401 if (c_constraints[i] != NULL) {
3402 c_constraints[i] = NULL;
3407 while (le != NULL) {
3411 c_current_loop[node] = 1; /* the header node gets 1 */
3412 else if (c_nestedLoops[node] == head)
3413 c_current_loop[node] = 2; /* top level nodes get 2 */
3415 c_current_loop[node] = 3; /* nodes, part of nested loop get 3 */
3417 c_toVisit[node] = 1;
3421 /* After setup work has been performed, start to analyse */
3423 printf("****** Starting analysis (%d)******\n", head);
3427 if (analyze_for_array_access(m, head) > 0) {/* loop contains array access */
3432 printf("analyze for array access finished and found\n");
3435 while (lv != NULL) {
3437 printf("Var --> %d\n", lv->value);
3442 /* for performance reasons the list of all interesting loop vars is */
3443 /* scaned and for all modified vars a flag in c_var_modified is set */
3447 printf("global list scanned\n");
3451 /* if the loop header contains or-conditions or an index variable */
3452 /* is modified in the catch-block within the loop, a conservative */
3453 /* approach is taken and optimizations are cancelled */
3454 if (analyze_or_exceptions(m, head, lc) > 0) {
3457 printf("Analyzed for or/exception - no problems \n");
3461 init_constraints(m, head); /* analyze dynamic bounds in header */
3467 if (c_rightside == NULL)
3470 /* single pass bound check removal - for all successors, do */
3471 remove_header_boundchecks(m, head, changes);
3475 remove_boundchecks(m, d->value, -1, changes, BOUNDCHECK_REGULAR);
3480 printf("Array-bound checks finished\n");
3484 mark_loop_nodes(lc);
3487 printf("START: create static checks\n");
3491 create_static_checks(m, lc); /* create checks */
3494 printf("END: create static checks\n");
3497 unmark_loop_nodes(lc);
3501 printf("No array accesses found\n"); */
3504 c_stat_num_loops++; /* increase number of loops */
3506 c_stat_sum_accesses += c_stat_array_accesses;
3507 c_stat_sum_full += c_stat_full_opt;
3508 c_stat_sum_no += c_stat_no_opt;
3509 c_stat_sum_lower += c_stat_lower_opt;
3510 c_stat_sum_upper += c_stat_upper_opt;
3511 c_stat_sum_or += c_stat_or;
3512 c_stat_sum_exception += c_stat_exception;
3514 c_stat_array_accesses = 0;
3515 c_stat_full_opt = 0;
3517 c_stat_lower_opt = 0;
3518 c_stat_upper_opt = 0;
3519 c_stat_or = c_stat_exception = 0;
3524 /* This function preforms necessary setup work, before the recursive function
3525 optimize_single loop can be called.
3527 void optimize_loops(methodinfo *m)
3529 struct LoopContainer *lc = c_allLoops;
3531 /* first, merge loops with same header node - all loops with the same */
3532 /* header node are optimizied in one pass, because they all depend on the */
3533 /* same dynamic loop condition */
3536 printf("start analyze_double_headers\n");
3540 analyze_double_headers();
3542 /* create array with loop nesting levels - nested loops cause problems, */
3543 /* especially, when they modify index variables used in surrounding loops */
3544 /* store results in array c_nestedLoops and c_hierarchie */
3547 printf("double done\n");
3554 printf("analyze nested done\n");
3558 /* create array with entries for current loop */
3559 c_current_loop = DMNEW(int, m->basicblockcount);
3560 c_toVisit = DMNEW(int, m->basicblockcount);
3561 c_var_modified = DMNEW(int, m->maxlocals);
3562 c_null_check = DMNEW(int, m->maxlocals);
3564 if ((c_constraints = (struct Constraint **) malloc((m->maxlocals+1) * sizeof(struct Constraint *))) == NULL)
3568 c_stat_num_loops = 0; /* set statistic vars to zero */
3569 c_stat_array_accesses = c_stat_sum_accesses = 0;
3570 c_stat_full_opt = c_stat_sum_full = 0;
3571 c_stat_no_opt = c_stat_sum_no = 0;
3572 c_stat_lower_opt = c_stat_sum_lower = 0;
3573 c_stat_upper_opt = c_stat_sum_upper = 0;
3574 c_stat_or = c_stat_sum_or = 0;
3575 c_stat_exception = c_stat_sum_exception = 0;
3578 /* init vars needed by all loops */
3579 c_needs_redirection = false;
3581 c_old_xtablelength = m->exceptiontablelength;
3583 /* loops have been topologically sorted */
3585 while (lc != NULL) {
3586 optimize_single_loop(m, lc);
3589 printf(" *** Optimized loop *** \n");
3596 printf("---*** All loops finished ***---\n");
3600 /* if global BB list start is modified, set block to new start */
3601 if (c_needs_redirection == true)
3602 m->basicblocks = c_newstart;
3608 * These are local overrides for various environment variables in Emacs.
3609 * Please do not remove this and leave it at the end of the file, where
3610 * Emacs will automagically detect them.
3611 * ---------------------------------------------------------------------
3614 * indent-tabs-mode: t