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 576 2003-11-09 17:31:38Z twisti $
47 #include "toolbox/loging.h"
48 #include "toolbox/memory.h"
53 /* Test functions -> will be removed in final release
56 void show_trace(struct Trace *trace)
59 switch (trace->type) {
62 printf("\nNr.:\t%d", trace->var);
63 printf("\nValue:\t%d", trace->constant);
68 printf("\nNr.:\t%d", trace->var);
72 printf("array-length");
73 printf("\nNr.:\t%d", trace->var);
74 printf("\nValue:\t%d", trace->constant);
79 printf("\nValue:\t%d", trace->constant);
88 printf("Trace is null");
94 void show_change(struct Changes *c)
96 printf("*** Changes ***\n");
98 printf("Lower/Upper Bound:\t%d/%d\n", c->lower_bound, c->upper_bound);
100 printf("Unrestricted\n");
103 show_varinfo(struct LoopVar *lv)
105 printf(" *** Loop Info ***\n");
106 printf("Value:\t%d\n", lv->value);
107 printf("Static:\t\t%d/%d\n", lv->static_l, lv->static_u);
108 printf("D-Valid:\t%d/%d\n", lv->dynamic_l_v, lv->dynamic_u_v);
109 printf("Dynamic\t\t%d/%d\n", lv->dynamic_l, lv->dynamic_u);
112 void show_right_side()
115 printf("\n *** Head *** \nType:\t");
116 show_trace(c_rightside);
118 printf("\n *** Nested Loops: ***\n");
119 for (i=0; i<block_count; ++i)
120 printf("%d\t", c_nestedLoops[i]);
123 printf("\n *** Hierarchie: ***\n");
124 for (i=0; i<block_count; ++i)
125 printf("%d\t", c_hierarchie[i]);
129 printf("\n *** Current Loop ***\n");
130 for (i=0; i<block_count; ++i)
131 printf("%d\t", c_current_loop[i]);
138 struct LoopContainer *lc = c_allLoops;
140 printf("\n\n****** PASS 3 ******\n\n");
143 printf("Loop Analysis:\n");
144 printf("Optimize:\t%d\n", lc->toOpt);
145 printf("Modified Vars: ");
147 for (i=0; i<lc->num_vars; ++i)
148 printf("%d ", lc->vars[i]);
154 printf("\nNested Loops:\n");
155 for (i=0; i<block_count; ++i)
156 printf("%d ", c_nestedLoops[i]);
158 for (i=0; i<block_count; ++i)
159 printf("%d ", c_hierarchie[i]);
164 void show_tree(struct LoopContainer *lc, int tabs)
169 for (cnt = 0; cnt < tabs; ++cnt)
171 printf("%d\n", lc->loop_head);
173 show_tree(lc->tree_down, tabs+1);
183 void show_loop_statistics()
185 printf("\n\n****** LOOP STATISTICS ****** \n\n");
187 printf("Optimization cancelled by or\n");
188 else if (c_stat_exception)
189 printf("Optimization cancelled by exception\n");
191 printf("Number of array accesses:\t%d\n", c_stat_array_accesses);
192 if (c_stat_array_accesses) {
193 printf("\nFully optimized:\t%d\n", c_stat_full_opt);
194 printf("Not optimized:\t\t%d\n", c_stat_no_opt);
195 printf("Upper optimized:\t%d\n", c_stat_upper_opt);
196 printf("Lower optimized:\t%d\n", c_stat_lower_opt);
201 void show_procedure_statistics()
203 printf("\n\n****** PROCEDURE STATISTICS ****** \n\n");
204 printf("Number of loops:\t\t%d\n", c_stat_num_loops);
205 printf("Number of array accesses:\t%d\n", c_stat_sum_accesses);
206 if (c_stat_sum_accesses) {
207 printf("\nFully optimized:\t%d\n", c_stat_sum_full);
208 printf("Not optimized:\t\t%d\n", c_stat_sum_no);
209 printf("Upper optimized:\t%d\n", c_stat_sum_upper);
210 printf("Lower optimized:\t%d\n", c_stat_sum_lower);
212 printf("Opt. cancelled by or:\t\t%d\n", c_stat_sum_or);
213 printf("Opt. cancelled by exception:\t%d\n", c_stat_sum_exception);
219 /* This function is used to merge two loops with the same header together.
220 A simple merge sort of the lists nodes of both loops is performed.
222 void analyze_merge(struct LoopContainer *l1, struct LoopContainer *l2)
224 struct LoopElement *start, *last, *le1, *le2;
225 /* start and last are pointers to the newly built list, le1 and le2 step */
226 /* step through the lists, that have to be merged. */
231 /* start a simple merge sort of the nodes of both loops. These lists are */
232 /* already sorted, so merging is easy. */
233 if (le1->node < le2->node) {
237 else if (le1->node == le2->node) {
247 /* while the first loop != NULL, depending of the first element of second */
248 /* loop, add new node to result list */
249 while (le1 != NULL) {
255 if (le1->node < le2->node) {
259 else if (le1->node == le2->node) {
276 /* This function is used to merge loops with the same header node to a single
277 one. O(n^2) of number of loops. This merginig is necessary, because the loop
278 finding algorith sometimes (eg. when loopbody ends with a if-else construct)
279 reports a single loop as two loops with the same header node.
281 void analyze_double_headers()
284 struct LoopContainer *t1, *t2, *t3;
288 while (t1 != NULL) { /* for all loops do */
289 toCheck = t1->loop_head; /* get header node */
292 while (t2 != NULL) { /* compare it to headers of rest */
293 if (t2->loop_head == toCheck) {
295 /* found overlapping loops -> merge them together */
296 /* printf("C_INFO: found overlapping loops - merging"); */
297 analyze_merge(t1, t2);
299 /* remove second loop from the list of all loops */
301 while (t3->next != t2)
313 /* After the hierarchie of loops has been built, we have to insert the exceptions
314 into this tree. The exception ex is inserted into the subtree pointed to by
317 void insert_exception(struct LoopContainer *lc, xtable *ex)
319 struct LoopContainer *temp;
320 struct LoopElement *le;
323 /* printf("insert_exception called with %d-%d and loop %d\n", ex->start->debug_nr, ex->end->debug_nr, lc->loop_head); */
326 /* if child node is reached immediately insert exception into the tree */
327 if (lc->tree_down == NULL) {
328 ex->next = lc->exceptions;
332 /* if we are inside the tree, there are two possibilities: */
333 /* 1. the exception is inside a nested loop or */
334 /* 2. in the loop body of the current loop */
336 /* check all children (= nested loops) */
337 temp = lc->tree_down;
339 while (temp != NULL) {
345 printf("%d.%d\n", le->node, block_index[ex->startpc]);
347 /* if the start of the exception is part of the loop, the */
348 /* whole exception must be part of the loop */
349 if (le->node == block_index[ex->startpc])
354 /* Exception is part of a nested loop (Case 1) -> insert it there */
356 insert_exception(temp, ex);
359 else if ((temp->loop_head >= block_index[ex->startpc]) && (temp->loop_head < block_index[ex->endpc])) {
361 /* optimization: if nested loop is part of the exception, the */
362 /* exception cannot be part of a differnet nested loop. */
363 ex->next = lc->exceptions;
368 temp = temp->tree_right;
371 /* Exception is not contained in any nested loop (Case 2) */
373 ex->next = lc->exceptions;
380 /* This function builds a loop hierarchie. The header node of the innermost loop,
381 each basic block belongs to, is stored in the array c_nestedLoops. The array
382 c_hierarchie stores the relationship between differnt loops in as follows:
383 Each loop, that is a nested loop, stores its direct surrounding loop as a
384 parent. Top level loops have no parents.
386 void analyze_nested()
388 /* i/count/tmp are counters */
389 /* toOverwrite is used while loop hierarchie is built (see below) */
390 int i, header, toOverwrite, tmp, len;
392 /* first/last are used during topological sort to build ordered loop list */
393 struct LoopContainer *first, *last, *start, *t, *temp;
395 /* Used to step through all nodes of a loop. */
396 struct LoopElement *le;
398 /* init global structures */
399 c_nestedLoops = DMNEW(int, block_count);
400 c_hierarchie = DMNEW(int, block_count);
401 for (i=0; i<block_count; ++i) {
402 c_nestedLoops[i] = -1;
403 c_hierarchie[i] = -1;
406 /* if there are no optimizable loops -> return */
407 if (c_allLoops == NULL)
411 while (temp != NULL) { /* for all loops, do */
412 header = temp->loop_head;
414 /* toOverwrite is number of current parent loop (-1 if none) */
415 toOverwrite = c_nestedLoops[header];
417 c_hierarchie[header] = toOverwrite;
419 if (toOverwrite == header) /* check for loops with same header */
420 printf("C_ERROR: Loops have same header\n");
423 while (le != NULL) { /* for all loop nodes, do */
424 tmp = c_nestedLoops[le->node];
426 /* if node is part of parent loop -> overwrite it with nested */
427 if (tmp == toOverwrite)
428 c_nestedLoops[le->node] = header;
430 c_hierarchie[tmp] = header;
432 /* printf("set head of %d to %d", tmp, header); */
442 /* init root of hierarchie tree */
443 root = DMNEW(struct LoopContainer, 1);
444 LoopContainerInit(root, -1);
446 /* obtain parent pointer and build hierarchie tree */
448 while (start != NULL) {
450 /* look for parent of loop pointed at by start */
452 while (first != NULL) {
454 /* the parent of the loop, pointed at by start has been found */
455 if (first->loop_head == c_hierarchie[start->loop_head]) {
457 /* printf("set parent to pointer\n"); */
460 start->parent = first;
461 start->tree_right = first->tree_down;
462 first->tree_down = start;
469 /* no parent loop found, set parent to root */
472 /* printf("set parent to root\n"); */
475 start->parent = root;
476 start->tree_right = root->tree_down;
477 root->tree_down = start;
479 /* if a parent exists, increase this nodes indegree */
481 start->parent->in_degree += 1;
486 /* insert exceptions into tree */
488 printf("--- Showing tree ---\n");
490 printf(" --- End ---\n");
492 for (len = 0; len < exceptiontablelength; ++len)
493 insert_exception(root, extable + len);
496 /* determine sequence of loops for optimization by topological sort */
501 while (temp != NULL) {
503 /* a loops with indegree == 0 are pushed onto the stack */
504 if (temp->in_degree == 0) {
516 first = last = start;
520 printf("C_ERROR: loops are looped\n");
524 /* pop each node from the stack and decrease its parents indegree by one */
525 /* when the parents indegree reaches zero, push it onto the stack as well */
526 if ((last->parent != root) && (--last->parent->in_degree == 0)) {
527 last->parent->next = start;
528 start = last->parent;
530 while (start != NULL) {
537 if ((last->parent != root) && (--last->parent->in_degree == 0)) {
538 last->parent->next = start;
539 start = last->parent;
547 printf("*** Hierarchie Results \n");
548 while (first != NULL) {
549 printf("%d ", first->loop_head);
557 /* This function is used to add variables that occur as index variables in
558 array accesses (ARRAY_INDEX) or as variables, that change their value (VAR_MOD)
559 to the list of interesting vars (c_loopvars) for the current loop.
561 void add_to_vars(int var, int type, int direction)
565 /* printf("Added to vars %d %d %d\n", var, type, direction); */
567 while (lv != NULL) { /* check if var has been previously added */
568 if (lv->value == var) {
569 if (type == ARRAY_INDEX)
570 lv->index = 1; /* var is used as index */
571 else if (type == VAR_MOD) {
572 lv->modified = 1; /* var is used in assignment */
573 switch (direction) { /* how was var modified ? */
575 lv->static_u = 0; /* incremented, no static upper */
576 break; /* bound can be guaranteeed */
578 lv->static_l = 0; /* decremented, no static lower */
579 break; /* bound can be guaranteeed */
581 lv->static_u = lv->static_l = 0;
582 break; /* no info at all */
584 printf("C_ERROR: unknown direction\n");
593 /* variable is not found in list -> add variable to list */
594 lv = DNEW(struct LoopVar);
596 lv->modified = lv->index = 0;
599 if (type == ARRAY_INDEX) {
601 lv->static_u = lv->static_l = 1; /* arrayindex -> var not modified */
603 else if (type == VAR_MOD) {
605 switch (direction) { /* var used in assignment -> set */
606 case D_UP: /* proper static bounds */
607 lv->static_u = 0; lv->static_l = 1;
610 lv->static_u = 1; lv->static_l = 0;
613 lv->static_u = lv->static_l = 0;
616 printf("C_ERROR: unknown direction\n");
621 /* no dynamic bounds have been determined so far */
622 lv->dynamic_l = lv->dynamic_l_v = lv->dynamic_u = lv->dynamic_u_v = 0;
624 lv->next = c_loopvars; /* add var to list */
628 /* This function checks, whether a given loop with header node contains array
629 accesses. If so, it returns 1, else it returns 0 and the loops needs no
630 further consideration in the optimization process. When array accesses are
631 found, a list of all variables, that are used as array index, is built and
632 stored in c_loopvars. For all variables (integer), which values are changed,
633 a flag in c_var_modified is set.
635 int analyze_for_array_access(int node)
640 struct depthElement *d;
643 if (c_toVisit[node] > 0) { /* node has not been visited yet */
646 bp = block[node]; /* prepare an instruction scan */
650 access = 0; /* number of array accesses in loop */
652 for (i=0; i<ic; ++i, ++ip) { /* for each instruction, check opcode */
654 case ICMD_IASTORE: /* array store */
662 t = tracing(&bp, i-1, 1); /* try to identify index variable */
664 if (t->type == TRACE_IVAR) {
665 /* if it is a variable, add it to list of index variables */
666 add_to_vars(t->var, ARRAY_INDEX, D_UNKNOWN);
669 else if (t->type == TRACE_ICONST)
673 case ICMD_IALOAD: /* array load */
681 t = tracing(&bp, i-1, 0); /* try to identify index variable */
683 if (t->type == TRACE_IVAR) {
684 /* if it is a variable, add it to list of index variables */
685 add_to_vars(t->var, ARRAY_INDEX, D_UNKNOWN);
688 else if (t->type == TRACE_ICONST)
692 case ICMD_ISTORE: /* integer store */
693 c_var_modified[ip->op1] = 1;
695 /* try to find out, how it was modified */
696 t = tracing(&bp, i-1, 0);
697 if (t->type == TRACE_IVAR) {
698 if ((t->constant > 0) && (t->var == ip->op1))
699 /* a constant was added to the same var */
700 add_to_vars(t->var, VAR_MOD, D_UP);
701 else if (t->var == ip->op1)
702 /* a constant was subtracted from the same var */
703 add_to_vars(t->var, VAR_MOD, D_DOWN);
705 add_to_vars(t->var, VAR_MOD, D_UNKNOWN);
708 add_to_vars(ip->op1, VAR_MOD, D_UNKNOWN);
711 case ICMD_IINC: /* simple add/sub of a constant */
712 c_var_modified[ip->op1] = 1;
715 add_to_vars(ip->op1, VAR_MOD, D_UP);
717 add_to_vars(ip->op1, VAR_MOD, D_DOWN);
724 c_var_modified[ip->op1] = 1;
730 while (d != NULL) { /* check all successors of block */
731 access += analyze_for_array_access(d->value);
741 /* This function scans the exception graph structure to find modifications of
742 array index variables of the current loop. If any modifications are found,
743 1 is returned, else 0.
745 int quick_scan(int node)
751 struct depthElement *d;
753 /* printf("QS: %d - %d\n", node, c_exceptionVisit[node]); */
756 if (c_exceptionVisit[node] > 0) { /* node is part of exception graph */
757 c_exceptionVisit[node] = -1;
759 bp = block[node]; /* setup scan of all instructions */
763 for (i=0; i<count; ++i, ++ip) { /* for each instruction do */
766 case ICMD_IINC: /* a variable is modified */
768 lv = c_loopvars; /* is it an array index var ? */
770 if ((lv->index) && (lv->value == ip->op1))
771 return 1; /* yes, so return 1 */
778 d = c_exceptionGraph[node]; /* check all successor nodes */
780 if (quick_scan(d->value) > 0)
781 return 1; /* if an access is found return 1 */
785 return 0; /* nothing found, so return 0 */
791 /* This function returns 1, when the condition of the loop contains
792 or statements or when an array index variable is modified in any
793 catch block within the loop.
795 int analyze_or_exceptions(int head, struct LoopContainer *lc)
797 struct depthElement *d;
798 int i, k, value, flag, count;
799 struct LoopElement *le;
804 /* analyze for or-statements */
806 printf("*** Analyze for OR ... ");
810 while (d != NULL) { /* for all successor nodes check if they */
811 value = d->value; /* are part of the loop */
816 if (le->node == value)
821 if (le == NULL) /* node is not part of the loop */
828 if ((count > 1) && (flag == 0)){/* if all successors part of the loop, exit */
835 /* check for exceptions */
836 /* printf("done\n*** Analyze for EXCEPTIONS(%d) . ", exceptiontablelength); */
838 if (!exceptiontablelength) /* when there are no exceptions, exit */
841 if ((c_exceptionGraph = (struct depthElement **) malloc(sizeof(struct depthElement *) * block_count)) == NULL)
843 if ((c_exceptionVisit = (int *) malloc(sizeof(int) * block_count)) == NULL)
846 for (k=0; k<block_count; ++k) {
847 c_exceptionVisit[k] = -1;
848 c_exceptionGraph[k] = NULL;
852 /* for all nodes that start catch block check whether they are part of loop */
853 for (i = 0; i < c_old_xtablelength; i++) {
854 value = block_index[extable[i].startpc];
859 if (le->node == value) { /* exception is in loop */
861 printf("C_INFO: Loop contains exception\n");
865 /* build a graph structure, that contains all nodes that are */
866 /* part of the catc block */
867 dF_Exception(-1, block_index[extable[i].handlerpc]);
869 /* if array index variables are modified there, return 0 */
870 if (quick_scan(block_index[extable[i].handlerpc]) > 0) {
874 /* printf("C_INFO: loopVar modified in exception\n"); */
883 printf("none ... done\n");
889 /* This function sets a flag in c_var_modified for all variables that have
890 been found as part of an assigment in the loop.
892 void scan_global_list()
899 c_var_modified[lv->value] = 1;
904 /* This function analyses the condition in the loop header and trys to find
905 out, whether some dynamic guarantees can be set up.
907 void init_constraints(int head)
911 int ic, l_mod, r_mod, changed, operand;
912 struct Trace *left, *right, *th;
913 struct LoopVar *lv_left, *lv_right, *lh;
917 ip = bp.iinstr+(ic-1); /* set ip to last instruction in header node */
919 switch (ip->opc) { /* check op-code */
921 /* comparison against constant value */
922 case ICMD_IFEQ: /* ..., value ==> ... */
923 case ICMD_IFLT: /* ..., value ==> ... */
924 case ICMD_IFLE: /* ..., value ==> ... */
925 case ICMD_IFGT: /* ..., value ==> ... */
926 case ICMD_IFGE: /* ..., value ==> ... */
927 /* op1 = target JavaVM pc, val.i = constant */
929 left = tracing(&bp, ic-2, 0); /* analyse left arg., right is constant */
930 right = create_trace(TRACE_ICONST, -1, ip->val.i, 0);
933 /* standard comparison */
934 case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */
935 case ICMD_IF_ICMPLT: /* ..., value, value ==> ... */
936 case ICMD_IF_ICMPGT: /* ..., value, value ==> ... */
937 case ICMD_IF_ICMPLE: /* ..., value, value ==> ... */
938 case ICMD_IF_ICMPGE: /* ..., value, value ==> ... */
940 left = tracing(&bp, ic-2, 1); /* get left and right argument */
941 right = tracing(&bp, ic-2, 0);
944 /* other condition */
946 left = create_trace(TRACE_UNKNOWN, -1, 0, 0);
947 right = create_trace(TRACE_UNKNOWN, -1, 0, 0);
951 /* analyse left and right side of comparison */
954 if (left->type == TRACE_IVAR) { /* is a loop variable on left side ? */
955 lv_left = c_loopvars;
956 while (lv_left != NULL) {
957 if (lv_left->value == left->var) {
958 l_mod = lv_left->modified; /* yes, but has it been modified ? */
961 lv_left = lv_left->next;
965 if (right->type == TRACE_IVAR){ /* is a loop variable on right side ? */
966 lv_right = c_loopvars;
967 while (lv_right != NULL) {
968 if (lv_right->value == right->var) {
969 r_mod = lv_right->modified; /* yes, but has it been modified ? */
972 lv_right = lv_right->next;
976 if ((l_mod - r_mod) == 0) { /* both 1 or both 0 -> no dynamic contraints*/
977 c_rightside = NULL; /* possible */
981 /* to simplify processing, make the left side the one, that contains the */
982 /* modified variable */
984 th = left; left = right; right = th;
985 lh = lv_left; lv_left = lv_right; lv_right = lh;
986 changed = 1; /* set changed to true */
989 changed = 0; /* no change needed */
991 /* make sure that right side's value does not change during loop execution */
992 if (right->type == TRACE_UNKNOWN) {
997 /* determine operands: */
998 /* for further explaination a is modified, b nonmodified var */
999 switch (ip->opc) { /* check opcode again */
1000 case ICMD_IFEQ: /* ..., value ==> ... */
1001 case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */
1002 operand = OP_EQ; /* a == b */
1005 case ICMD_IFLE: /* ..., value ==> ... */
1006 case ICMD_IF_ICMPLE: /* ..., value, value ==> ... */
1008 operand = OP_GE; /* b<=a -> a>=b */
1010 operand = OP_LT; /* a<=b -> a<(b+1) */
1011 if (left->constant != 0)
1012 left->constant -= 1;
1014 right->constant += 1;
1018 case ICMD_IFLT: /* ..., value ==> ... */
1019 case ICMD_IF_ICMPLT: /* ..., value, value ==> ... */
1021 operand = OP_GE; /* b<a -> a>=(b+1) */
1022 if (left->constant != 0)
1023 left->constant -= 1;
1025 right->constant += 1;
1028 operand = OP_LT; /* a<b -> a<b */
1031 case ICMD_IFGT: /* ..., value ==> ... */
1032 case ICMD_IF_ICMPGT: /* ..., value, value ==> ... */
1034 operand = OP_LT; /* b>a -> a<b */
1036 operand = OP_GE; /* a>b -> a>=(b+1) */
1037 if (left->constant != 0)
1038 left->constant -= 1;
1040 right->constant += 1;
1044 case ICMD_IFGE: /* ..., value ==> ... */
1045 case ICMD_IF_ICMPGE: /* ..., value, value ==> ... */
1047 operand = OP_LT; /* b>=a -> a<(b+1) */
1048 if (left->constant != 0)
1049 left->constant -= 1;
1051 right->constant += 1;
1054 operand = OP_GE; /* a>=b -> a>=b */
1058 printf("C_ERROR: debugging error 0x00\n");
1062 /* NOW: left/lv_left -> loopVar */
1063 /* right/lv_right -> const, nonmod. var, arraylength */
1064 switch (operand) { /* check operand */
1066 lv_left->dynamic_u_v = 1; /* upper + lower bound tested */
1067 lv_left->dynamic_l_v = 1;
1069 lv_left->dynamic_l = lv_left->dynamic_u = left->constant;
1073 lv_left->dynamic_u_v = 1; /* upper bound tested */
1075 lv_left->dynamic_u = left->constant;
1079 lv_left->dynamic_l_v = 1; /* lower bound tested */
1081 lv_left->dynamic_l = left->constant;
1085 printf("C_ERROR: debugging error 0x01\n");
1088 c_rightside = right;
1090 switch (c_rightside->type) {
1092 c_rs_needed_instr = 1;
1095 c_rs_needed_instr = 2;
1098 c_rs_needed_instr = 3;
1101 printf("C_ERROR: wrong right-side type\n");
1105 /* This function is needed to add and record new static tests (before loop
1106 entry) of variables to make guaratees for index variables. type states
1107 the kind of the test. arrayRef is the array, which length is tested
1108 against, varRef is the variable, that is testes and constant is the
1109 constant value, that is tested.
1111 void add_new_constraint(int type, int arrayRef, int varRef, int constant)
1113 struct Constraint *tc;
1116 case TEST_ZERO: /* a variable is tested against a const */
1118 tc = c_constraints[varRef]; /* does a test already exist for this var ? */
1119 while (tc != NULL) {
1120 if (tc->type == TEST_ZERO) {
1121 if (constant < tc->constant)
1122 tc->constant = constant;
1123 return; /* yes. update constant and return */
1128 /* insert a new test for this variable */
1129 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1131 tc->type = TEST_ZERO;
1132 tc->varRef = varRef;
1133 tc->constant = constant;
1134 tc->next = c_constraints[varRef];
1135 c_constraints[varRef] = tc;
1136 c_needed_instr += 3;
1140 case TEST_ALENGTH: /* variable is tested against array length */
1142 tc = c_constraints[varRef]; /* does a test already exist for this var ? */
1143 while (tc != NULL) {
1144 if ((tc->type == TEST_ALENGTH) && (tc->arrayRef == arrayRef)) {
1145 if (constant > tc->constant)
1146 tc->constant = constant;
1147 return; /* yes. update constant and return */
1152 /* insert a new test for this variable */
1153 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1155 tc->type = TEST_ALENGTH;
1156 tc->arrayRef = arrayRef;
1157 tc->varRef = varRef;
1158 tc->constant = constant;
1159 tc->next = c_constraints[varRef];
1160 c_constraints[varRef] = tc;
1161 c_needed_instr += 6;
1163 /* if arrayRef is not already tested against null, insert that test */
1164 if (!(c_null_check[arrayRef])) {
1165 c_null_check[arrayRef] = 1;
1171 case TEST_CONST_ZERO:
1175 case TEST_CONST_ALENGTH: /* a const is tested against array length */
1177 /* does a test already exist for this array */
1178 tc = c_constraints[maxlocals];
1179 while (tc != NULL) {
1180 if ((tc->type == TEST_CONST_ALENGTH) && (tc->arrayRef == arrayRef)) {
1181 if (constant > tc->constant)
1182 tc->constant = constant;
1183 return; /* yes. update constant and return */
1188 /* insert a new test for this array */
1189 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1191 tc->type = TEST_CONST_ALENGTH;
1192 tc->arrayRef = arrayRef;
1193 tc->constant = constant;
1194 tc->next = c_constraints[maxlocals];
1195 c_constraints[maxlocals] = tc;
1196 c_needed_instr += 4;
1198 /* if arrayRef is not already tested against null, insert that test */
1199 if (!(c_null_check[arrayRef])) {
1200 c_null_check[arrayRef] = 1;
1206 case TEST_UNMOD_ZERO: /* test unmodified var against constant */
1208 /* search if test already exists */
1209 tc = c_constraints[varRef];
1210 while (tc != NULL) {
1211 if (tc->type == TEST_UNMOD_ZERO) {
1212 if (constant < tc->constant)
1213 tc->constant = constant;
1214 return; /* yes, so update constant */
1219 /* else, a new test is inserted */
1220 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1222 tc->type = TEST_UNMOD_ZERO;
1223 tc->varRef = varRef;
1224 tc->constant = constant;
1225 tc->next = c_constraints[varRef];
1226 c_constraints[varRef] = tc;
1227 c_needed_instr += 3;
1231 case TEST_UNMOD_ALENGTH: /* test unmodified var against array length */
1233 /* search if test alreay exists */
1234 tc = c_constraints[varRef];
1235 while (tc != NULL) {
1236 if ((tc->type == TEST_UNMOD_ALENGTH) && (tc->arrayRef == arrayRef)) {
1237 if (constant > tc->constant)
1238 tc->constant = constant;
1239 return; /* yes, so modify constants */
1244 /* create new entry */
1245 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1247 tc->type = TEST_UNMOD_ALENGTH;
1248 tc->varRef = varRef;
1249 tc->arrayRef = arrayRef;
1250 tc->constant = constant;
1251 tc->next = c_constraints[varRef];
1252 c_constraints[varRef] = tc;
1253 c_needed_instr += 6;
1255 /* if arrayRef is not already tested against null, insert that test */
1256 if (!(c_null_check[arrayRef])) {
1257 c_null_check[arrayRef] = 1;
1263 case TEST_RS_ZERO: /* test right side of the loop condition */
1264 /* against a constant - needed by dynamic */
1266 /*!! varRef -> maxlocals */
1267 /* search if test already exists */
1268 tc = c_constraints[maxlocals];
1269 while (tc != NULL) {
1270 if (tc->type == TEST_RS_ZERO) {
1271 if (constant < tc->constant)
1272 tc->constant = constant;
1273 return; /* yes, so modify constants */
1278 /* create new entry */
1279 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1281 tc->type = TEST_RS_ZERO;
1282 tc->constant = constant;
1283 tc->next = c_constraints[maxlocals];
1284 c_constraints[maxlocals] = tc;
1285 c_needed_instr += (2 + c_rs_needed_instr);
1287 /* if arrayRef on right side is not already tested against null, */
1288 /* insert that test */
1289 if ((c_rightside->type == TRACE_ALENGTH) && (!(c_null_check[c_rightside->var]))) {
1290 c_null_check[c_rightside->var] = 1;
1296 case TEST_RS_ALENGTH: /* test right side of the loop condition */
1297 /* against array length - needed by dynamic */
1299 /*!! varRef -> maxlocals */
1300 /* search if test already exists */
1301 tc = c_constraints[maxlocals];
1304 if ((tc->type == TEST_RS_ALENGTH) && (tc->arrayRef == arrayRef))
1306 if (constant > tc->constant)
1307 tc->constant = constant;
1308 return; /* yes, so modify constants */
1313 /* create new entry */
1314 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1316 tc->type = TEST_RS_ALENGTH;
1317 tc->arrayRef = arrayRef;
1318 tc->constant = constant;
1319 tc->next = c_constraints[maxlocals];
1320 c_constraints[maxlocals] = tc;
1321 c_needed_instr += (3 + c_rs_needed_instr);
1323 /* if arrayRef is not already tested against null, insert that test */
1324 if (!(c_null_check[arrayRef])) {
1325 c_null_check[arrayRef] = 1;
1329 /* if arrayRef on right side is not already tested against null, */
1330 /* insert that test */
1331 if ((c_rightside->type == TRACE_ALENGTH) && (!(c_null_check[c_rightside->var]))) {
1332 c_null_check[c_rightside->var] = 1;
1340 /* This functions adds new static (before loop enry) tests of variables to the
1341 program to be able to guarantee certain values for index variables in array
1342 access (to safely remove bound checks).
1344 int insert_static(int arrayRef, struct Trace *index, struct Changes *varChanges, int special)
1350 /* printf("insert static check - %d\n", arrayRef);
1352 show_change(varChanges);
1355 if (varChanges == NULL) { /* the variable hasn't changed / const */
1356 if ((varChanges = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
1358 varChanges->lower_bound = varChanges->upper_bound = 0;
1361 switch (index->type) { /* check index type */
1362 case TRACE_IVAR: /* it is a variable */
1363 if (index->neg < 0) { /* if it's a negated var, return */
1370 varRef = index->var;
1373 if (c_var_modified[varRef]) { /* volatile var */
1375 lv = c_loopvars; /* get reference to loop variable */
1377 while ((lv != NULL) && (lv->value != varRef))
1380 printf("C_ERROR: debugging error 0x02\n");
1382 /* show_varinfo(lv); */
1384 /* check existing static bounds and add new contraints on variable */
1385 /* to possibly remove bound checks */
1387 /* the var is never decremented, so we add a static test againt */
1389 if (varChanges->lower_bound > varChanges->upper_bound)
1390 add_new_constraint(TEST_ZERO, arrayRef, varRef, index->constant);
1392 add_new_constraint(TEST_ZERO, arrayRef, varRef, varChanges->lower_bound+index->constant);
1395 else if ((lv->dynamic_l_v) && (!special)) {
1396 /* the variable is decremented, but it is checked against a */
1397 /* bound in the loop condition */
1398 if (varChanges->lower_bound <= varChanges->upper_bound) {
1399 add_new_constraint(TEST_RS_ZERO, arrayRef, varRef, varChanges->lower_bound+index->constant+lv->dynamic_l);
1405 /* the var is never incremented, so we add a static test againt */
1407 if (varChanges->lower_bound > varChanges->upper_bound)
1408 add_new_constraint(TEST_ALENGTH, arrayRef, varRef, index->constant);
1410 add_new_constraint(TEST_ALENGTH, arrayRef, varRef, varChanges->upper_bound+index->constant);
1413 else if ((lv->dynamic_u_v) && (!special)) {
1414 /* the variable is decremented, but it is checked against a */
1415 /* bound in the loop condition */
1416 if (varChanges->lower_bound <= varChanges->upper_bound) {
1417 add_new_constraint(TEST_RS_ALENGTH, arrayRef, varRef, varChanges->upper_bound+index->constant+lv->dynamic_u);
1422 else { /* the var is never modified at all */
1423 add_new_constraint(TEST_UNMOD_ZERO, arrayRef, index->var, index->constant);
1424 add_new_constraint(TEST_UNMOD_ALENGTH, arrayRef, index->var, index->constant);
1428 /* if the addition of new variable tests made guarantees possible, */
1429 /* return the best possible optimization */
1430 if ((high > 0) && (low > 0)) {
1431 /* printf("fully optimzed\n"); */
1437 else if (high > 0) {
1438 /* printf("upper optimzed\n"); */
1445 /* printf("lower optimzed\n"); */
1452 /* printf("not optimzed\n"); */
1460 case TRACE_ICONST: /* if it is a constant, optimization is easy */
1461 if (index->constant < 0) {
1465 return OPT_NONE; /* negative index -> bad */
1468 add_new_constraint(TEST_CONST_ALENGTH, arrayRef, 0, index->constant);
1472 return OPT_FULL; /* else just test constant against array length */
1476 case TRACE_ALENGTH: /* else, no optimizations possible */
1485 /* keep compiler happy */
1491 /* copy a stack and return the start pointer of the newly created one
1493 stackptr copy_stack_from(stackptr source) {
1494 stackptr current, top;
1499 /* copy first element */
1500 current = DMNEW(stackelement, 1);
1501 current->type = source->type;
1502 current->flags = source->flags;
1503 current->varkind = source->varkind;
1504 current->varnum = source->varnum;
1505 current->regoff = source->regoff;
1509 /* if there exist more, then copy the rest */
1510 while (source->prev != NULL) {
1511 source = source->prev;
1512 current->prev = DMNEW(stackelement, 1);
1513 current->type = source->type;
1514 current->flags = source->flags;
1515 current->varkind = source->varkind;
1516 current->varnum = source->varnum;
1517 current->regoff = source->regoff;
1518 current = current->prev;
1521 current->prev = NULL;
1526 /* The following defines are used in the procedure void create_static_checks(...)
1527 They add a new instruction with its corresponding stack manipulation and
1528 are used to build the new loop header of an optimized loop, where we have
1529 to check certain variables and constants against values to guarantee that
1530 index values in array accesses remain with array bounds.
1532 inst: pointer to the new instruction
1533 tos: stackpointer before this operation is executed
1534 newstack: temporary stackptr
1535 stackdepth: counts the current stackdepth
1536 original start: blockpointer to the head of the new, optimized loop
1539 /* Load a local integer variable v */
1540 #define LOAD_VAR(v) { \
1541 inst->opc = ICMD_ILOAD; \
1543 newstack = DMNEW(stackelement, 1); \
1544 inst->dst = newstack; \
1545 newstack->prev = tos; \
1546 newstack->type = TYPE_INT; \
1547 newstack->flags = 0; \
1548 newstack->varkind = LOCALVAR; \
1549 newstack->varnum = v; \
1555 /* Load a constant with value c */
1556 #define LOAD_CONST(c) { \
1557 inst->opc = ICMD_ICONST; \
1559 inst->val.i = (c); \
1560 newstack = DMNEW(stackelement, 1); \
1561 newstack->prev = tos; \
1562 newstack->type = TYPE_INT; \
1563 newstack->flags = 0; \
1564 newstack->varkind = UNDEFVAR; \
1565 newstack->varnum = stackdepth; \
1572 /* Load a local reference (adress) variable a */
1573 #define LOAD_ADDR(a) { \
1574 inst->opc = ICMD_ALOAD; \
1576 newstack = DMNEW(stackelement, 1); \
1577 newstack->prev = tos; \
1578 newstack->type = TYPE_ADR; \
1579 newstack->flags = 0; \
1580 newstack->varkind = LOCALVAR; \
1581 newstack->varnum = a; \
1588 /* Insert a compare greater-or-equal and jump to the unoptimized loop, if the */
1589 /* comparison is true */
1590 #define GOTO_NOOPT_IF_GE { \
1591 inst->opc = ICMD_IF_ICMPGE; \
1592 inst->target = original_start->copied_to; \
1593 if (tos->varkind == UNDEFVAR) \
1594 tos->varkind = TEMPVAR; \
1596 if (tos->varkind == UNDEFVAR) \
1597 tos->varkind = TEMPVAR; \
1604 /* Insert a compare greater than and jump to the unoptimized loop, if the */
1605 /* comparison is true */
1606 #define GOTO_NOOPT_IF_GT { \
1607 inst->opc = ICMD_IF_ICMPGT; \
1608 inst->target = original_start->copied_to; \
1609 if (tos->varkind == UNDEFVAR) \
1610 tos->varkind = TEMPVAR; \
1612 if (tos->varkind == UNDEFVAR) \
1613 tos->varkind = TEMPVAR; \
1621 /* Insert a compare less-than and jump to the unoptimized loop, if the */
1622 /* comparison is true */
1623 #define GOTO_NOOPT_IF_LT { \
1624 inst->opc = ICMD_IF_ICMPLT; \
1625 inst->target = original_start->copied_to; \
1626 if(tos->varkind == UNDEFVAR) \
1627 tos->varkind = TEMPVAR; \
1629 if(tos->varkind == UNDEFVAR) \
1630 tos->varkind = TEMPVAR; \
1637 /* Insert a compare if-not-null and jump to the unoptimized loop, if the */
1638 /* comparison is true */
1639 #define GOTO_NOOPT_IF_NULL { \
1640 inst->opc = ICMD_IFNULL; \
1641 inst->target = original_start->copied_to; \
1642 if(tos->varkind == UNDEFVAR) \
1643 tos->varkind = TEMPVAR; \
1650 /* Insert an add instruction, that adds two integer values on top of the stack */
1653 inst->opc = ICMD_IADD; \
1654 if(tos->varkind == UNDEFVAR) \
1655 tos->varkind = TEMPVAR; \
1657 if(tos->varkind == UNDEFVAR) \
1658 tos->varkind = TEMPVAR; \
1660 newstack = DMNEW(stackelement, 1); \
1661 newstack->prev = tos; \
1662 newstack->type = TYPE_INT; \
1663 newstack->flags = 0; \
1664 newstack->varkind = UNDEFVAR; \
1665 newstack->varnum = stackdepth; \
1672 /* Insert instructions to load the arraylength of an array with reference a */
1673 /* fisrt, the reference must be loaded, then a null-pointer check is inserted */
1674 /* if not already done earlier. Finally an arraylength instruction is added */
1675 #define LOAD_ARRAYLENGTH(a) { \
1676 if (c_null_check[a]) { \
1678 GOTO_NOOPT_IF_NULL; \
1679 c_null_check[a] = 0; \
1682 inst->opc = ICMD_ARRAYLENGTH; \
1683 if(tos->varkind == UNDEFVAR) \
1684 tos->varkind = TEMPVAR; \
1686 newstack = DMNEW(stackelement, 1); \
1687 newstack->prev = tos; \
1688 newstack->type = TYPE_INT; \
1689 newstack->flags = 0; \
1690 newstack->varkind = UNDEFVAR; \
1691 newstack->varnum = stackdepth; \
1698 /* Inserts the instructions to load the value of the right side of comparison */
1699 /* Depending of the type of the right side, the apropriate instructions are */
1701 #define LOAD_RIGHT_SIDE { \
1702 switch (c_rightside->type) { \
1703 case TRACE_ICONST: \
1704 LOAD_CONST(c_rightside->constant); \
1707 LOAD_VAR(c_rightside->var); \
1708 LOAD_CONST(c_rightside->constant); \
1711 case TRACE_ALENGTH: \
1712 LOAD_ARRAYLENGTH(c_rightside->var); \
1715 panic("C_ERROR: illegal trace on rightside of loop-header"); \
1719 /* Patch jumps in original loop and in copied loop, add gotos in copied loop.
1720 All jumps in the original loop to the loop head have to be redirected to
1721 the newly inserted one. For the copied loop, it is necessay to redirect all
1722 jumps inside that loop to the copied nodes. lc points to the current loop,
1723 loop_head is a pointer to the newly inserted head and original start was
1724 the old head and is now the head of the optimized variant of the loop.
1726 void patch_jumps(basicblock *original_start, basicblock *loop_head, struct LoopContainer *lc)
1728 /* step through all nodes of a loop */
1729 struct LoopElement *le;
1731 instruction *inst, *temp_instr;
1735 while (le != NULL) {
1737 /* do nothing for new loop head */
1738 if (le->block == loop_head) {
1743 /* for original version */
1745 inst = bptr->iinstr;
1746 for (i = 0; i < bptr->icount; ++i, ++inst) {
1747 switch (inst->opc) {
1749 case ICMD_IF_ICMPEQ:
1750 case ICMD_IF_ICMPLT:
1751 case ICMD_IF_ICMPLE:
1752 case ICMD_IF_ICMPNE:
1753 case ICMD_IF_ICMPGT:
1754 case ICMD_IF_ICMPGE:
1756 case ICMD_IF_LCMPEQ:
1757 case ICMD_IF_LCMPLT:
1758 case ICMD_IF_LCMPLE:
1759 case ICMD_IF_LCMPNE:
1760 case ICMD_IF_LCMPGT:
1761 case ICMD_IF_LCMPGE:
1763 case ICMD_IF_ACMPEQ:
1764 case ICMD_IF_ACMPNE:
1783 case ICMD_IFNONNULL:
1785 /* jump to newly inserted loopheader has to be redirected */
1786 if (((basicblock *) inst->target) == loop_head)
1787 inst->target = (void *) original_start;
1790 case ICMD_TABLESWITCH:
1795 tptr = (void **) inst->target;
1797 s4ptr = inst->val.a;
1798 l = s4ptr[1]; /* low */
1799 i = s4ptr[2]; /* high */
1803 /* jump to newly inserted loopheader has to be redirected */
1804 for (tptr = inst->target; i >= 0; --i, ++tptr) {
1805 if (((basicblock *) *tptr) == loop_head)
1806 tptr[0] = (void *) original_start;
1811 case ICMD_LOOKUPSWITCH:
1816 tptr = (void **) inst->target;
1818 s4ptr = inst->val.a;
1819 l = s4ptr[0]; /* default */
1820 i = s4ptr[1]; /* count */
1822 /* jump to newly inserted loopheader has to be redirected */
1823 for (tptr = inst->target; i >= 0; --i, ++tptr) {
1824 if (((basicblock *) *tptr) == loop_head)
1825 tptr[0] = (void *) original_start;
1832 /* if node is part of loop and has fall through to original start, that */
1833 /* must be redirected. Unfortunately the instructions have to be copied */
1835 if (bptr->next == loop_head) {
1836 temp_instr = DMNEW(instruction, bptr->icount + 1);
1837 memcpy(temp_instr, bptr->iinstr, sizeof(instruction)*bptr->icount);
1838 bptr->iinstr = temp_instr;
1840 bptr->iinstr[bptr->icount].opc = ICMD_GOTO;
1841 bptr->iinstr[bptr->icount].target = original_start;
1842 bptr->iinstr[bptr->icount].dst = NULL;
1846 /* for copied version - which gets the unoptimized variant */
1847 bptr = le->block->copied_to;
1848 inst = bptr->iinstr;
1849 for (i = 0; i < bptr->icount; ++i, ++inst) {
1851 switch (inst->opc) {
1853 case ICMD_IASTORE: /* array store */
1861 case ICMD_IALOAD: /* array load */
1870 /* undo previous optimizations in new loop */
1874 case ICMD_IF_ICMPEQ:
1875 case ICMD_IF_ICMPLT:
1876 case ICMD_IF_ICMPLE:
1877 case ICMD_IF_ICMPNE:
1878 case ICMD_IF_ICMPGT:
1879 case ICMD_IF_ICMPGE:
1881 case ICMD_IF_LCMPEQ:
1882 case ICMD_IF_LCMPLT:
1883 case ICMD_IF_LCMPLE:
1884 case ICMD_IF_LCMPNE:
1885 case ICMD_IF_LCMPGT:
1886 case ICMD_IF_LCMPGE:
1888 case ICMD_IF_ACMPEQ:
1889 case ICMD_IF_ACMPNE:
1908 case ICMD_IFNONNULL:
1910 /* jump to newly inserted loopheader has to be redirected */
1911 if (((basicblock *) inst->target) == loop_head)
1912 inst->target = (void *) original_start->copied_to;
1913 /* jump to loop internal nodes has to be redirected */
1914 else if (((basicblock *) inst->target)->lflags & LOOP_PART)
1915 inst->target = (void *) ((basicblock *) inst->target)->copied_to;
1918 case ICMD_TABLESWITCH:
1922 void **copy_ptr, *base_ptr;
1925 tptr = (void **) inst->target;
1927 s4ptr = inst->val.a;
1928 l = s4ptr[1]; /* low */
1929 i = s4ptr[2]; /* high */
1933 copy_ptr = (void**) DMNEW(void*, i+1);
1934 base_ptr = (void*) copy_ptr;
1936 /* Targets for switch instructions are stored in an extra */
1937 /* that must be copied for new inserted loop. */
1939 for (tptr = inst->target; i >= 0; --i, ++tptr, ++copy_ptr) {
1940 /* jump to newly inserted loopheader must be redirected */
1941 if (((basicblock *) *tptr) == loop_head)
1942 copy_ptr[0] = (void *) original_start->copied_to;
1943 /* jump to loop internal nodes has to be redirected */
1944 else if (((basicblock *) *tptr)->lflags & LOOP_PART)
1945 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
1947 copy_ptr[0] = tptr[0];
1950 inst->target = base_ptr;
1954 case ICMD_LOOKUPSWITCH:
1958 void **copy_ptr, **base_ptr;
1961 tptr = (void **) inst->target;
1963 s4ptr = inst->val.a;
1964 l = s4ptr[0]; /* default */
1965 i = s4ptr[1]; /* count */
1967 copy_ptr = (void**) DMNEW(void*, i+1);
1968 base_ptr = (void*) copy_ptr;
1970 /* Targets for switch instructions are stored in an extra */
1971 /* that must be copied for new inserted loop. */
1973 for (tptr = inst->target; i >= 0; --i, ++tptr, ++copy_ptr) {
1974 /* jump to newly inserted loopheader must be redirected */
1975 if (((basicblock *) *tptr) == loop_head)
1976 copy_ptr[0] = (void *) original_start->copied_to;
1977 /* jump to loop internal nodes has to be redirected */
1978 else if (((basicblock *) *tptr)->lflags & LOOP_PART)
1979 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
1981 copy_ptr[0] = tptr[0];
1984 inst->target = base_ptr;
1991 /* if fall through exits loop, goto is needed */
1992 if (!(le->block->next->lflags & LOOP_PART)) {
1993 bptr->iinstr[bptr->icount].opc = ICMD_GOTO;
1994 bptr->iinstr[bptr->icount].dst = NULL;
1995 bptr->iinstr[bptr->icount].target = le->block->next;
2003 /* Add the new header node of a loop that has been duplicated to all parent
2004 loops in nesting hierarchie.
2006 void header_into_parent_loops(struct LoopContainer *lc, basicblock *to_insert, basicblock *replace, basicblock *after)
2008 /* we have to insert the node to_insert before the node after and replace */
2009 /* the pointer of to_insert by the node replace */
2011 struct LoopElement *le, *t;
2013 /* if the top of the tree is reached, then return */
2014 if ((lc == NULL) || (lc == root))
2017 /* create new node, that should be inserted */
2018 t = DMNEW(struct LoopElement, 1);
2019 t->block = to_insert;
2022 /* first, find the node, that has to be replaced (= "to_insert") and */
2023 /* replace it by the node "replace" */
2025 while (le->block != to_insert)
2027 le->block = replace;
2030 if (after == to_insert)
2033 /* now find the node after and insert the newly create node before "after" */
2035 if (le->block == after) {
2036 t->next = lc->nodes;
2040 while (le->next->block != after)
2047 /* go up one hierarchie level */
2048 header_into_parent_loops(lc->parent, to_insert, replace, after);
2051 /* Add a new node (not header) of a duplicated loop to all parent loops in
2054 void node_into_parent_loops(struct LoopContainer *lc, basicblock *to_insert)
2056 struct LoopElement *le, *t;
2058 /* if the top of the tree is reached, then return */
2059 if ((lc == NULL) || (lc == root))
2062 /* create new node, that should be inserted */
2063 t = DMNEW(struct LoopElement, 1);
2064 t->block = to_insert;
2069 /* append new node to node list of loop */
2070 while (le->next != NULL)
2076 /* go up one hierarchie level */
2077 node_into_parent_loops(NULL, to_insert);
2081 /* void patch_handler(...) is very similar to parts of the function patch_jumps.
2082 Its task is to redirect all jumps from the original head to the new head and
2083 to redirect internal jumps inside the exception handler to the newly
2084 created (copied) nodes.
2086 void patch_handler(struct LoopContainer *lc, basicblock *bptr, basicblock *original_head, basicblock *new_head)
2091 /* If node is not part of exception handler or has been visited, exit */
2092 if (!(bptr->lflags & HANDLER_PART) || (bptr->lflags & HANDLER_VISITED))
2095 /* mark block as visited */
2096 bptr->lflags |= HANDLER_VISITED;
2098 /* for all instructions in the copied block, do */
2099 for (i = 0, ip = bptr->copied_to->iinstr; i < bptr->copied_to->icount; ++i, ++ip) {
2110 case ICMD_IF_ICMPEQ:
2111 case ICMD_IF_ICMPLT:
2112 case ICMD_IF_ICMPLE:
2113 case ICMD_IF_ICMPNE:
2114 case ICMD_IF_ICMPGT:
2115 case ICMD_IF_ICMPGE:
2117 case ICMD_IF_LCMPEQ:
2118 case ICMD_IF_LCMPLT:
2119 case ICMD_IF_LCMPLE:
2120 case ICMD_IF_LCMPNE:
2121 case ICMD_IF_LCMPGT:
2122 case ICMD_IF_LCMPGE:
2124 case ICMD_IF_ACMPEQ:
2125 case ICMD_IF_ACMPNE:
2143 case ICMD_IFNONNULL:
2145 patch_handler(lc, bptr->next, original_head, new_head);
2151 patch_handler(lc, ip->target, original_head, new_head);
2153 /* jumps to old header have to be redirected */
2154 if (((basicblock *) ip->target) == original_head)
2155 ip->target = (void *) new_head->copied_to;
2156 /* jumps to handler internal nodes have to be redirected */
2157 else if (((basicblock *) ip->target)->lflags & HANDLER_PART)
2158 ip->target = (void *) ((basicblock *) ip->target)->copied_to;
2159 /* jumps to loop internal nodes have to be redirected */
2160 else if (((basicblock *) ip->target)->lflags & LOOP_PART)
2161 ip->target = (void *) ((basicblock *) ip->target)->copied_to;
2166 case ICMD_TABLESWITCH:
2170 void **copy_ptr, **base_ptr;
2172 tptr = (void **) ip->target;
2174 l = s4ptr[1]; /* low */
2175 i = s4ptr[2]; /* high */
2178 copy_ptr = (void**) DMNEW(void*, i+1);
2179 base_ptr = (void*) copy_ptr;
2181 for (tptr = ip->target; i >= 0; --i, ++tptr, ++copy_ptr) {
2182 patch_handler(lc, ((basicblock *) *tptr), original_head, new_head);
2183 /* jumps to old header have to be redirected */
2184 if (((basicblock *) *tptr) == original_head)
2185 copy_ptr[0] = (void *) new_head->copied_to;
2186 /* jumps to handler internal nodes have to be redirected */
2187 else if (((basicblock *) *tptr)->lflags & HANDLER_PART)
2188 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2189 /* jumps to loop internal nodes have to be redirected */
2190 else if (((basicblock *) ip->target)->lflags & LOOP_PART)
2191 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2193 copy_ptr[0] = tptr[0];
2196 ip->target = base_ptr;
2200 case ICMD_LOOKUPSWITCH:
2205 void **copy_ptr, **base_ptr;
2207 tptr = (void **) ip->target;
2209 l = s4ptr[0]; /* default */
2210 i = s4ptr[1]; /* count */
2212 copy_ptr = (void**) DMNEW(void*, i+1);
2213 base_ptr = (void*) copy_ptr;
2215 for (tptr = ip->target; i >= 0; --i, ++tptr, ++copy_ptr) {
2217 patch_handler(lc, ((basicblock *) *tptr), original_head, new_head);
2218 /* jumps to old header have to be redirected */
2219 if (((basicblock *) *tptr) == original_head)
2220 copy_ptr[0] = (void *) new_head->copied_to;
2221 /* jumps to handler internal nodes have to be redirected */
2222 else if (((basicblock *) *tptr)->lflags & HANDLER_PART)
2223 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2224 /* jumps to loop internal nodes have to be redirected */
2225 else if (((basicblock *) ip->target)->lflags & LOOP_PART)
2226 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2228 copy_ptr[0] = tptr[0];
2231 ip->target = base_ptr;
2239 /* if fall through exits loop, goto is needed */
2240 if (!(bptr->next->lflags & HANDLER_PART)) {
2241 bptr->copied_to->iinstr[bptr->copied_to->icount].opc = ICMD_GOTO;
2242 bptr->copied_to->iinstr[bptr->copied_to->icount].dst = NULL;
2243 bptr->copied_to->iinstr[bptr->copied_to->icount].target = bptr->next;
2244 bptr->copied_to->icount++;
2249 /* This function copys the exception handler and redirects all jumps from the
2250 original head to the new head in the original exception handler. All
2251 redirection in the copied exception handler is done in patch_handler(...).
2253 void copy_handler(struct LoopContainer *lc, basicblock *bptr, basicblock *original_head, basicblock *new_head)
2258 int high, low, count;
2259 struct LoopElement *le;
2262 /* If this node has already been copied, return */
2263 if (bptr->lflags & HANDLER_PART)
2266 /* The exception handler exists, when control flow enters loop again */
2268 if (bptr->lflags & LOOP_PART)
2270 for (le = lc->nodes; le != NULL; le = le->next) {
2271 if (le->block == bptr) {
2272 printf("C_PANIC: should not happen\n");
2277 /* mark block as part of handler */
2278 bptr->lflags |= HANDLER_PART;
2281 new = DMNEW(basicblock, 1);
2282 memcpy(new, bptr, sizeof(basicblock));
2283 new->debug_nr = c_debug_nr++;
2285 c_last_block_copied = new;
2287 /* copy instructions and allow one more slot for possible GOTO */
2288 new->iinstr = DMNEW(instruction, bptr->icount + 1);
2289 memcpy(new->iinstr, bptr->iinstr, bptr->icount*sizeof(instruction));
2291 /* update original block */
2292 bptr->copied_to = new;
2294 /* append block to global list of basic blocks */
2295 last_block->next = new;
2300 /* find next block to copy, depending on last instruction of BB */
2301 if (bptr->icount == 0) {
2302 copy_handler(lc, bptr->next, original_head, new_head);
2306 ip = bptr->iinstr + (bptr->icount - 1);
2325 case ICMD_IF_LCMPEQ:
2326 case ICMD_IF_LCMPLT:
2327 case ICMD_IF_LCMPLE:
2328 case ICMD_IF_LCMPNE:
2329 case ICMD_IF_LCMPGT:
2330 case ICMD_IF_LCMPGE:
2340 case ICMD_IFNONNULL:
2342 case ICMD_IF_ICMPEQ:
2343 case ICMD_IF_ICMPNE:
2344 case ICMD_IF_ICMPLT:
2345 case ICMD_IF_ICMPGE:
2346 case ICMD_IF_ICMPGT:
2347 case ICMD_IF_ICMPLE:
2348 case ICMD_IF_ACMPEQ:
2349 case ICMD_IF_ACMPNE:
2350 copy_handler(lc, bptr->next, original_head, new_head);
2355 /* redirect jump from original_head to new_head */
2356 if ((basicblock *) ip->target == original_head)
2357 ip->target = (void *) new_head;
2359 copy_handler(lc, (basicblock *) (ip->target), original_head, new_head);
2363 case ICMD_TABLESWITCH:
2365 tptr = (void **) ip->target;
2367 /* default branch */
2368 if (((basicblock *) *tptr) == original_head)
2369 tptr[0] = (void *) new_head;
2371 copy_handler(lc, (basicblock *) *tptr, original_head, new_head);
2378 count = (high-low+1);
2380 while (--count >= 0) {
2382 /* redirect jump from original_head to new_head */
2383 if (((basicblock *) *tptr) == original_head)
2384 tptr[0] = (void *) new_head;
2385 copy_handler(lc, (basicblock *) *tptr, original_head, new_head);
2389 case ICMD_LOOKUPSWITCH:
2391 tptr = (void **) ip->target;
2393 /* default branch */
2394 if (((basicblock *) *tptr) == original_head)
2395 tptr[0] = (void *) new_head;
2397 copy_handler(lc, (basicblock *) *tptr, original_head, new_head);
2402 while (--count >= 0) {
2404 /* redirect jump from original_head to new_head */
2405 if (((basicblock *) *tptr) == original_head)
2406 tptr[0] = (void *) new_head;
2407 copy_handler(lc, (basicblock *) *tptr, original_head, new_head);
2412 c_last_target = bptr;
2413 copy_handler(lc, (basicblock *) (ip->target), original_head, new_head);
2417 copy_handler(lc, c_last_target->next, original_head, new_head);
2421 copy_handler(lc, bptr->next, original_head, new_head);
2428 /* If a loop is duplicated, all exceptions, that are contained in this loops' body
2429 have to be duplicated as well. The following function together with the
2430 two helper functions copy_handler and patch_handler perform this task.
2432 void update_internal_exceptions(struct LoopContainer *lc, basicblock *original_head, basicblock *new_head)
2435 struct LoopContainer *l;
2437 /* Bottom of tree reached -> return */
2441 /* Call update_internal for all nested (=child) loops */
2444 update_internal_exceptions(l, original_head, new_head);
2448 /* For all exceptions of this loop, do */
2449 ex = lc->exceptions;
2450 while (ex != NULL) {
2452 /* Copy the exception and patch the jumps */
2453 copy_handler(lc, ex->handler, original_head, new_head);
2454 patch_handler(lc, ex->handler, original_head, new_head);
2456 /* Insert a new exception into the global exception table */
2457 new = DMNEW(xtable, 1);
2458 memcpy(new, ex, sizeof(xtable));
2460 /* Increase number of exceptions */
2461 ++exceptiontablelength;
2466 /* Set new start and end point of this exception */
2467 new->start = ex->start->copied_to;
2468 new->end = ex->end->copied_to;
2470 /* Set handler pointer to copied exception handler */
2471 new->handler = ex->handler->copied_to;
2478 /* If a loop is duplicated, all exceptions that contain this loop have to be
2479 extended to the copied nodes as well. The following function checks for
2480 all exceptions of all parent loops, whether they contain the loop pointed to
2481 by lc. If so, the exceptions are extended to contain all newly created nodes.
2483 void update_external_exceptions(struct LoopContainer *lc, int loop_head)
2487 /* Top of tree reached -> return */
2491 ex = lc->exceptions;
2493 /* For all exceptions of this loop do */
2494 while (ex != NULL) {
2496 /* It is possible that the loop contains exceptions that do not protect */
2497 /* the loop just duplicated. It must be checked, if this is the case */
2498 if ((loop_head >= block_index[ex->startpc]) && (loop_head < block_index[ex->endpc])) {
2500 /* loop is really inside exception, so create new exception entry */
2501 /* in global exception list */
2502 new = DMNEW(xtable, 1);
2503 memcpy(new, ex, sizeof(xtable));
2506 /* Increase number of exceptions */
2507 ++exceptiontablelength;
2512 /* Set new start and end point of this exception */
2513 new->start = c_first_block_copied;
2514 new->end = c_last_block_copied;
2518 /* exception does not contain the duplicated loop -> do nothing */
2523 /* Call update_external for parent node */
2524 update_external_exceptions(lc->parent, loop_head);
2529 /* This function is needed to insert the static checks, stored in c_constraints
2530 into the intermediate code.
2532 void create_static_checks(struct LoopContainer *lc)
2534 int i, stackdepth, cnt;
2535 struct Constraint *tc1;
2536 struct LoopElement *le;
2538 /* loop_head points to the newly inserted loop_head, original_start to */
2539 /* the old loop header */
2540 basicblock *bptr, *loop_head, *original_start, *temp;
2541 instruction *inst, *tiptr;
2543 /* tos and newstack are needed by the macros, that insert instructions into */
2544 /* the new loop head */
2545 stackptr newstack, tos;
2549 /* show_loop_statistics(); */
2552 loop_head = &block[c_current_head];
2553 c_first_block_copied = c_last_block_copied = NULL;
2555 /* the loop nodes are copied */
2559 bptr = DMNEW(basicblock, 1);
2560 memcpy(bptr, le->block, sizeof(basicblock));
2561 bptr->debug_nr = c_debug_nr++;
2563 /* determine beginning of copied loop to extend exception handler, that */
2564 /* protect this loop */
2565 if (c_first_block_copied == NULL)
2566 c_first_block_copied = bptr;
2568 /* copy instructions and add one more slot for possible GOTO */
2569 bptr->iinstr = DMNEW(instruction, bptr->icount + 1);
2571 memcpy(bptr->iinstr, le->block->iinstr, (bptr->icount+1)*sizeof(instruction));
2573 le->block->copied_to = bptr;
2575 /* add block to global list of BBs */
2576 last_block->next = bptr;
2580 node_into_parent_loops(lc->parent, bptr);
2584 c_last_block_copied = bptr;
2586 /* create an additional basicblock for dynamic checks */
2587 original_start = bptr = DMNEW(basicblock, 1);
2589 /* copy current loop header to new basic block */
2590 memcpy(bptr, loop_head, sizeof(basicblock));
2591 bptr->debug_nr = c_debug_nr++;
2593 /* insert the new basic block and move header before first loop node */
2597 /* if header is first node of loop, insert original header after it */
2598 if (temp == loop_head)
2599 loop_head->next = bptr;
2601 /* else, we have to find the predecessor of loop header */
2602 while (temp->next != loop_head)
2605 /* insert original header after newly created block */
2608 /* if predecessor is not loop part, insert a goto */
2609 if (!(temp->lflags & LOOP_PART)) {
2611 /* copy instructions and add an additional slot */
2612 tiptr = DMNEW(instruction, temp->icount + 1);
2613 memcpy(tiptr, temp->iinstr, sizeof(instruction)*temp->icount);
2615 temp->iinstr = tiptr;
2616 tiptr = temp->iinstr + temp->icount;
2618 /* add goto to loop header. If node is part of exception handler */
2619 /* jmp is automagically redirected during patch_handler and works */
2621 tiptr->opc = ICMD_GOTO;
2623 tiptr->target = (void*) loop_head;
2630 /* if first loop block is first BB of global list, insert loop_head at */
2631 /* beginning of global BB list */
2632 if (temp == le->block) {
2633 if (c_newstart == NULL) {
2634 c_needs_redirection = true;
2635 c_newstart = loop_head;
2636 loop_head->next = block;
2639 loop_head->next = c_newstart;
2640 c_newstart = loop_head;
2645 while (temp->next != le->block)
2648 loop_head->next = temp->next;
2649 temp->next = loop_head;
2651 /* to be on the safe side insert a jump from the previous instr */
2652 /* over thr new inserted node */
2654 /* special case - jump from node to loop_head: then remove */
2655 /* goto / happens rather often due to loop layout */
2656 tiptr = temp->iinstr + (temp->icount-1);
2658 if ((tiptr->opc == ICMD_GOTO) && (tiptr->target == loop_head)) {
2659 tiptr->opc = ICMD_NOP;
2664 tiptr = DMNEW(instruction, temp->icount + 1);
2665 memcpy(tiptr, temp->iinstr, sizeof(instruction)*temp->icount);
2667 temp->iinstr = tiptr;
2668 tiptr = temp->iinstr + temp->icount;
2670 tiptr->opc = ICMD_GOTO;
2672 tiptr->target = (void*) loop_head->next;
2679 /* adjust exceptions */
2681 while (ex != NULL) {
2683 /* if an exception covers whole loop and starts at first loop node, it */
2684 /* has to be extended to cover the new first node as well */
2685 if (ex->start == le->block) {
2687 if ((lc->loop_head >= block_index[ex->startpc]) && (lc->loop_head < block_index[ex->endpc]))
2688 ex->start = loop_head;
2691 /* an exception that ended at the old loop header now must contains the */
2692 /* new loop header as well */
2693 if (ex->end == loop_head)
2694 ex->end = original_start;
2700 /* insert new header node into nodelists of all enclosing loops */
2701 header_into_parent_loops(lc, loop_head, original_start, le->block);
2703 /* prepare instruction array to insert checks */
2704 inst = loop_head->iinstr = DMNEW(instruction, c_needed_instr + 2);
2705 loop_head->icount = c_needed_instr + 1;
2707 /* init instruction array */
2708 for (cnt=0; cnt<c_needed_instr + 1; ++cnt) {
2709 inst[0].opc = ICMD_NOP;
2713 loop_head->copied_to = NULL;
2716 loop_head->instack = copy_stack_from(bptr->instack);
2717 loop_head->outstack = copy_stack_from(bptr->instack);
2719 tos = loop_head->instack;
2720 stackdepth = loop_head->indepth;
2722 /* step through all inserted checks and create instructions for them */
2723 for (i=0; i<maxlocals+1; ++i)
2725 tc1 = c_constraints[i];
2731 /* check a variable against a constant */
2733 case TEST_UNMOD_ZERO:
2736 printf("insert ZERO-test\n");
2740 /* optimize if tc1->varRef >= tc1->constant */
2741 LOAD_VAR(tc1->varRef);
2742 LOAD_CONST(tc1->constant);
2746 /* check a variable against an array length */
2748 case TEST_UNMOD_ALENGTH:
2751 /* tc1->varRef + tc1->constant < lengthOf(tc1->arrayRef) */
2753 printf("insert ALENGTH-test\n");
2757 LOAD_VAR(tc1->varRef);
2758 LOAD_CONST(tc1->constant);
2760 LOAD_ARRAYLENGTH(tc1->arrayRef);
2764 /* test right side of comparison against constant */
2768 printf("insert RS-ZERO-test\n");
2772 /* optimize if right-side >= tc1->constant */
2774 LOAD_CONST(tc1->constant);
2778 /* test right side of comparison against array length */
2779 case TEST_RS_ALENGTH:
2782 printf("insert RS-ALENGTH-test\n");
2785 /* optimize if right-side < lengthOf(arrayRef) */
2787 LOAD_ARRAYLENGTH(tc1->arrayRef);
2791 /* test unmodified variable against arraylength */
2792 case TEST_CONST_ALENGTH:
2795 printf("insert CONST ALENGTH-test\n");
2799 /* optimize if tc1->constant < lengthOf(tc1->arrayRef) */
2800 LOAD_CONST(tc1->constant);
2801 LOAD_ARRAYLENGTH(tc1->arrayRef);
2808 c_constraints[i] = NULL;
2811 /* if all tests succeed, jump to optimized loop header */
2812 if (loop_head->next != original_start) {
2813 inst->opc = ICMD_GOTO;
2815 inst->target = original_start;
2818 /* redirect jumps from original loop head to newly inserted one */
2819 patch_jumps(original_start, loop_head, lc);
2821 /* if exceptions have to be correct due to loop duplication these two */
2822 /* functions perform this task. */
2823 update_internal_exceptions(lc, loop_head, original_start);
2824 update_external_exceptions(lc->parent, lc->loop_head);
2828 /* This function performs an update between two arrays of struct Changes (that
2829 reflect variable changes). The merge is performed unrstricted in the way, that
2830 all variable changes in c1 took place in a nested loop and therefore are
2831 considered to be without limit. Beside that, the merge is a simple union of the
2832 changes recorded in both arrays. A variable, which limits are undefinied, is
2833 represented by its lower bound being higher than the upper bound. The result
2834 of the union is stored in c1.
2836 struct Changes ** constraints_unrestricted_merge(struct Changes **c1, struct Changes **c2)
2840 if ((c1 == NULL) || (c2 == NULL))
2841 printf("C_ERROR: debugging error 0x03\n");
2844 for (i=0; i<maxlocals; ++i) {
2845 if (c1[i] == NULL) {
2846 if (c2[i] != NULL) { /* a change in c2 is updated in c1 */
2849 c1[i]->lower_bound = c1[i]->upper_bound+1;
2853 if (c1[i]->lower_bound > c1[i]->upper_bound)
2854 continue; /* variable's bounds already undefined */
2856 if (c2[i] == NULL) { /* variable changed in c1 -> now undef. */
2858 c1[i]->lower_bound = c1[i]->upper_bound+1;
2861 if ((c1[i]->lower_bound == c2[i]->lower_bound) &&
2862 (c1[i]->upper_bound == c2[i]->upper_bound))
2863 continue; /* variable's bounds remain the same */
2866 c1[i]->lower_bound = c1[i]->upper_bound+1;
2867 } /* variable changed in c1 -> now undef. */
2878 /* This function performs an update between two arrays of struct Changes (that
2879 reflect variable changes). The merge is a simple union of the bounds
2880 changes recorded in both arrays. A variable, which limits are undefinied, is
2881 represented by its lower bound being higher than the upper bound. The result
2882 of the union is stored in c1.
2884 struct Changes ** constraints_merge(struct Changes **c1, struct Changes **c2)
2888 if ((c1 == NULL) || (c2 == NULL))
2889 printf("C_ERROR: debugging error 0x04\n");
2893 for (i=0; i<maxlocals; ++i) {
2894 if (c1[i] == NULL) {
2895 if (c2[i] != NULL) { /* update changes in c2 in c1 */
2896 if ((c1[i] = (struct Changes *) malloc (sizeof(struct Changes))) == NULL)
2899 c1[i]->lower_bound = c2[i]->lower_bound;
2900 c1[i]->upper_bound = c2[i]->upper_bound;
2905 if (c2[i] != NULL) {
2907 if (c1[i]->lower_bound > c1[i]->upper_bound)
2908 continue; /* var in c1 is unrestricted */
2910 if (c1[i]->lower_bound > c2[i]->lower_bound) {
2911 c1[i]->lower_bound = c2[i]->lower_bound;
2912 changed = 1; /* write new lower bound */
2914 if (c1[i]->upper_bound < c2[i]->upper_bound) {
2915 c1[i]->upper_bound = c2[i]->upper_bound;
2916 changed = 1; /* write new higher bound */
2929 /* This function simply copies an array of changes
2931 struct Changes** constraints_clone(struct Changes **c)
2936 if ((t = (struct Changes **) malloc(maxlocals * sizeof(struct Changes *))) == NULL)
2939 for (i=0; i<maxlocals; ++i) { /* for all array elements (vars) do */
2943 if ((t[i] = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
2945 t[i]->lower_bound = c[i]->lower_bound;
2946 t[i]->upper_bound = c[i]->upper_bound;
2953 /* This function is used to reset the changes of a variable to the time, it was
2954 pushed onto the stack. If a variable has been modified between an instruction
2955 and a previous push onto the stack, its value in the changes array does not
2956 correctly reflect its bounds the time, it was pushed onto the stack. This
2957 function corrects the situation.
2959 struct Changes* backtrack_var(int node, int from, int to, int varRef, struct Changes *changes)
2961 struct Changes *tmp;
2966 if (changes == NULL) /* if there are no changes, immediately return */
2968 else { /* init a Changes structure with current values */
2969 if ((tmp = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
2972 tmp->upper_bound = changes->upper_bound;
2973 tmp->lower_bound = changes->lower_bound;
2976 if (tmp->upper_bound < tmp->lower_bound)
2977 return tmp; /* if it is unrestricted no backtracking can happen */
2980 ip = bp.iinstr + to;
2982 for (; from < to; --to, --ip) { /* scan instructions backwards */
2984 case ICMD_IINC: /* a var has been modified */
2985 if (varRef != ip->op1) /* not the one, we are interested in */
2987 tmp->upper_bound -= ip->val.i; /* take back modifications */
2988 tmp->lower_bound -= ip->val.i;
2991 case ICMD_ISTORE: /* a var has been modified */
2992 if (varRef != ip->op1) /* not the one, we are interested in */
2995 /* it is our variable, so trace its origin */
2996 t = tracing(&block[node],to, 0);
3000 if ((t->var = ip->op1) && (t->neg > 0)) {
3001 /* it was the same var -> take back modifications */
3002 tmp->upper_bound -= t->constant;
3003 tmp->lower_bound -= t->constant;
3006 tmp->lower_bound = tmp->upper_bound+1; /* unknown */
3009 /* cannot restore it -> invalidate t */
3014 tmp->lower_bound = tmp->upper_bound+1;
3024 /* This function performs the main task of bound check removal. It removes
3025 all bound-checks in node. change is a pointer to an array of struct Changes
3026 that reflect for all local variables, how their values have changed from
3027 the start of the loop. The special flag is needed to deal with the header
3030 void remove_boundchecks(int node, int from, struct Changes **change, int special)
3034 int i, count, ignore, degrade_checks, opt_level;
3035 struct depthElement *d;
3036 struct Changes **t1, **tmp, *t;
3037 struct Trace *t_array, *t_index;
3039 /* printf("remove_bc called: %d - %d - %d\n", node, from, special); */
3041 /* a flag, that is set, when previous optimzations have to be taken back */
3044 if (c_current_loop[node] > 0) { /* this node is part of the loop */
3045 if (c_current_loop[node] > 1) { /* it is not the header node */
3047 /* get variable changes, already recorded for this node */
3048 t1 = c_dTable[node]->changes;
3050 if (t1 != NULL) { /* it is not the first visit */
3051 if ((c_nestedLoops[node] != c_current_head) && (c_nestedLoops[node] == c_nestedLoops[from])) {
3052 /* we are looping in a nested loop, so made optimizations */
3053 /* need to be reconsidered */
3055 if (constraints_unrestricted_merge(t1, change) == NULL)
3056 return; /* no changes since previous visit */
3057 /* if there have been changes, they are updated by */
3058 /* constraints_unrestricted_merge in t1 */
3061 if (constraints_merge(t1, change) == NULL)
3062 return; /* no changes since previous visit */
3063 /* if there have been changes, they are updated by */
3064 /* constraints_merge in t1 */
3067 else { /* first visit */
3068 /* printf("first visit - constraints cloned\n"); */
3069 c_dTable[node]->changes = constraints_clone(change);
3072 /* tmp now holds a copy of the updated variable changes */
3073 tmp = constraints_clone(c_dTable[node]->changes);
3075 else if (special) { /* header and need special traetment */
3076 /* printf("special treatment called\n"); */
3077 /* tmp now holds a copy of the current new variable changes */
3078 tmp = constraints_clone(change);
3083 bp = block[node]; /* scan all instructions */
3088 for (i=0; i<count; ++i, ++ip) {
3090 case ICMD_IASTORE: /* found an array store */
3099 t_index = tracing(&bp, i-1, 1); /* get index */
3100 t_array = tracing(&bp, i-1, 2); /* get array refernce */
3104 case ICMD_IALOAD: /* found an array load */
3113 t_index = tracing(&bp, i-1, 0); /* get index */
3114 t_array = tracing(&bp, i-1, 1); /* get array refernce */
3118 /* printf("Array access with params:\n");
3120 show_trace(t_array);
3122 show_trace(t_index);
3126 if (ip->op1 == OPT_UNCHECKED) { /* found new access */
3127 c_stat_array_accesses++;
3133 /* can only optimize known arrays that do not change */
3134 if ((t_array->type != TRACE_AVAR) || (c_var_modified[t_array->var]))
3137 switch (t_index->type) { /* now we look at the index */
3138 case TRACE_ICONST: /* it is a constant value or an */
3139 case TRACE_ALENGTH: /* array length */
3141 switch (ip->op1) { /* take back old optimzation */
3158 if (degrade_checks) /* replace existing optimization */
3159 ip->op1 = insert_static(t_array->var, t_index, NULL, special);
3161 /* Check current optimization and try to improve it by */
3162 /* inserting new checks */
3165 ip->op1 = insert_static(t_array->var, t_index, NULL, special);
3168 ip->op1 = insert_static(t_array->var, t_index, NULL, special);
3171 opt_level = insert_static(t_array->var, t_index, NULL, special);
3172 if ((opt_level == OPT_FULL) || (opt_level == OPT_LOWER))
3176 opt_level = insert_static(t_array->var, t_index, NULL, special);
3177 if ((opt_level == OPT_FULL) || (opt_level == OPT_UPPER))
3189 case TRACE_IVAR: /* it's a variable */
3191 /* if the variable is changed between its usage as an index */
3192 /* of the array access and its push onto the stack, we have */
3193 /* to set the changes back to the time, it is pushed onto */
3194 /* the stack as an index variable. */
3195 t = backtrack_var(node, t_index->nr, i-1, t_index->var, tmp[t_index->var]);
3197 switch (ip->op1) { /* take back old optimzation */
3215 ip->op1 = insert_static(t_array->var, t_index, t, special);
3217 /* Check current optimization and try to improve it by */
3218 /* insert new check. t reflects var changes for index */
3221 ip->op1 = insert_static(t_array->var, t_index, t, special);
3224 ip->op1 = insert_static(t_array->var, t_index, t, special);
3227 opt_level = insert_static(t_array->var, t_index, t, special);
3228 if ((opt_level == OPT_FULL) || (opt_level == OPT_LOWER))
3232 opt_level = insert_static(t_array->var, t_index, t, special);
3233 if ((opt_level == OPT_FULL) || (opt_level == OPT_UPPER))
3251 case ICMD_ISTORE: /* an integer value is stored */
3252 t_index = tracing(&bp, i-1, 0); /* trace back its origin */
3254 /* the struct Changes for this variable needs to be updated */
3256 if (t == NULL) { /* if it's the first one, create new entry */
3257 if ((t = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
3259 t->upper_bound = t->lower_bound = 0;
3263 switch (t_index->type) { /* check origin of store */
3265 case TRACE_ICONST: /* constant -> set bounds to const value */
3266 t->upper_bound = t->lower_bound = t_index->constant;
3269 case TRACE_IVAR: /* if it's the same variable, update consts */
3270 if ((t_index->var = ip->op1) && (t_index->neg > 0)) {
3271 t->upper_bound += t_index->constant;
3272 t->lower_bound += t_index->constant;
3275 t->lower_bound = t->upper_bound+1;
3278 case TRACE_ALENGTH: /* else -> unknown */
3281 t->lower_bound = t->upper_bound+1;
3289 /* the struct Changes for this variable needs to be updated */
3290 if ((t = tmp[ip->op1]) == NULL) { /* first one -> create new */
3291 if ((t = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
3293 t->upper_bound = t->lower_bound = ip->val.i;
3296 else { /* update changes, made by iinc */
3297 t->upper_bound += ip->val.i;
3298 t->lower_bound += ip->val.i;
3304 if (!special) { /* we are not interested in only the header */
3306 while (d != NULL) { /* check all sucessors of current node */
3307 remove_boundchecks(d->value, node, tmp, special);
3314 /* This function calls the bound-check removal function for the header node
3315 with a special flag. It is important to notice, that no dynamic
3316 constraint hold in the header node (because the comparison is done at
3319 void remove_header_boundchecks(int node, struct Changes **changes)
3321 remove_boundchecks(node, -1, changes, BOUNDCHECK_SPECIAL);
3324 /* Marks all basicblocks that are part of the loop
3326 void mark_loop_nodes(struct LoopContainer *lc)
3328 struct LoopElement *le = lc->nodes;
3330 while (le != NULL) {
3331 le->block->lflags |= LOOP_PART;
3336 /* Clears mark for all basicblocks that are part of the loop
3338 void unmark_loop_nodes(struct LoopContainer *lc)
3340 struct LoopElement *le = lc->nodes;
3342 while (le != NULL) {
3343 le->block->lflags = 0;
3349 /* This function performs the analysis of code in detected loops and trys to
3350 identify array accesses suitable for optimization (bound check removal). The
3351 intermediate code is then modified to reflect these optimizations.
3353 void optimize_single_loop(struct LoopContainer *lc)
3355 struct LoopElement *le;
3356 struct depthElement *d;
3358 struct Changes **changes;
3360 if ((changes = (struct Changes **) malloc(maxlocals * sizeof(struct Changes *))) == NULL)
3363 head = c_current_head = lc->loop_head;
3364 c_needed_instr = c_rs_needed_instr = 0;
3366 /* init array for null ptr checks */
3367 for (i=0; i<maxlocals; ++i)
3368 c_null_check[i] = 0;
3371 /* don't optimize root node (it is the main procedure, not a loop) */
3375 /* setup variables with initial values */
3377 for (i=0; i < block_count; ++i) {
3379 c_current_loop[i] = -1;
3380 if ((d = c_dTable[i]) != NULL)
3384 for (i=0; i < maxlocals; ++i) {
3385 c_var_modified[i] = 0;
3386 if (changes[i] != NULL) {
3391 for (i=0; i < (maxlocals+1); ++i) {
3392 if (c_constraints[i] != NULL) {
3393 c_constraints[i] = NULL;
3398 while (le != NULL) {
3402 c_current_loop[node] = 1; /* the header node gets 1 */
3403 else if (c_nestedLoops[node] == head)
3404 c_current_loop[node] = 2; /* top level nodes get 2 */
3406 c_current_loop[node] = 3; /* nodes, part of nested loop get 3 */
3408 c_toVisit[node] = 1;
3412 /* After setup work has been performed, start to analyse */
3414 printf("****** Starting analysis (%d)******\n", head);
3418 if (analyze_for_array_access(head) > 0) {/* loop contains array access */
3423 printf("analyze for array access finished and found\n");
3426 while (lv != NULL) {
3428 printf("Var --> %d\n", lv->value);
3433 /* for performance reasons the list of all interesting loop vars is */
3434 /* scaned and for all modified vars a flag in c_var_modified is set */
3438 printf("global list scanned\n");
3442 /* if the loop header contains or-conditions or an index variable */
3443 /* is modified in the catch-block within the loop, a conservative */
3444 /* approach is taken and optimizations are cancelled */
3445 if (analyze_or_exceptions(head, lc) > 0) {
3448 printf("Analyzed for or/exception - no problems \n");
3452 init_constraints(head); /* analyze dynamic bounds in header */
3458 if (c_rightside == NULL)
3461 /* single pass bound check removal - for all successors, do */
3462 remove_header_boundchecks(head, changes);
3466 remove_boundchecks(d->value, -1, changes, BOUNDCHECK_REGULAR);
3471 printf("Array-bound checks finished\n");
3475 mark_loop_nodes(lc);
3478 printf("START: create static checks\n");
3482 create_static_checks(lc); /* create checks */
3485 printf("END: create static checks\n");
3488 unmark_loop_nodes(lc);
3492 printf("No array accesses found\n"); */
3495 c_stat_num_loops++; /* increase number of loops */
3497 c_stat_sum_accesses += c_stat_array_accesses;
3498 c_stat_sum_full += c_stat_full_opt;
3499 c_stat_sum_no += c_stat_no_opt;
3500 c_stat_sum_lower += c_stat_lower_opt;
3501 c_stat_sum_upper += c_stat_upper_opt;
3502 c_stat_sum_or += c_stat_or;
3503 c_stat_sum_exception += c_stat_exception;
3505 c_stat_array_accesses = 0;
3506 c_stat_full_opt = 0;
3508 c_stat_lower_opt = 0;
3509 c_stat_upper_opt = 0;
3510 c_stat_or = c_stat_exception = 0;
3515 /* This function preforms necessary setup work, before the recursive function
3516 optimize_single loop can be called.
3518 void optimize_loops()
3520 struct LoopContainer *lc = c_allLoops;
3522 /* first, merge loops with same header node - all loops with the same */
3523 /* header node are optimizied in one pass, because they all depend on the */
3524 /* same dynamic loop condition */
3527 printf("start analyze_double_headers\n");
3531 analyze_double_headers();
3533 /* create array with loop nesting levels - nested loops cause problems, */
3534 /* especially, when they modify index variables used in surrounding loops */
3535 /* store results in array c_nestedLoops and c_hierarchie */
3538 printf("double done\n");
3545 printf("analyze nested done\n");
3549 /* create array with entries for current loop */
3550 c_current_loop = DMNEW(int, block_count);
3551 c_toVisit = DMNEW(int, block_count);
3552 c_var_modified = DMNEW(int, maxlocals);
3553 c_null_check = DMNEW(int, maxlocals);
3555 if ((c_constraints = (struct Constraint **) malloc((maxlocals+1) * sizeof(struct Constraint *))) == NULL)
3559 c_stat_num_loops = 0; /* set statistic vars to zero */
3560 c_stat_array_accesses = c_stat_sum_accesses = 0;
3561 c_stat_full_opt = c_stat_sum_full = 0;
3562 c_stat_no_opt = c_stat_sum_no = 0;
3563 c_stat_lower_opt = c_stat_sum_lower = 0;
3564 c_stat_upper_opt = c_stat_sum_upper = 0;
3565 c_stat_or = c_stat_sum_or = 0;
3566 c_stat_exception = c_stat_sum_exception = 0;
3569 /* init vars needed by all loops */
3570 c_needs_redirection = false;
3572 c_old_xtablelength = exceptiontablelength;
3574 /* loops have been topologically sorted */
3576 while (lc != NULL) {
3577 optimize_single_loop(lc);
3580 printf(" *** Optimized loop *** \n");
3587 printf("---*** All loops finished ***---\n");
3591 /* if global BB list start is modified, set block to new start */
3592 if (c_needs_redirection == true)
3599 * These are local overrides for various environment variables in Emacs.
3600 * Please do not remove this and leave it at the end of the file, where
3601 * Emacs will automagically detect them.
3602 * ---------------------------------------------------------------------
3605 * indent-tabs-mode: t