1 /* analyze.c *******************************************************************
3 Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst
5 See file COPYRIGHT for information on usage and disclaimer of warranties.
7 Contains the functions which perform the bound check removals. With
8 the loops identified, these functions scan the code for array accesses
9 that take place in loops and try to guarantee that their bounds are
10 never violated. The function to call is optimize_loops().
12 Authors: Christopher Kruegel EMAIL: cacao@complang.tuwien.ac.at
14 Last Change: 1998/17/02
16 *******************************************************************************/
20 /* Test functions -> will be removed in final release
23 void show_trace(struct Trace *trace)
26 switch (trace->type) {
29 printf("\nNr.:\t%d", trace->var);
30 printf("\nValue:\t%d", trace->constant);
35 printf("\nNr.:\t%d", trace->var);
39 printf("array-length");
40 printf("\nNr.:\t%d", trace->var);
41 printf("\nValue:\t%d", trace->constant);
46 printf("\nValue:\t%d", trace->constant);
55 printf("Trace is null");
61 void show_change(struct Changes *c)
63 printf("*** Changes ***\n");
65 printf("Lower/Upper Bound:\t%d/%d\n", c->lower_bound, c->upper_bound);
67 printf("Unrestricted\n");
70 show_varinfo(struct LoopVar *lv)
72 printf(" *** Loop Info ***\n");
73 printf("Value:\t%d\n", lv->value);
74 printf("Static:\t\t%d/%d\n", lv->static_l, lv->static_u);
75 printf("D-Valid:\t%d/%d\n", lv->dynamic_l_v, lv->dynamic_u_v);
76 printf("Dynamic\t\t%d/%d\n", lv->dynamic_l, lv->dynamic_u);
79 void show_right_side()
82 printf("\n *** Head *** \nType:\t");
83 show_trace(c_rightside);
85 printf("\n *** Nested Loops: ***\n");
86 for (i=0; i<block_count; ++i)
87 printf("%d\t", c_nestedLoops[i]);
90 printf("\n *** Hierarchie: ***\n");
91 for (i=0; i<block_count; ++i)
92 printf("%d\t", c_hierarchie[i]);
96 printf("\n *** Current Loop ***\n");
97 for (i=0; i<block_count; ++i)
98 printf("%d\t", c_current_loop[i]);
105 struct LoopContainer *lc = c_allLoops;
107 printf("\n\n****** PASS 3 ******\n\n");
110 printf("Loop Analysis:\n");
111 printf("Optimize:\t%d\n", lc->toOpt);
112 printf("Modified Vars: ");
114 for (i=0; i<lc->num_vars; ++i)
115 printf("%d ", lc->vars[i]);
121 printf("\nNested Loops:\n");
122 for (i=0; i<block_count; ++i)
123 printf("%d ", c_nestedLoops[i]);
125 for (i=0; i<block_count; ++i)
126 printf("%d ", c_hierarchie[i]);
131 void show_tree(struct LoopContainer *lc, int tabs)
136 for (cnt = 0; cnt < tabs; ++cnt)
138 printf("%d\n", lc->loop_head);
140 show_tree(lc->tree_down, tabs+1);
150 void show_loop_statistics()
152 printf("\n\n****** LOOP STATISTICS ****** \n\n");
154 printf("Optimization cancelled by or\n");
155 else if (c_stat_exception)
156 printf("Optimization cancelled by exception\n");
158 printf("Number of array accesses:\t%d\n", c_stat_array_accesses);
159 if (c_stat_array_accesses) {
160 printf("\nFully optimized:\t%d\n", c_stat_full_opt);
161 printf("Not optimized:\t\t%d\n", c_stat_no_opt);
162 printf("Upper optimized:\t%d\n", c_stat_upper_opt);
163 printf("Lower optimized:\t%d\n", c_stat_lower_opt);
168 void show_procedure_statistics()
170 printf("\n\n****** PROCEDURE STATISTICS ****** \n\n");
171 printf("Number of loops:\t\t%d\n", c_stat_num_loops);
172 printf("Number of array accesses:\t%d\n", c_stat_sum_accesses);
173 if (c_stat_sum_accesses) {
174 printf("\nFully optimized:\t%d\n", c_stat_sum_full);
175 printf("Not optimized:\t\t%d\n", c_stat_sum_no);
176 printf("Upper optimized:\t%d\n", c_stat_sum_upper);
177 printf("Lower optimized:\t%d\n", c_stat_sum_lower);
179 printf("Opt. cancelled by or:\t\t%d\n", c_stat_sum_or);
180 printf("Opt. cancelled by exception:\t%d\n", c_stat_sum_exception);
186 /* This function is used to merge two loops with the same header together.
187 A simple merge sort of the lists nodes of both loops is performed.
189 void analyze_merge(struct LoopContainer *l1, struct LoopContainer *l2)
191 struct LoopElement *start, *last, *le1, *le2;
192 /* start and last are pointers to the newly built list, le1 and le2 step */
193 /* step through the lists, that have to be merged. */
198 /* start a simple merge sort of the nodes of both loops. These lists are */
199 /* already sorted, so merging is easy. */
200 if (le1->node < le2->node) {
204 else if (le1->node == le2->node) {
214 /* while the first loop != NULL, depending of the first element of second */
215 /* loop, add new node to result list */
216 while (le1 != NULL) {
222 if (le1->node < le2->node) {
226 else if (le1->node == le2->node) {
243 /* This function is used to merge loops with the same header node to a single
244 one. O(n^2) of number of loops. This merginig is necessary, because the loop
245 finding algorith sometimes (eg. when loopbody ends with a if-else construct)
246 reports a single loop as two loops with the same header node.
248 void analyze_double_headers()
251 struct LoopContainer *t1, *t2, *t3;
255 while (t1 != NULL) { /* for all loops do */
256 toCheck = t1->loop_head; /* get header node */
259 while (t2 != NULL) { /* compare it to headers of rest */
260 if (t2->loop_head == toCheck) {
262 /* found overlapping loops -> merge them together */
263 /* printf("C_INFO: found overlapping loops - merging"); */
264 analyze_merge(t1, t2);
266 /* remove second loop from the list of all loops */
268 while (t3->next != t2)
280 /* After the hierarchie of loops has been built, we have to insert the exceptions
281 into this tree. The exception ex is inserted into the subtree pointed to by
284 void insert_exception(struct LoopContainer *lc, xtable *ex)
286 struct LoopContainer *temp;
287 struct LoopElement *le;
290 /* printf("insert_exception called with %d-%d and loop %d\n", ex->start->debug_nr, ex->end->debug_nr, lc->loop_head); */
293 /* if child node is reached immediately insert exception into the tree */
294 if (lc->tree_down == NULL) {
295 ex->next = lc->exceptions;
299 /* if we are inside the tree, there are two possibilities: */
300 /* 1. the exception is inside a nested loop or */
301 /* 2. in the loop body of the current loop */
303 /* check all children (= nested loops) */
304 temp = lc->tree_down;
306 while (temp != NULL) {
312 printf("%d.%d\n", le->node, block_index[ex->startpc]);
314 /* if the start of the exception is part of the loop, the */
315 /* whole exception must be part of the loop */
316 if (le->node == block_index[ex->startpc])
321 /* Exception is part of a nested loop (Case 1) -> insert it there */
323 insert_exception(temp, ex);
326 else if ((temp->loop_head >= block_index[ex->startpc]) && (temp->loop_head < block_index[ex->endpc])) {
328 /* optimization: if nested loop is part of the exception, the */
329 /* exception cannot be part of a differnet nested loop. */
330 ex->next = lc->exceptions;
335 temp = temp->tree_right;
338 /* Exception is not contained in any nested loop (Case 2) */
340 ex->next = lc->exceptions;
347 /* This function builds a loop hierarchie. The header node of the innermost loop,
348 each basic block belongs to, is stored in the array c_nestedLoops. The array
349 c_hierarchie stores the relationship between differnt loops in as follows:
350 Each loop, that is a nested loop, stores its direct surrounding loop as a
351 parent. Top level loops have no parents.
353 void analyze_nested()
355 /* i/count/tmp are counters */
356 /* toOverwrite is used while loop hierarchie is built (see below) */
357 int i, count, header, toOverwrite, tmp, len;
359 /* first/last are used during topological sort to build ordered loop list */
360 struct LoopContainer *first, *last, *start, *t, *temp;
362 /* Used to step through all nodes of a loop. */
363 struct LoopElement *le;
365 /* init global structures */
366 c_nestedLoops = DMNEW(int, block_count);
367 c_hierarchie = DMNEW(int, block_count);
368 for (i=0; i<block_count; ++i) {
369 c_nestedLoops[i] = -1;
370 c_hierarchie[i] = -1;
373 /* if there are no optimizable loops -> return */
374 if (c_allLoops == NULL)
378 while (temp != NULL) { /* for all loops, do */
379 header = temp->loop_head;
381 /* toOverwrite is number of current parent loop (-1 if none) */
382 toOverwrite = c_nestedLoops[header];
384 c_hierarchie[header] = toOverwrite;
386 if (toOverwrite == header) /* check for loops with same header */
387 printf("C_ERROR: Loops have same header\n");
390 while (le != NULL) { /* for all loop nodes, do */
391 tmp = c_nestedLoops[le->node];
393 /* if node is part of parent loop -> overwrite it with nested */
394 if (tmp == toOverwrite)
395 c_nestedLoops[le->node] = header;
397 c_hierarchie[tmp] = header;
399 /* printf("set head of %d to %d", tmp, header); */
409 /* init root of hierarchie tree */
410 root = DMNEW(struct LoopContainer, 1);
411 LoopContainerInit(root, -1);
413 /* obtain parent pointer and build hierarchie tree */
415 while (start != NULL) {
417 /* look for parent of loop pointed at by start */
419 while (first != NULL) {
421 /* the parent of the loop, pointed at by start has been found */
422 if (first->loop_head == c_hierarchie[start->loop_head]) {
424 /* printf("set parent to pointer\n"); */
427 start->parent = first;
428 start->tree_right = first->tree_down;
429 first->tree_down = start;
436 /* no parent loop found, set parent to root */
439 /* printf("set parent to root\n"); */
442 start->parent = root;
443 start->tree_right = root->tree_down;
444 root->tree_down = start;
446 /* if a parent exists, increase this nodes indegree */
448 start->parent->in_degree += 1;
453 /* insert exceptions into tree */
455 printf("--- Showing tree ---\n");
457 printf(" --- End ---\n");
459 for (len = 0; len < exceptiontablelength; ++len)
460 insert_exception(root, extable + len);
463 /* determine sequence of loops for optimization by topological sort */
468 while (temp != NULL) {
470 /* a loops with indegree == 0 are pushed onto the stack */
471 if (temp->in_degree == 0) {
483 first = last = start;
487 printf("C_ERROR: loops are looped\n");
491 /* pop each node from the stack and decrease its parents indegree by one */
492 /* when the parents indegree reaches zero, push it onto the stack as well */
493 if ((last->parent != root) && (--last->parent->in_degree == 0)) {
494 last->parent->next = start;
495 start = last->parent;
497 while (start != NULL) {
504 if ((last->parent != root) && (--last->parent->in_degree == 0)) {
505 last->parent->next = start;
506 start = last->parent;
514 printf("*** Hierarchie Results \n");
515 while (first != NULL) {
516 printf("%d ", first->loop_head);
524 /* This function is used to add variables that occur as index variables in
525 array accesses (ARRAY_INDEX) or as variables, that change their value (VAR_MOD)
526 to the list of interesting vars (c_loopvars) for the current loop.
528 void add_to_vars(int var, int type, int direction)
532 /* printf("Added to vars %d %d %d\n", var, type, direction); */
534 while (lv != NULL) { /* check if var has been previously added */
535 if (lv->value == var) {
536 if (type == ARRAY_INDEX)
537 lv->index = 1; /* var is used as index */
538 else if (type == VAR_MOD) {
539 lv->modified = 1; /* var is used in assignment */
540 switch (direction) { /* how was var modified ? */
542 lv->static_u = 0; /* incremented, no static upper */
543 break; /* bound can be guaranteeed */
545 lv->static_l = 0; /* decremented, no static lower */
546 break; /* bound can be guaranteeed */
548 lv->static_u = lv->static_l = 0;
549 break; /* no info at all */
551 printf("C_ERROR: unknown direction\n");
560 /* variable is not found in list -> add variable to list */
561 lv = DNEW(struct LoopVar);
563 lv->modified = lv->index = 0;
566 if (type == ARRAY_INDEX) {
568 lv->static_u = lv->static_l = 1; /* arrayindex -> var not modified */
570 else if (type == VAR_MOD) {
572 switch (direction) { /* var used in assignment -> set */
573 case D_UP: /* proper static bounds */
574 lv->static_u = 0; lv->static_l = 1;
577 lv->static_u = 1; lv->static_l = 0;
580 lv->static_u = lv->static_l = 0;
583 printf("C_ERROR: unknown direction\n");
588 /* no dynamic bounds have been determined so far */
589 lv->dynamic_l = lv->dynamic_l_v = lv->dynamic_u = lv->dynamic_u_v = 0;
591 lv->next = c_loopvars; /* add var to list */
595 /* This function checks, whether a given loop with header node contains array
596 accesses. If so, it returns 1, else it returns 0 and the loops needs no
597 further consideration in the optimization process. When array accesses are
598 found, a list of all variables, that are used as array index, is built and
599 stored in c_loopvars. For all variables (integer), which values are changed,
600 a flag in c_var_modified is set.
602 int analyze_for_array_access(int node)
606 int ic, i, j, access;
607 struct depthElement *d;
610 if (c_toVisit[node] > 0) { /* node has not been visited yet */
613 bp = block[node]; /* prepare an instruction scan */
617 access = 0; /* number of array accesses in loop */
619 for (i=0; i<ic; ++i, ++ip) { /* for each instruction, check opcode */
621 case ICMD_IASTORE: /* array store */
629 t = tracing(&bp, i-1, 1); /* try to identify index variable */
631 if (t->type == TRACE_IVAR) {
632 /* if it is a variable, add it to list of index variables */
633 add_to_vars(t->var, ARRAY_INDEX, D_UNKNOWN);
636 else if (t->type == TRACE_ICONST)
640 case ICMD_IALOAD: /* array load */
648 t = tracing(&bp, i-1, 0); /* try to identify index variable */
650 if (t->type == TRACE_IVAR) {
651 /* if it is a variable, add it to list of index variables */
652 add_to_vars(t->var, ARRAY_INDEX, D_UNKNOWN);
655 else if (t->type == TRACE_ICONST)
659 case ICMD_ISTORE: /* integer store */
660 c_var_modified[ip->op1] = 1;
662 /* try to find out, how it was modified */
663 t = tracing(&bp, i-1, 0);
664 if (t->type == TRACE_IVAR) {
665 if ((t->constant > 0) && (t->var == ip->op1))
666 /* a constant was added to the same var */
667 add_to_vars(t->var, VAR_MOD, D_UP);
668 else if (t->var == ip->op1)
669 /* a constant was subtracted from the same var */
670 add_to_vars(t->var, VAR_MOD, D_DOWN);
672 add_to_vars(t->var, VAR_MOD, D_UNKNOWN);
675 add_to_vars(ip->op1, VAR_MOD, D_UNKNOWN);
678 case ICMD_IINC: /* simple add/sub of a constant */
679 c_var_modified[ip->op1] = 1;
682 add_to_vars(ip->op1, VAR_MOD, D_UP);
684 add_to_vars(ip->op1, VAR_MOD, D_DOWN);
691 c_var_modified[ip->op1] = 1;
699 while (d != NULL) { /* check all successors of block */
700 access += analyze_for_array_access(d->value);
710 /* This function scans the exception graph structure to find modifications of
711 array index variables of the current loop. If any modifications are found,
712 1 is returned, else 0.
714 int quick_scan(int node)
720 struct depthElement *d;
722 /* printf("QS: %d - %d\n", node, c_exceptionVisit[node]); */
725 if (c_exceptionVisit[node] > 0) { /* node is part of exception graph */
726 c_exceptionVisit[node] = -1;
728 bp = block[node]; /* setup scan of all instructions */
732 for (i=0; i<count; ++i, ++ip) { /* for each instruction do */
735 case ICMD_IINC: /* a variable is modified */
737 lv = c_loopvars; /* is it an array index var ? */
739 if ((lv->index) && (lv->value == ip->op1))
740 return 1; /* yes, so return 1 */
747 d = c_exceptionGraph[node]; /* check all successor nodes */
749 if (quick_scan(d->value) > 0)
750 return 1; /* if an access is found return 1 */
754 return 0; /* nothing found, so return 0 */
760 /* This function returns 1, when the condition of the loop contains
761 or statements or when an array index variable is modified in any
762 catch block within the loop.
764 int analyze_or_exceptions(int head, struct LoopContainer *lc)
766 struct depthElement *d, *tmp, *tmp2;
767 int i, j, k, value, flag, count;
768 struct LoopElement *le;
773 /* analyze for or-statements */
775 printf("*** Analyze for OR ... ");
779 while (d != NULL) { /* for all successor nodes check if they */
780 value = d->value; /* are part of the loop */
785 if (le->node == value)
790 if (le == NULL) /* node is not part of the loop */
797 if ((count > 1) && (flag == 0)){/* if all successors part of the loop, exit */
804 /* check for exceptions */
805 /* printf("done\n*** Analyze for EXCEPTIONS(%d) . ", exceptiontablelength); */
807 if (!exceptiontablelength) /* when there are no exceptions, exit */
810 if ((c_exceptionGraph = (struct depthElement **) malloc(sizeof(struct depthElement *) * block_count)) == NULL)
812 if ((c_exceptionVisit = (int *) malloc(sizeof(int) * block_count)) == NULL)
815 for (k=0; k<block_count; ++k) {
816 c_exceptionVisit[k] = -1;
817 c_exceptionGraph[k] = NULL;
821 /* for all nodes that start catch block check whether they are part of loop */
822 for (i = 0; i < c_old_xtablelength; i++) {
823 value = block_index[extable[i].startpc];
828 if (le->node == value) { /* exception is in loop */
830 printf("C_INFO: Loop contains exception\n");
834 /* build a graph structure, that contains all nodes that are */
835 /* part of the catc block */
836 dF_Exception(-1, block_index[extable[i].handlerpc]);
838 /* if array index variables are modified there, return 0 */
839 if (quick_scan(block_index[extable[i].handlerpc]) > 0) {
843 /* printf("C_INFO: loopVar modified in exception\n"); */
852 printf("none ... done\n");
858 /* This function sets a flag in c_var_modified for all variables that have
859 been found as part of an assigment in the loop.
861 void scan_global_list()
868 c_var_modified[lv->value] = 1;
873 /* This function analyses the condition in the loop header and trys to find
874 out, whether some dynamic guarantees can be set up.
876 void init_constraints(int head)
880 int ic, l_mod, r_mod, changed, operand;
881 struct Trace *left, *right, *th;
882 struct LoopVar *lv_left, *lv_right, *lh;
886 ip = bp.iinstr+(ic-1); /* set ip to last instruction in header node */
888 switch (ip->opc) { /* check op-code */
890 /* comparison against constant value */
891 case ICMD_IFEQ: /* ..., value ==> ... */
892 case ICMD_IFLT: /* ..., value ==> ... */
893 case ICMD_IFLE: /* ..., value ==> ... */
894 case ICMD_IFGT: /* ..., value ==> ... */
895 case ICMD_IFGE: /* ..., value ==> ... */
896 /* op1 = target JavaVM pc, val.i = constant */
898 left = tracing(&bp, ic-2, 0); /* analyse left arg., right is constant */
899 right = create_trace(TRACE_ICONST, -1, ip->val.i, 0);
902 /* standard comparison */
903 case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */
904 case ICMD_IF_ICMPLT: /* ..., value, value ==> ... */
905 case ICMD_IF_ICMPGT: /* ..., value, value ==> ... */
906 case ICMD_IF_ICMPLE: /* ..., value, value ==> ... */
907 case ICMD_IF_ICMPGE: /* ..., value, value ==> ... */
909 left = tracing(&bp, ic-2, 1); /* get left and right argument */
910 right = tracing(&bp, ic-2, 0);
913 /* other condition */
915 left = create_trace(TRACE_UNKNOWN, -1, 0, 0);
916 right = create_trace(TRACE_UNKNOWN, -1, 0, 0);
920 /* analyse left and right side of comparison */
923 if (left->type == TRACE_IVAR) { /* is a loop variable on left side ? */
924 lv_left = c_loopvars;
925 while (lv_left != NULL) {
926 if (lv_left->value == left->var) {
927 l_mod = lv_left->modified; /* yes, but has it been modified ? */
930 lv_left = lv_left->next;
934 if (right->type == TRACE_IVAR){ /* is a loop variable on right side ? */
935 lv_right = c_loopvars;
936 while (lv_right != NULL) {
937 if (lv_right->value == right->var) {
938 r_mod = lv_right->modified; /* yes, but has it been modified ? */
941 lv_right = lv_right->next;
945 if ((l_mod - r_mod) == 0) { /* both 1 or both 0 -> no dynamic contraints*/
946 c_rightside = NULL; /* possible */
950 /* to simplify processing, make the left side the one, that contains the */
951 /* modified variable */
953 th = left; left = right; right = th;
954 lh = lv_left; lv_left = lv_right; lv_right = lh;
955 changed = 1; /* set changed to true */
958 changed = 0; /* no change needed */
960 /* make sure that right side's value does not change during loop execution */
961 if (right->type == TRACE_UNKNOWN) {
966 /* determine operands: */
967 /* for further explaination a is modified, b nonmodified var */
968 switch (ip->opc) { /* check opcode again */
969 case ICMD_IFEQ: /* ..., value ==> ... */
970 case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */
971 operand = OP_EQ; /* a == b */
974 case ICMD_IFLE: /* ..., value ==> ... */
975 case ICMD_IF_ICMPLE: /* ..., value, value ==> ... */
977 operand = OP_GE; /* b<=a -> a>=b */
979 operand = OP_LT; /* a<=b -> a<(b+1) */
980 if (left->constant != 0)
983 right->constant += 1;
987 case ICMD_IFLT: /* ..., value ==> ... */
988 case ICMD_IF_ICMPLT: /* ..., value, value ==> ... */
990 operand = OP_GE; /* b<a -> a>=(b+1) */
991 if (left->constant != 0)
994 right->constant += 1;
997 operand = OP_LT; /* a<b -> a<b */
1000 case ICMD_IFGT: /* ..., value ==> ... */
1001 case ICMD_IF_ICMPGT: /* ..., value, value ==> ... */
1003 operand = OP_LT; /* b>a -> a<b */
1005 operand = OP_GE; /* a>b -> a>=(b+1) */
1006 if (left->constant != 0)
1007 left->constant -= 1;
1009 right->constant += 1;
1013 case ICMD_IFGE: /* ..., value ==> ... */
1014 case ICMD_IF_ICMPGE: /* ..., value, value ==> ... */
1016 operand = OP_LT; /* b>=a -> a<(b+1) */
1017 if (left->constant != 0)
1018 left->constant -= 1;
1020 right->constant += 1;
1023 operand = OP_GE; /* a>=b -> a>=b */
1027 printf("C_ERROR: debugging error 0x00\n");
1031 /* NOW: left/lv_left -> loopVar */
1032 /* right/lv_right -> const, nonmod. var, arraylength */
1033 switch (operand) { /* check operand */
1035 lv_left->dynamic_u_v = 1; /* upper + lower bound tested */
1036 lv_left->dynamic_l_v = 1;
1038 lv_left->dynamic_l = lv_left->dynamic_u = left->constant;
1042 lv_left->dynamic_u_v = 1; /* upper bound tested */
1044 lv_left->dynamic_u = left->constant;
1048 lv_left->dynamic_l_v = 1; /* lower bound tested */
1050 lv_left->dynamic_l = left->constant;
1054 printf("C_ERROR: debugging error 0x01\n");
1057 c_rightside = right;
1059 switch (c_rightside->type) {
1061 c_rs_needed_instr = 1;
1064 c_rs_needed_instr = 2;
1067 c_rs_needed_instr = 3;
1070 printf("C_ERROR: wrong right-side type\n");
1074 /* This function is needed to add and record new static tests (before loop
1075 entry) of variables to make guaratees for index variables. type states
1076 the kind of the test. arrayRef is the array, which length is tested
1077 against, varRef is the variable, that is testes and constant is the
1078 constant value, that is tested.
1080 void add_new_constraint(int type, int arrayRef, int varRef, int constant)
1082 struct Constraint *tc;
1085 case TEST_ZERO: /* a variable is tested against a const */
1087 tc = c_constraints[varRef]; /* does a test already exist for this var ? */
1088 while (tc != NULL) {
1089 if (tc->type == TEST_ZERO) {
1090 if (constant < tc->constant)
1091 tc->constant = constant;
1092 return; /* yes. update constant and return */
1097 /* insert a new test for this variable */
1098 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1100 tc->type = TEST_ZERO;
1101 tc->varRef = varRef;
1102 tc->constant = constant;
1103 tc->next = c_constraints[varRef];
1104 c_constraints[varRef] = tc;
1105 c_needed_instr += 3;
1109 case TEST_ALENGTH: /* variable is tested against array length */
1111 tc = c_constraints[varRef]; /* does a test already exist for this var ? */
1112 while (tc != NULL) {
1113 if ((tc->type == TEST_ALENGTH) && (tc->arrayRef == arrayRef)) {
1114 if (constant > tc->constant)
1115 tc->constant = constant;
1116 return; /* yes. update constant and return */
1121 /* insert a new test for this variable */
1122 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1124 tc->type = TEST_ALENGTH;
1125 tc->arrayRef = arrayRef;
1126 tc->varRef = varRef;
1127 tc->constant = constant;
1128 tc->next = c_constraints[varRef];
1129 c_constraints[varRef] = tc;
1130 c_needed_instr += 6;
1132 /* if arrayRef is not already tested against null, insert that test */
1133 if (!(c_null_check[arrayRef])) {
1134 c_null_check[arrayRef] = 1;
1140 case TEST_CONST_ZERO:
1144 case TEST_CONST_ALENGTH: /* a const is tested against array length */
1146 /* does a test already exist for this array */
1147 tc = c_constraints[maxlocals];
1148 while (tc != NULL) {
1149 if ((tc->type == TEST_CONST_ALENGTH) && (tc->arrayRef == arrayRef)) {
1150 if (constant > tc->constant)
1151 tc->constant = constant;
1152 return; /* yes. update constant and return */
1157 /* insert a new test for this array */
1158 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1160 tc->type = TEST_CONST_ALENGTH;
1161 tc->arrayRef = arrayRef;
1162 tc->constant = constant;
1163 tc->next = c_constraints[maxlocals];
1164 c_constraints[maxlocals] = tc;
1165 c_needed_instr += 4;
1167 /* if arrayRef is not already tested against null, insert that test */
1168 if (!(c_null_check[arrayRef])) {
1169 c_null_check[arrayRef] = 1;
1175 case TEST_UNMOD_ZERO: /* test unmodified var against constant */
1177 /* search if test already exists */
1178 tc = c_constraints[varRef];
1179 while (tc != NULL) {
1180 if (tc->type == TEST_UNMOD_ZERO) {
1181 if (constant < tc->constant)
1182 tc->constant = constant;
1183 return; /* yes, so update constant */
1188 /* else, a new test is inserted */
1189 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1191 tc->type = TEST_UNMOD_ZERO;
1192 tc->varRef = varRef;
1193 tc->constant = constant;
1194 tc->next = c_constraints[varRef];
1195 c_constraints[varRef] = tc;
1196 c_needed_instr += 3;
1200 case TEST_UNMOD_ALENGTH: /* test unmodified var against array length */
1202 /* search if test alreay exists */
1203 tc = c_constraints[varRef];
1204 while (tc != NULL) {
1205 if ((tc->type == TEST_UNMOD_ALENGTH) && (tc->arrayRef == arrayRef)) {
1206 if (constant > tc->constant)
1207 tc->constant = constant;
1208 return; /* yes, so modify constants */
1213 /* create new entry */
1214 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1216 tc->type = TEST_UNMOD_ALENGTH;
1217 tc->varRef = varRef;
1218 tc->arrayRef = arrayRef;
1219 tc->constant = constant;
1220 tc->next = c_constraints[varRef];
1221 c_constraints[varRef] = tc;
1222 c_needed_instr += 6;
1224 /* if arrayRef is not already tested against null, insert that test */
1225 if (!(c_null_check[arrayRef])) {
1226 c_null_check[arrayRef] = 1;
1232 case TEST_RS_ZERO: /* test right side of the loop condition */
1233 /* against a constant - needed by dynamic */
1235 /*!! varRef -> maxlocals */
1236 /* search if test already exists */
1237 tc = c_constraints[maxlocals];
1238 while (tc != NULL) {
1239 if (tc->type == TEST_RS_ZERO) {
1240 if (constant < tc->constant)
1241 tc->constant = constant;
1242 return; /* yes, so modify constants */
1247 /* create new entry */
1248 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1250 tc->type = TEST_RS_ZERO;
1251 tc->constant = constant;
1252 tc->next = c_constraints[maxlocals];
1253 c_constraints[maxlocals] = tc;
1254 c_needed_instr += (2 + c_rs_needed_instr);
1256 /* if arrayRef on right side is not already tested against null, */
1257 /* insert that test */
1258 if ((c_rightside->type == TRACE_ALENGTH) && (!(c_null_check[c_rightside->var]))) {
1259 c_null_check[c_rightside->var] = 1;
1265 case TEST_RS_ALENGTH: /* test right side of the loop condition */
1266 /* against array length - needed by dynamic */
1268 /*!! varRef -> maxlocals */
1269 /* search if test already exists */
1270 tc = c_constraints[maxlocals];
1273 if ((tc->type == TEST_RS_ALENGTH) && (tc->arrayRef == arrayRef))
1275 if (constant > tc->constant)
1276 tc->constant = constant;
1277 return; /* yes, so modify constants */
1282 /* create new entry */
1283 if ((tc = (struct Constraint *) malloc(sizeof(struct Constraint))) == NULL)
1285 tc->type = TEST_RS_ALENGTH;
1286 tc->arrayRef = arrayRef;
1287 tc->constant = constant;
1288 tc->next = c_constraints[maxlocals];
1289 c_constraints[maxlocals] = tc;
1290 c_needed_instr += (3 + c_rs_needed_instr);
1292 /* if arrayRef is not already tested against null, insert that test */
1293 if (!(c_null_check[arrayRef])) {
1294 c_null_check[arrayRef] = 1;
1298 /* if arrayRef on right side is not already tested against null, */
1299 /* insert that test */
1300 if ((c_rightside->type == TRACE_ALENGTH) && (!(c_null_check[c_rightside->var]))) {
1301 c_null_check[c_rightside->var] = 1;
1309 /* This functions adds new static (before loop enry) tests of variables to the
1310 program to be able to guarantee certain values for index variables in array
1311 access (to safely remove bound checks).
1313 int insert_static(int arrayRef, struct Trace *index, struct Changes *varChanges, int special)
1315 struct Constraint *tc;
1320 /* printf("insert static check - %d\n", arrayRef);
1322 show_change(varChanges);
1325 if (varChanges == NULL) { /* the variable hasn't changed / const */
1326 if ((varChanges = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
1328 varChanges->lower_bound = varChanges->upper_bound = 0;
1331 switch (index->type) { /* check index type */
1332 case TRACE_IVAR: /* it is a variable */
1333 if (index->neg < 0) { /* if it's a negated var, return */
1340 varRef = index->var;
1343 if (c_var_modified[varRef]) { /* volatile var */
1345 lv = c_loopvars; /* get reference to loop variable */
1347 while ((lv != NULL) && (lv->value != varRef))
1350 printf("C_ERROR: debugging error 0x02\n");
1352 /* show_varinfo(lv); */
1354 /* check existing static bounds and add new contraints on variable */
1355 /* to possibly remove bound checks */
1357 /* the var is never decremented, so we add a static test againt */
1359 if (varChanges->lower_bound > varChanges->upper_bound)
1360 add_new_constraint(TEST_ZERO, arrayRef, varRef, index->constant);
1362 add_new_constraint(TEST_ZERO, arrayRef, varRef, varChanges->lower_bound+index->constant);
1365 else if ((lv->dynamic_l_v) && (!special)) {
1366 /* the variable is decremented, but it is checked against a */
1367 /* bound in the loop condition */
1368 if (varChanges->lower_bound <= varChanges->upper_bound) {
1369 add_new_constraint(TEST_RS_ZERO, arrayRef, varRef, varChanges->lower_bound+index->constant+lv->dynamic_l);
1375 /* the var is never incremented, so we add a static test againt */
1377 if (varChanges->lower_bound > varChanges->upper_bound)
1378 add_new_constraint(TEST_ALENGTH, arrayRef, varRef, index->constant);
1380 add_new_constraint(TEST_ALENGTH, arrayRef, varRef, varChanges->upper_bound+index->constant);
1383 else if ((lv->dynamic_u_v) && (!special)) {
1384 /* the variable is decremented, but it is checked against a */
1385 /* bound in the loop condition */
1386 if (varChanges->lower_bound <= varChanges->upper_bound) {
1387 add_new_constraint(TEST_RS_ALENGTH, arrayRef, varRef, varChanges->upper_bound+index->constant+lv->dynamic_u);
1392 else { /* the var is never modified at all */
1393 add_new_constraint(TEST_UNMOD_ZERO, arrayRef, index->var, index->constant);
1394 add_new_constraint(TEST_UNMOD_ALENGTH, arrayRef, index->var, index->constant);
1398 /* if the addition of new variable tests made guarantees possible, */
1399 /* return the best possible optimization */
1400 if ((high > 0) && (low > 0)) {
1401 /* printf("fully optimzed\n"); */
1407 else if (high > 0) {
1408 /* printf("upper optimzed\n"); */
1415 /* printf("lower optimzed\n"); */
1422 /* printf("not optimzed\n"); */
1430 case TRACE_ICONST: /* if it is a constant, optimization is easy */
1431 if (index->constant < 0) {
1435 return OPT_NONE; /* negative index -> bad */
1438 add_new_constraint(TEST_CONST_ALENGTH, arrayRef, 0, index->constant);
1442 return OPT_FULL; /* else just test constant against array length */
1446 case TRACE_ALENGTH: /* else, no optimizations possible */
1458 /* copy a stack and return the start pointer of the newly created one
1460 stackptr copy_stack_from(stackptr source) {
1461 stackptr current, top;
1466 /* copy first element */
1467 current = DMNEW(stackelement, 1);
1468 current->type = source->type;
1469 current->flags = source->flags;
1470 current->varkind = source->varkind;
1471 current->varnum = source->varnum;
1472 current->regoff = source->regoff;
1476 /* if there exist more, then copy the rest */
1477 while (source->prev != NULL) {
1478 source = source->prev;
1479 current->prev = DMNEW(stackelement, 1);
1480 current->type = source->type;
1481 current->flags = source->flags;
1482 current->varkind = source->varkind;
1483 current->varnum = source->varnum;
1484 current->regoff = source->regoff;
1485 current = current->prev;
1488 current->prev = NULL;
1493 /* The following defines are used in the procedure void create_static_checks(...)
1494 They add a new instruction with its corresponding stack manipulation and
1495 are used to build the new loop header of an optimized loop, where we have
1496 to check certain variables and constants against values to guarantee that
1497 index values in array accesses remain with array bounds.
1499 inst: pointer to the new instruction
1500 tos: stackpointer before this operation is executed
1501 newstack: temporary stackptr
1502 stackdepth: counts the current stackdepth
1503 original start: blockpointer to the head of the new, optimized loop
1506 /* Load a local integer variable v */
1507 #define LOAD_VAR(v) { \
1508 inst->opc = ICMD_ILOAD; \
1510 newstack = DMNEW(stackelement, 1); \
1511 inst->dst = newstack; \
1512 newstack->prev = tos; \
1513 newstack->type = TYPE_INT; \
1514 newstack->flags = 0; \
1515 newstack->varkind = LOCALVAR; \
1516 newstack->varnum = v; \
1522 /* Load a constant with value c */
1523 #define LOAD_CONST(c) { \
1524 inst->opc = ICMD_ICONST; \
1526 inst->val.i = (c); \
1527 newstack = DMNEW(stackelement, 1); \
1528 newstack->prev = tos; \
1529 newstack->type = TYPE_INT; \
1530 newstack->flags = 0; \
1531 newstack->varkind = UNDEFVAR; \
1532 newstack->varnum = stackdepth; \
1539 /* Load a local reference (adress) variable a */
1540 #define LOAD_ADDR(a) { \
1541 inst->opc = ICMD_ALOAD; \
1543 newstack = DMNEW(stackelement, 1); \
1544 newstack->prev = tos; \
1545 newstack->type = TYPE_ADR; \
1546 newstack->flags = 0; \
1547 newstack->varkind = LOCALVAR; \
1548 newstack->varnum = a; \
1555 /* Insert a compare greater-or-equal and jump to the unoptimized loop, if the */
1556 /* comparison is true */
1557 #define GOTO_NOOPT_IF_GE { \
1558 inst->opc = ICMD_IF_ICMPGE; \
1559 inst->target = original_start->copied_to; \
1560 if (tos->varkind == UNDEFVAR) \
1561 tos->varkind = TEMPVAR; \
1563 if (tos->varkind == UNDEFVAR) \
1564 tos->varkind = TEMPVAR; \
1571 /* Insert a compare greater than and jump to the unoptimized loop, if the */
1572 /* comparison is true */
1573 #define GOTO_NOOPT_IF_GT { \
1574 inst->opc = ICMD_IF_ICMPGT; \
1575 inst->target = original_start->copied_to; \
1576 if (tos->varkind == UNDEFVAR) \
1577 tos->varkind = TEMPVAR; \
1579 if (tos->varkind == UNDEFVAR) \
1580 tos->varkind = TEMPVAR; \
1588 /* Insert a compare less-than and jump to the unoptimized loop, if the */
1589 /* comparison is true */
1590 #define GOTO_NOOPT_IF_LT { \
1591 inst->opc = ICMD_IF_ICMPLT; \
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 if-not-null and jump to the unoptimized loop, if the */
1605 /* comparison is true */
1606 #define GOTO_NOOPT_IF_NULL { \
1607 inst->opc = ICMD_IFNULL; \
1608 inst->target = original_start->copied_to; \
1609 if(tos->varkind == UNDEFVAR) \
1610 tos->varkind = TEMPVAR; \
1617 /* Insert an add instruction, that adds two integer values on top of the stack */
1620 inst->opc = ICMD_IADD; \
1621 if(tos->varkind == UNDEFVAR) \
1622 tos->varkind = TEMPVAR; \
1624 if(tos->varkind == UNDEFVAR) \
1625 tos->varkind = TEMPVAR; \
1627 newstack = DMNEW(stackelement, 1); \
1628 newstack->prev = tos; \
1629 newstack->type = TYPE_INT; \
1630 newstack->flags = 0; \
1631 newstack->varkind = UNDEFVAR; \
1632 newstack->varnum = stackdepth; \
1639 /* Insert instructions to load the arraylength of an array with reference a */
1640 /* fisrt, the reference must be loaded, then a null-pointer check is inserted */
1641 /* if not already done earlier. Finally an arraylength instruction is added */
1642 #define LOAD_ARRAYLENGTH(a) { \
1643 if (c_null_check[a]) { \
1645 GOTO_NOOPT_IF_NULL; \
1646 c_null_check[a] = 0; \
1649 inst->opc = ICMD_ARRAYLENGTH; \
1650 if(tos->varkind == UNDEFVAR) \
1651 tos->varkind = TEMPVAR; \
1653 newstack = DMNEW(stackelement, 1); \
1654 newstack->prev = tos; \
1655 newstack->type = TYPE_INT; \
1656 newstack->flags = 0; \
1657 newstack->varkind = UNDEFVAR; \
1658 newstack->varnum = stackdepth; \
1665 /* Inserts the instructions to load the value of the right side of comparison */
1666 /* Depending of the type of the right side, the apropriate instructions are */
1668 #define LOAD_RIGHT_SIDE { \
1669 switch (c_rightside->type) { \
1670 case TRACE_ICONST: \
1671 LOAD_CONST(c_rightside->constant); \
1674 LOAD_VAR(c_rightside->var); \
1675 LOAD_CONST(c_rightside->constant); \
1678 case TRACE_ALENGTH: \
1679 LOAD_ARRAYLENGTH(c_rightside->var); \
1682 printf("C_ERROR: illegal trace on rightside of loop-header\n"); \
1687 /* Patch jumps in original loop and in copied loop, add gotos in copied loop.
1688 All jumps in the original loop to the loop head have to be redirected to
1689 the newly inserted one. For the copied loop, it is necessay to redirect all
1690 jumps inside that loop to the copied nodes. lc points to the current loop,
1691 loop_head is a pointer to the newly inserted head and original start was
1692 the old head and is now the head of the optimized variant of the loop.
1694 void patch_jumps(basicblock *original_start, basicblock *loop_head, struct LoopContainer *lc)
1696 /* step through all nodes of a loop */
1697 struct LoopElement *le;
1699 instruction *inst, *temp_instr;
1703 while (le != NULL) {
1705 /* do nothing for new loop head */
1706 if (le->block == loop_head) {
1711 /* for original version */
1713 inst = bptr->iinstr;
1714 for (i = 0; i < bptr->icount; ++i, ++inst) {
1715 switch (inst->opc) {
1717 case ICMD_IF_ICMPEQ:
1718 case ICMD_IF_ICMPLT:
1719 case ICMD_IF_ICMPLE:
1720 case ICMD_IF_ICMPNE:
1721 case ICMD_IF_ICMPGT:
1722 case ICMD_IF_ICMPGE:
1724 case ICMD_IF_LCMPEQ:
1725 case ICMD_IF_LCMPLT:
1726 case ICMD_IF_LCMPLE:
1727 case ICMD_IF_LCMPNE:
1728 case ICMD_IF_LCMPGT:
1729 case ICMD_IF_LCMPGE:
1731 case ICMD_IF_ACMPEQ:
1732 case ICMD_IF_ACMPNE:
1751 case ICMD_IFNONNULL:
1753 /* jump to newly inserted loopheader has to be redirected */
1754 if (((basicblock *) inst->target) == loop_head)
1755 inst->target = (void *) original_start;
1758 case ICMD_TABLESWITCH:
1763 tptr = (void **) inst->target;
1765 s4ptr = inst->val.a;
1766 l = s4ptr[1]; /* low */
1767 i = s4ptr[2]; /* high */
1771 /* jump to newly inserted loopheader has to be redirected */
1772 for (tptr = inst->target; i >= 0; --i, ++tptr) {
1773 if (((basicblock *) *tptr) == loop_head)
1774 tptr[0] = (void *) original_start;
1779 case ICMD_LOOKUPSWITCH:
1781 s4 i, l, val, *s4ptr;
1784 tptr = (void **) inst->target;
1786 s4ptr = inst->val.a;
1787 l = s4ptr[0]; /* default */
1788 i = s4ptr[1]; /* count */
1790 /* jump to newly inserted loopheader has to be redirected */
1791 for (tptr = inst->target; i >= 0; --i, ++tptr) {
1792 if (((basicblock *) *tptr) == loop_head)
1793 tptr[0] = (void *) original_start;
1801 /* if node is part of loop and has fall through to original start, that */
1802 /* must be redirected. Unfortunately the instructions have to be copied */
1804 if (bptr->next == loop_head) {
1805 temp_instr = DMNEW(instruction, bptr->icount + 1);
1806 memcpy(temp_instr, bptr->iinstr, sizeof(instruction)*bptr->icount);
1807 bptr->iinstr = temp_instr;
1809 bptr->iinstr[bptr->icount].opc = ICMD_GOTO;
1810 bptr->iinstr[bptr->icount].target = original_start;
1811 bptr->iinstr[bptr->icount].dst = NULL;
1815 /* for copied version - which gets the unoptimized variant */
1816 bptr = le->block->copied_to;
1817 inst = bptr->iinstr;
1818 for (i = 0; i < bptr->icount; ++i, ++inst) {
1820 switch (inst->opc) {
1822 case ICMD_IASTORE: /* array store */
1830 case ICMD_IALOAD: /* array load */
1839 /* undo previous optimizations in new loop */
1843 case ICMD_IF_ICMPEQ:
1844 case ICMD_IF_ICMPLT:
1845 case ICMD_IF_ICMPLE:
1846 case ICMD_IF_ICMPNE:
1847 case ICMD_IF_ICMPGT:
1848 case ICMD_IF_ICMPGE:
1850 case ICMD_IF_LCMPEQ:
1851 case ICMD_IF_LCMPLT:
1852 case ICMD_IF_LCMPLE:
1853 case ICMD_IF_LCMPNE:
1854 case ICMD_IF_LCMPGT:
1855 case ICMD_IF_LCMPGE:
1857 case ICMD_IF_ACMPEQ:
1858 case ICMD_IF_ACMPNE:
1877 case ICMD_IFNONNULL:
1879 /* jump to newly inserted loopheader has to be redirected */
1880 if (((basicblock *) inst->target) == loop_head)
1881 inst->target = (void *) original_start->copied_to;
1882 /* jump to loop internal nodes has to be redirected */
1883 else if (((basicblock *) inst->target)->lflags & LOOP_PART)
1884 inst->target = (void *) ((basicblock *) inst->target)->copied_to;
1887 case ICMD_TABLESWITCH:
1891 void **copy_ptr, *base_ptr;
1894 tptr = (void **) inst->target;
1896 s4ptr = inst->val.a;
1897 l = s4ptr[1]; /* low */
1898 i = s4ptr[2]; /* high */
1902 copy_ptr = (void**) DMNEW(void*, i+1);
1903 base_ptr = (void*) copy_ptr;
1905 /* Targets for switch instructions are stored in an extra */
1906 /* that must be copied for new inserted loop. */
1908 for (tptr = inst->target; i >= 0; --i, ++tptr, ++copy_ptr) {
1909 /* jump to newly inserted loopheader must be redirected */
1910 if (((basicblock *) *tptr) == loop_head)
1911 copy_ptr[0] = (void *) original_start->copied_to;
1912 /* jump to loop internal nodes has to be redirected */
1913 else if (((basicblock *) *tptr)->lflags & LOOP_PART)
1914 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
1916 copy_ptr[0] = tptr[0];
1919 inst->target = base_ptr;
1923 case ICMD_LOOKUPSWITCH:
1925 s4 i, l, val, *s4ptr;
1927 void **copy_ptr, **base_ptr;
1930 tptr = (void **) inst->target;
1932 s4ptr = inst->val.a;
1933 l = s4ptr[0]; /* default */
1934 i = s4ptr[1]; /* count */
1936 copy_ptr = (void**) DMNEW(void*, i+1);
1937 base_ptr = (void*) copy_ptr;
1939 /* Targets for switch instructions are stored in an extra */
1940 /* that must be copied for new inserted loop. */
1942 for (tptr = inst->target; i >= 0; --i, ++tptr, ++copy_ptr) {
1943 /* jump to newly inserted loopheader must be redirected */
1944 if (((basicblock *) *tptr) == loop_head)
1945 copy_ptr[0] = (void *) original_start->copied_to;
1946 /* jump to loop internal nodes has to be redirected */
1947 else if (((basicblock *) *tptr)->lflags & LOOP_PART)
1948 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
1950 copy_ptr[0] = tptr[0];
1953 inst->target = base_ptr;
1960 /* if fall through exits loop, goto is needed */
1961 if (!(le->block->next->lflags & LOOP_PART)) {
1962 bptr->iinstr[bptr->icount].opc = ICMD_GOTO;
1963 bptr->iinstr[bptr->icount].dst = NULL;
1964 bptr->iinstr[bptr->icount].target = le->block->next;
1972 /* Add the new header node of a loop that has been duplicated to all parent
1973 loops in nesting hierarchie.
1975 void header_into_parent_loops(struct LoopContainer *lc, basicblock *to_insert, basicblock *replace, basicblock *after)
1977 /* we have to insert the node to_insert before the node after and replace */
1978 /* the pointer of to_insert by the node replace */
1980 struct LoopElement *le, *t;
1982 /* if the top of the tree is reached, then return */
1983 if ((lc == NULL) || (lc == root))
1986 /* create new node, that should be inserted */
1987 t = DMNEW(struct LoopElement, 1);
1988 t->block = to_insert;
1991 /* first, find the node, that has to be replaced (= "to_insert") and */
1992 /* replace it by the node "replace" */
1994 while (le->block != to_insert)
1996 le->block = replace;
1999 if (after == to_insert)
2002 /* now find the node after and insert the newly create node before "after" */
2004 if (le->block == after) {
2005 t->next = lc->nodes;
2009 while (le->next->block != after)
2016 /* go up one hierarchie level */
2017 header_into_parent_loops(lc->parent, to_insert, replace, after);
2020 /* Add a new node (not header) of a duplicated loop to all parent loops in
2023 void node_into_parent_loops(struct LoopContainer *lc, basicblock *to_insert)
2025 struct LoopElement *le, *t;
2027 /* if the top of the tree is reached, then return */
2028 if ((lc == NULL) || (lc == root))
2031 /* create new node, that should be inserted */
2032 t = DMNEW(struct LoopElement, 1);
2033 t->block = to_insert;
2038 /* append new node to node list of loop */
2039 while (le->next != NULL)
2045 /* go up one hierarchie level */
2046 node_into_parent_loops(NULL, to_insert);
2050 /* void patch_handler(...) is very similar to parts of the function patch_jumps.
2051 Its task is to redirect all jumps from the original head to the new head and
2052 to redirect internal jumps inside the exception handler to the newly
2053 created (copied) nodes.
2055 void patch_handler(struct LoopContainer *lc, basicblock *bptr, basicblock *original_head, basicblock *new_head)
2060 int high, low, count, i;
2062 /* If node is not part of exception handler or has been visited, exit */
2063 if (!(bptr->lflags & HANDLER_PART) || (bptr->lflags & HANDLER_VISITED))
2066 /* mark block as visited */
2067 bptr->lflags |= HANDLER_VISITED;
2069 /* for all instructions in the copied block, do */
2070 for (i = 0, ip = bptr->copied_to->iinstr; i < bptr->copied_to->icount; ++i, ++ip) {
2081 case ICMD_IF_ICMPEQ:
2082 case ICMD_IF_ICMPLT:
2083 case ICMD_IF_ICMPLE:
2084 case ICMD_IF_ICMPNE:
2085 case ICMD_IF_ICMPGT:
2086 case ICMD_IF_ICMPGE:
2088 case ICMD_IF_LCMPEQ:
2089 case ICMD_IF_LCMPLT:
2090 case ICMD_IF_LCMPLE:
2091 case ICMD_IF_LCMPNE:
2092 case ICMD_IF_LCMPGT:
2093 case ICMD_IF_LCMPGE:
2095 case ICMD_IF_ACMPEQ:
2096 case ICMD_IF_ACMPNE:
2114 case ICMD_IFNONNULL:
2116 patch_handler(lc, bptr->next, original_head, new_head);
2122 patch_handler(lc, ip->target, original_head, new_head);
2124 /* jumps to old header have to be redirected */
2125 if (((basicblock *) ip->target) == original_head)
2126 ip->target = (void *) new_head->copied_to;
2127 /* jumps to handler internal nodes have to be redirected */
2128 else if (((basicblock *) ip->target)->lflags & HANDLER_PART)
2129 ip->target = (void *) ((basicblock *) ip->target)->copied_to;
2130 /* jumps to loop internal nodes have to be redirected */
2131 else if (((basicblock *) ip->target)->lflags & LOOP_PART)
2132 ip->target = (void *) ((basicblock *) ip->target)->copied_to;
2137 case ICMD_TABLESWITCH:
2141 void **copy_ptr, **base_ptr;
2143 tptr = (void **) ip->target;
2145 l = s4ptr[1]; /* low */
2146 i = s4ptr[2]; /* high */
2149 copy_ptr = (void**) DMNEW(void*, i+1);
2150 base_ptr = (void*) copy_ptr;
2152 for (tptr = ip->target; i >= 0; --i, ++tptr, ++copy_ptr) {
2153 patch_handler(lc, ((basicblock *) *tptr), original_head, new_head);
2154 /* jumps to old header have to be redirected */
2155 if (((basicblock *) *tptr) == original_head)
2156 copy_ptr[0] = (void *) new_head->copied_to;
2157 /* jumps to handler internal nodes have to be redirected */
2158 else if (((basicblock *) *tptr)->lflags & HANDLER_PART)
2159 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2160 /* jumps to loop internal nodes have to be redirected */
2161 else if (((basicblock *) ip->target)->lflags & LOOP_PART)
2162 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2164 copy_ptr[0] = tptr[0];
2167 ip->target = base_ptr;
2171 case ICMD_LOOKUPSWITCH:
2173 s4 i, l, val, *s4ptr;
2176 void **copy_ptr, **base_ptr;
2178 tptr = (void **) ip->target;
2180 l = s4ptr[0]; /* default */
2181 i = s4ptr[1]; /* count */
2183 copy_ptr = (void**) DMNEW(void*, i+1);
2184 base_ptr = (void*) copy_ptr;
2186 for (tptr = ip->target; i >= 0; --i, ++tptr, ++copy_ptr) {
2188 patch_handler(lc, ((basicblock *) *tptr), original_head, new_head);
2189 /* jumps to old header have to be redirected */
2190 if (((basicblock *) *tptr) == original_head)
2191 copy_ptr[0] = (void *) new_head->copied_to;
2192 /* jumps to handler internal nodes have to be redirected */
2193 else if (((basicblock *) *tptr)->lflags & HANDLER_PART)
2194 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2195 /* jumps to loop internal nodes have to be redirected */
2196 else if (((basicblock *) ip->target)->lflags & LOOP_PART)
2197 copy_ptr[0] = (void *) ((basicblock *) tptr[0])->copied_to;
2199 copy_ptr[0] = tptr[0];
2202 ip->target = base_ptr;
2210 /* if fall through exits loop, goto is needed */
2211 if (!(bptr->next->lflags & HANDLER_PART)) {
2212 bptr->copied_to->iinstr[bptr->copied_to->icount].opc = ICMD_GOTO;
2213 bptr->copied_to->iinstr[bptr->copied_to->icount].dst = NULL;
2214 bptr->copied_to->iinstr[bptr->copied_to->icount].target = bptr->next;
2215 bptr->copied_to->icount++;
2220 /* This function copys the exception handler and redirects all jumps from the
2221 original head to the new head in the original exception handler. All
2222 redirection in the copied exception handler is done in patch_handler(...).
2224 void copy_handler(struct LoopContainer *lc, basicblock *bptr, basicblock *original_head, basicblock *new_head)
2229 int high, low, count, cnt;
2230 struct LoopElement *le;
2233 /* If this node has already been copied, return */
2234 if (bptr->lflags & HANDLER_PART)
2237 /* The exception handler exists, when control flow enters loop again */
2239 if (bptr->lflags & LOOP_PART)
2241 for (le = lc->nodes; le != NULL; le = le->next) {
2242 if (le->block == bptr) {
2243 printf("C_PANIC: should not happen\n");
2248 /* mark block as part of handler */
2249 bptr->lflags |= HANDLER_PART;
2252 new = DMNEW(basicblock, 1);
2253 memcpy(new, bptr, sizeof(basicblock));
2254 new->debug_nr = c_debug_nr++;
2256 c_last_block_copied = new;
2258 /* copy instructions and allow one more slot for possible GOTO */
2259 new->iinstr = DMNEW(instruction, bptr->icount + 1);
2260 memcpy(new->iinstr, bptr->iinstr, bptr->icount*sizeof(instruction));
2262 /* update original block */
2263 bptr->copied_to = new;
2265 /* append block to global list of basic blocks */
2266 last_block->next = new;
2271 /* find next block to copy, depending on last instruction of BB */
2272 if (bptr->icount == 0) {
2273 copy_handler(lc, bptr->next, original_head, new_head);
2277 ip = bptr->iinstr + (bptr->icount - 1);
2296 case ICMD_IF_LCMPEQ:
2297 case ICMD_IF_LCMPLT:
2298 case ICMD_IF_LCMPLE:
2299 case ICMD_IF_LCMPNE:
2300 case ICMD_IF_LCMPGT:
2301 case ICMD_IF_LCMPGE:
2311 case ICMD_IFNONNULL:
2313 case ICMD_IF_ICMPEQ:
2314 case ICMD_IF_ICMPNE:
2315 case ICMD_IF_ICMPLT:
2316 case ICMD_IF_ICMPGE:
2317 case ICMD_IF_ICMPGT:
2318 case ICMD_IF_ICMPLE:
2319 case ICMD_IF_ACMPEQ:
2320 case ICMD_IF_ACMPNE:
2321 copy_handler(lc, bptr->next, original_head, new_head);
2326 /* redirect jump from original_head to new_head */
2327 if ((basicblock *) ip->target == original_head)
2328 ip->target = (void *) new_head;
2330 copy_handler(lc, (basicblock *) (ip->target), original_head, new_head);
2334 case ICMD_TABLESWITCH:
2336 tptr = (void **) ip->target;
2338 /* default branch */
2339 if (((basicblock *) *tptr) == original_head)
2340 tptr[0] = (void *) new_head;
2342 copy_handler(lc, (basicblock *) *tptr, original_head, new_head);
2349 count = (high-low+1);
2351 while (--count >= 0) {
2353 /* redirect jump from original_head to new_head */
2354 if (((basicblock *) *tptr) == original_head)
2355 tptr[0] = (void *) new_head;
2356 copy_handler(lc, (basicblock *) *tptr, original_head, new_head);
2360 case ICMD_LOOKUPSWITCH:
2362 tptr = (void **) ip->target;
2364 /* default branch */
2365 if (((basicblock *) *tptr) == original_head)
2366 tptr[0] = (void *) new_head;
2368 copy_handler(lc, (basicblock *) *tptr, original_head, new_head);
2373 while (--count >= 0) {
2375 /* redirect jump from original_head to new_head */
2376 if (((basicblock *) *tptr) == original_head)
2377 tptr[0] = (void *) new_head;
2378 copy_handler(lc, (basicblock *) *tptr, original_head, new_head);
2383 c_last_target = bptr;
2384 copy_handler(lc, (basicblock *) (ip->target), original_head, new_head);
2388 copy_handler(lc, c_last_target->next, original_head, new_head);
2392 copy_handler(lc, bptr->next, original_head, new_head);
2399 /* If a loop is duplicated, all exceptions, that are contained in this loops' body
2400 have to be duplicated as well. The following function together with the
2401 two helper functions copy_handler and patch_handler perform this task.
2403 void update_internal_exceptions(struct LoopContainer *lc, basicblock *original_head, basicblock *new_head)
2406 struct LoopContainer *l;
2408 /* Bottom of tree reached -> return */
2412 /* Call update_internal for all nested (=child) loops */
2415 update_internal_exceptions(l, original_head, new_head);
2419 /* For all exceptions of this loop, do */
2420 ex = lc->exceptions;
2421 while (ex != NULL) {
2423 /* Copy the exception and patch the jumps */
2424 copy_handler(lc, ex->handler, original_head, new_head);
2425 patch_handler(lc, ex->handler, original_head, new_head);
2427 /* Insert a new exception into the global exception table */
2428 new = DMNEW(xtable, 1);
2429 memcpy(new, ex, sizeof(xtable));
2431 /* Increase number of exceptions */
2432 ++exceptiontablelength;
2437 /* Set new start and end point of this exception */
2438 new->start = ex->start->copied_to;
2439 new->end = ex->end->copied_to;
2441 /* Set handler pointer to copied exception handler */
2442 new->handler = ex->handler->copied_to;
2449 /* If a loop is duplicated, all exceptions that contain this loop have to be
2450 extended to the copied nodes as well. The following function checks for
2451 all exceptions of all parent loops, whether they contain the loop pointed to
2452 by lc. If so, the exceptions are extended to contain all newly created nodes.
2454 void update_external_exceptions(struct LoopContainer *lc, int loop_head)
2458 /* Top of tree reached -> return */
2462 ex = lc->exceptions;
2464 /* For all exceptions of this loop do */
2465 while (ex != NULL) {
2467 /* It is possible that the loop contains exceptions that do not protect */
2468 /* the loop just duplicated. It must be checked, if this is the case */
2469 if ((loop_head >= block_index[ex->startpc]) && (loop_head < block_index[ex->endpc])) {
2471 /* loop is really inside exception, so create new exception entry */
2472 /* in global exception list */
2473 new = DMNEW(xtable, 1);
2474 memcpy(new, ex, sizeof(xtable));
2477 /* Increase number of exceptions */
2478 ++exceptiontablelength;
2483 /* Set new start and end point of this exception */
2484 new->start = c_first_block_copied;
2485 new->end = c_last_block_copied;
2489 /* exception does not contain the duplicated loop -> do nothing */
2494 /* Call update_external for parent node */
2495 update_external_exceptions(lc->parent, loop_head);
2500 /* This function is needed to insert the static checks, stored in c_constraints
2501 into the intermediate code.
2503 void create_static_checks(struct LoopContainer *lc)
2505 int i, j, stackdepth, cnt;
2507 struct Constraint *tc1, *tc2;
2508 struct LoopElement *le;
2510 /* loop_head points to the newly inserted loop_head, original_start to */
2511 /* the old loop header */
2512 basicblock *bptr, *loop_head, *original_start, *temp;
2513 instruction *inst, *tiptr;
2515 /* tos and newstack are needed by the macros, that insert instructions into */
2516 /* the new loop head */
2517 stackptr newstack, tos, sptr;
2521 /* show_loop_statistics(); */
2524 loop_head = &block[c_current_head];
2525 c_first_block_copied = c_last_block_copied = NULL;
2527 /* the loop nodes are copied */
2531 bptr = DMNEW(basicblock, 1);
2532 memcpy(bptr, le->block, sizeof(basicblock));
2533 bptr->debug_nr = c_debug_nr++;
2535 /* determine beginning of copied loop to extend exception handler, that */
2536 /* protect this loop */
2537 if (c_first_block_copied == NULL)
2538 c_first_block_copied = bptr;
2540 /* copy instructions and add one more slot for possible GOTO */
2541 bptr->iinstr = DMNEW(instruction, bptr->icount + 1);
2543 memcpy(bptr->iinstr, le->block->iinstr, (bptr->icount+1)*sizeof(instruction));
2545 le->block->copied_to = bptr;
2547 /* add block to global list of BBs */
2548 last_block->next = bptr;
2552 node_into_parent_loops(lc->parent, bptr);
2556 c_last_block_copied = bptr;
2558 /* create an additional basicblock for dynamic checks */
2559 original_start = bptr = DMNEW(basicblock, 1);
2561 /* copy current loop header to new basic block */
2562 memcpy(bptr, loop_head, sizeof(basicblock));
2563 bptr->debug_nr = c_debug_nr++;
2565 /* insert the new basic block and move header before first loop node */
2569 /* if header is first node of loop, insert original header after it */
2570 if (temp == loop_head)
2571 loop_head->next = bptr;
2573 /* else, we have to find the predecessor of loop header */
2574 while (temp->next != loop_head)
2577 /* insert original header after newly created block */
2580 /* if predecessor is not loop part, insert a goto */
2581 if (!(temp->lflags & LOOP_PART)) {
2583 /* copy instructions and add an additional slot */
2584 tiptr = DMNEW(instruction, temp->icount + 1);
2585 memcpy(tiptr, temp->iinstr, sizeof(instruction)*temp->icount);
2587 temp->iinstr = tiptr;
2588 tiptr = temp->iinstr + temp->icount;
2590 /* add goto to loop header. If node is part of exception handler */
2591 /* jmp is automagically redirected during patch_handler and works */
2593 tiptr->opc = ICMD_GOTO;
2595 tiptr->target = (void*) loop_head;
2602 /* if first loop block is first BB of global list, insert loop_head at */
2603 /* beginning of global BB list */
2604 if (temp == le->block) {
2605 if (c_newstart == NULL) {
2606 c_needs_redirection = true;
2607 c_newstart = loop_head;
2608 loop_head->next = block;
2611 loop_head->next = c_newstart;
2612 c_newstart = loop_head;
2617 while (temp->next != le->block)
2620 loop_head->next = temp->next;
2621 temp->next = loop_head;
2623 /* to be on the safe side insert a jump from the previous instr */
2624 /* over thr new inserted node */
2626 /* special case - jump from node to loop_head: then remove */
2627 /* goto / happens rather often due to loop layout */
2628 tiptr = temp->iinstr + (temp->icount-1);
2630 if ((tiptr->opc == ICMD_GOTO) && (tiptr->target == loop_head)) {
2631 tiptr->opc = ICMD_NOP;
2636 tiptr = DMNEW(instruction, temp->icount + 1);
2637 memcpy(tiptr, temp->iinstr, sizeof(instruction)*temp->icount);
2639 temp->iinstr = tiptr;
2640 tiptr = temp->iinstr + temp->icount;
2642 tiptr->opc = ICMD_GOTO;
2644 tiptr->target = (void*) loop_head->next;
2651 /* adjust exceptions */
2653 while (ex != NULL) {
2655 /* if an exception covers whole loop and starts at first loop node, it */
2656 /* has to be extended to cover the new first node as well */
2657 if (ex->start == le->block) {
2659 if ((lc->loop_head >= block_index[ex->startpc]) && (lc->loop_head < block_index[ex->endpc]))
2660 ex->start = loop_head;
2663 /* an exception that ended at the old loop header now must contains the */
2664 /* new loop header as well */
2665 if (ex->end == loop_head)
2666 ex->end = original_start;
2672 /* insert new header node into nodelists of all enclosing loops */
2673 header_into_parent_loops(lc, loop_head, original_start, le->block);
2675 /* prepare instruction array to insert checks */
2676 inst = loop_head->iinstr = DMNEW(instruction, c_needed_instr + 2);
2677 loop_head->icount = c_needed_instr + 1;
2679 /* init instruction array */
2680 for (cnt=0; cnt<c_needed_instr + 1; ++cnt) {
2681 inst[0].opc = ICMD_NOP;
2685 loop_head->copied_to = NULL;
2688 loop_head->instack = copy_stack_from(bptr->instack);
2689 loop_head->outstack = copy_stack_from(bptr->instack);
2691 tos = loop_head->instack;
2692 stackdepth = loop_head->indepth;
2694 /* step through all inserted checks and create instructions for them */
2695 for (i=0; i<maxlocals+1; ++i)
2697 tc1 = c_constraints[i];
2703 /* check a variable against a constant */
2705 case TEST_UNMOD_ZERO:
2708 printf("insert ZERO-test\n");
2712 /* optimize if tc1->varRef >= tc1->constant */
2713 LOAD_VAR(tc1->varRef);
2714 LOAD_CONST(tc1->constant);
2718 /* check a variable against an array length */
2720 case TEST_UNMOD_ALENGTH:
2723 /* tc1->varRef + tc1->constant < lengthOf(tc1->arrayRef) */
2725 printf("insert ALENGTH-test\n");
2729 LOAD_VAR(tc1->varRef);
2730 LOAD_CONST(tc1->constant);
2732 LOAD_ARRAYLENGTH(tc1->arrayRef);
2736 /* test right side of comparison against constant */
2740 printf("insert RS-ZERO-test\n");
2744 /* optimize if right-side >= tc1->constant */
2746 LOAD_CONST(tc1->constant);
2750 /* test right side of comparison against array length */
2751 case TEST_RS_ALENGTH:
2754 printf("insert RS-ALENGTH-test\n");
2757 /* optimize if right-side < lengthOf(arrayRef) */
2759 LOAD_ARRAYLENGTH(tc1->arrayRef);
2763 /* test unmodified variable against arraylength */
2764 case TEST_CONST_ALENGTH:
2767 printf("insert CONST ALENGTH-test\n");
2771 /* optimize if tc1->constant < lengthOf(tc1->arrayRef) */
2772 LOAD_CONST(tc1->constant);
2773 LOAD_ARRAYLENGTH(tc1->arrayRef);
2780 c_constraints[i] = NULL;
2783 /* if all tests succeed, jump to optimized loop header */
2784 if (loop_head->next != original_start) {
2785 inst->opc = ICMD_GOTO;
2787 inst->target = original_start;
2790 /* redirect jumps from original loop head to newly inserted one */
2791 patch_jumps(original_start, loop_head, lc);
2793 /* if exceptions have to be correct due to loop duplication these two */
2794 /* functions perform this task. */
2795 update_internal_exceptions(lc, loop_head, original_start);
2796 update_external_exceptions(lc->parent, lc->loop_head);
2801 /* This function performs an update between two arrays of struct Changes (that
2802 reflect variable changes). The merge is performed unrstricted in the way, that
2803 all variable changes in c1 took place in a nested loop and therefore are
2804 considered to be without limit. Beside that, the merge is a simple union of the
2805 changes recorded in both arrays. A variable, which limits are undefinied, is
2806 represented by its lower bound being higher than the upper bound. The result
2807 of the union is stored in c1.
2809 struct Changes ** constraints_unrestricted_merge(struct Changes **c1, struct Changes **c2)
2813 if ((c1 == NULL) || (c2 == NULL))
2814 printf("C_ERROR: debugging error 0x03\n");
2817 for (i=0; i<maxlocals; ++i) {
2818 if (c1[i] == NULL) {
2819 if (c2[i] != NULL) { /* a change in c2 is updated in c1 */
2822 c1[i]->lower_bound = c1[i]->upper_bound+1;
2826 if (c1[i]->lower_bound > c1[i]->upper_bound)
2827 continue; /* variable's bounds already undefined */
2829 if (c2[i] == NULL) { /* variable changed in c1 -> now undef. */
2831 c1[i]->lower_bound = c1[i]->upper_bound+1;
2834 if ((c1[i]->lower_bound == c2[i]->lower_bound) &&
2835 (c1[i]->upper_bound == c2[i]->upper_bound))
2836 continue; /* variable's bounds remain the same */
2839 c1[i]->lower_bound = c1[i]->upper_bound+1;
2840 } /* variable changed in c1 -> now undef. */
2851 /* This function performs an update between two arrays of struct Changes (that
2852 reflect variable changes). The merge is a simple union of the bounds
2853 changes recorded in both arrays. A variable, which limits are undefinied, is
2854 represented by its lower bound being higher than the upper bound. The result
2855 of the union is stored in c1.
2857 struct Changes ** constraints_merge(struct Changes **c1, struct Changes **c2)
2861 if ((c1 == NULL) || (c2 == NULL))
2862 printf("C_ERROR: debugging error 0x04\n");
2866 for (i=0; i<maxlocals; ++i) {
2867 if (c1[i] == NULL) {
2868 if (c2[i] != NULL) { /* update changes in c2 in c1 */
2869 if ((c1[i] = (struct Changes *) malloc (sizeof(struct Changes))) == NULL)
2872 c1[i]->lower_bound = c2[i]->lower_bound;
2873 c1[i]->upper_bound = c2[i]->upper_bound;
2878 if (c2[i] != NULL) {
2880 if (c1[i]->lower_bound > c1[i]->upper_bound)
2881 continue; /* var in c1 is unrestricted */
2883 if (c1[i]->lower_bound > c2[i]->lower_bound) {
2884 c1[i]->lower_bound = c2[i]->lower_bound;
2885 changed = 1; /* write new lower bound */
2887 if (c1[i]->upper_bound < c2[i]->upper_bound) {
2888 c1[i]->upper_bound = c2[i]->upper_bound;
2889 changed = 1; /* write new higher bound */
2902 /* This function simply copies an array of changes
2904 struct Changes** constraints_clone(struct Changes **c)
2909 if ((t = (struct Changes **) malloc(maxlocals * sizeof(struct Changes *))) == NULL)
2912 for (i=0; i<maxlocals; ++i) { /* for all array elements (vars) do */
2916 if ((t[i] = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
2918 t[i]->lower_bound = c[i]->lower_bound;
2919 t[i]->upper_bound = c[i]->upper_bound;
2926 /* This function is used to reset the changes of a variable to the time, it was
2927 pushed onto the stack. If a variable has been modified between an instruction
2928 and a previous push onto the stack, its value in the changes array does not
2929 correctly reflect its bounds the time, it was pushed onto the stack. This
2930 function corrects the situation.
2932 struct Changes* backtrack_var(int node, int from, int to, int varRef, struct Changes *changes)
2934 struct Changes *tmp;
2939 if (changes == NULL) /* if there are no changes, immediately return */
2941 else { /* init a Changes structure with current values */
2942 if ((tmp = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
2945 tmp->upper_bound = changes->upper_bound;
2946 tmp->lower_bound = changes->lower_bound;
2949 if (tmp->upper_bound < tmp->lower_bound)
2950 return tmp; /* if it is unrestricted no backtracking can happen */
2953 ip = bp.iinstr + to;
2955 for (; from < to; --to, --ip) { /* scan instructions backwards */
2957 case ICMD_IINC: /* a var has been modified */
2958 if (varRef != ip->op1) /* not the one, we are interested in */
2960 tmp->upper_bound -= ip->val.i; /* take back modifications */
2961 tmp->lower_bound -= ip->val.i;
2964 case ICMD_ISTORE: /* a var has been modified */
2965 if (varRef != ip->op1) /* not the one, we are interested in */
2968 /* it is our variable, so trace its origin */
2969 t = tracing(&block[node],to, 0);
2973 if ((t->var = ip->op1) && (t->neg > 0)) {
2974 /* it was the same var -> take back modifications */
2975 tmp->upper_bound -= t->constant;
2976 tmp->lower_bound -= t->constant;
2979 tmp->lower_bound = tmp->upper_bound+1; /* unknown */
2982 /* cannot restore it -> invalidate t */
2987 tmp->lower_bound = tmp->upper_bound+1;
2997 /* This function performs the main task of bound check removal. It removes
2998 all bound-checks in node. change is a pointer to an array of struct Changes
2999 that reflect for all local variables, how their values have changed from
3000 the start of the loop. The special flag is needed to deal with the header
3003 void remove_boundchecks(int node, int from, struct Changes **change, int special)
3007 int i, j, count, ignore, degrade_checks, opt_level;
3008 struct depthElement *d;
3009 struct Changes **t1, **t2, **tmp, *t;
3010 struct Trace *t_array, *t_index;
3012 /* printf("remove_bc called: %d - %d - %d\n", node, from, special); */
3014 /* a flag, that is set, when previous optimzations have to be taken back */
3017 if (c_current_loop[node] > 0) { /* this node is part of the loop */
3018 if (c_current_loop[node] > 1) { /* it is not the header node */
3020 /* get variable changes, already recorded for this node */
3021 t1 = c_dTable[node]->changes;
3023 if (t1 != NULL) { /* it is not the first visit */
3024 if ((c_nestedLoops[node] != c_current_head) && (c_nestedLoops[node] == c_nestedLoops[from])) {
3025 /* we are looping in a nested loop, so made optimizations */
3026 /* need to be reconsidered */
3028 if (constraints_unrestricted_merge(t1, change) == NULL)
3029 return; /* no changes since previous visit */
3030 /* if there have been changes, they are updated by */
3031 /* constraints_unrestricted_merge in t1 */
3034 if (constraints_merge(t1, change) == NULL)
3035 return; /* no changes since previous visit */
3036 /* if there have been changes, they are updated by */
3037 /* constraints_merge in t1 */
3040 else { /* first visit */
3041 /* printf("first visit - constraints cloned\n"); */
3042 c_dTable[node]->changes = constraints_clone(change);
3045 /* tmp now holds a copy of the updated variable changes */
3046 tmp = constraints_clone(c_dTable[node]->changes);
3048 else if (special) { /* header and need special traetment */
3049 /* printf("special treatment called\n"); */
3050 /* tmp now holds a copy of the current new variable changes */
3051 tmp = constraints_clone(change);
3056 bp = block[node]; /* scan all instructions */
3061 for (i=0; i<count; ++i, ++ip) {
3063 case ICMD_IASTORE: /* found an array store */
3072 t_index = tracing(&bp, i-1, 1); /* get index */
3073 t_array = tracing(&bp, i-1, 2); /* get array refernce */
3077 case ICMD_IALOAD: /* found an array load */
3086 t_index = tracing(&bp, i-1, 0); /* get index */
3087 t_array = tracing(&bp, i-1, 1); /* get array refernce */
3091 /* printf("Array access with params:\n");
3093 show_trace(t_array);
3095 show_trace(t_index);
3099 if (ip->op1 == OPT_UNCHECKED) { /* found new access */
3100 c_stat_array_accesses++;
3106 /* can only optimize known arrays that do not change */
3107 if ((t_array->type != TRACE_AVAR) || (c_var_modified[t_array->var]))
3110 switch (t_index->type) { /* now we look at the index */
3111 case TRACE_ICONST: /* it is a constant value or an */
3112 case TRACE_ALENGTH: /* array length */
3114 switch (ip->op1) { /* take back old optimzation */
3131 if (degrade_checks) /* replace existing optimization */
3132 ip->op1 = insert_static(t_array->var, t_index, NULL, special);
3134 /* Check current optimization and try to improve it by */
3135 /* inserting new checks */
3138 ip->op1 = insert_static(t_array->var, t_index, NULL, special);
3141 ip->op1 = insert_static(t_array->var, t_index, NULL, special);
3144 opt_level = insert_static(t_array->var, t_index, NULL, special);
3145 if ((opt_level == OPT_FULL) || (opt_level == OPT_LOWER))
3149 opt_level = insert_static(t_array->var, t_index, NULL, special);
3150 if ((opt_level == OPT_FULL) || (opt_level == OPT_UPPER))
3162 case TRACE_IVAR: /* it's a variable */
3164 /* if the variable is changed between its usage as an index */
3165 /* of the array access and its push onto the stack, we have */
3166 /* to set the changes back to the time, it is pushed onto */
3167 /* the stack as an index variable. */
3168 t = backtrack_var(node, t_index->nr, i-1, t_index->var, tmp[t_index->var]);
3170 switch (ip->op1) { /* take back old optimzation */
3188 ip->op1 = insert_static(t_array->var, t_index, t, special);
3190 /* Check current optimization and try to improve it by */
3191 /* insert new check. t reflects var changes for index */
3194 ip->op1 = insert_static(t_array->var, t_index, t, special);
3197 ip->op1 = insert_static(t_array->var, t_index, t, special);
3200 opt_level = insert_static(t_array->var, t_index, t, special);
3201 if ((opt_level == OPT_FULL) || (opt_level == OPT_LOWER))
3205 opt_level = insert_static(t_array->var, t_index, t, special);
3206 if ((opt_level == OPT_FULL) || (opt_level == OPT_UPPER))
3224 case ICMD_ISTORE: /* an integer value is stored */
3225 t_index = tracing(&bp, i-1, 0); /* trace back its origin */
3227 /* the struct Changes for this variable needs to be updated */
3229 if (t == NULL) { /* if it's the first one, create new entry */
3230 if ((t = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
3232 t->upper_bound = t->lower_bound = 0;
3236 switch (t_index->type) { /* check origin of store */
3238 case TRACE_ICONST: /* constant -> set bounds to const value */
3239 t->upper_bound = t->lower_bound = t_index->constant;
3242 case TRACE_IVAR: /* if it's the same variable, update consts */
3243 if ((t_index->var = ip->op1) && (t_index->neg > 0)) {
3244 t->upper_bound += t_index->constant;
3245 t->lower_bound += t_index->constant;
3248 t->lower_bound = t->upper_bound+1;
3251 case TRACE_ALENGTH: /* else -> unknown */
3254 t->lower_bound = t->upper_bound+1;
3262 /* the struct Changes for this variable needs to be updated */
3263 if ((t = tmp[ip->op1]) == NULL) { /* first one -> create new */
3264 if ((t = (struct Changes *) malloc(sizeof(struct Changes))) == NULL)
3266 t->upper_bound = t->lower_bound = ip->val.i;
3269 else { /* update changes, made by iinc */
3270 t->upper_bound += ip->val.i;
3271 t->lower_bound += ip->val.i;
3277 if (!special) { /* we are not interested in only the header */
3279 while (d != NULL) { /* check all sucessors of current node */
3280 remove_boundchecks(d->value, node, tmp, special);
3287 /* This function calls the bound-check removal function for the header node
3288 with a special flag. It is important to notice, that no dynamic
3289 constraint hold in the header node (because the comparison is done at
3292 void remove_header_boundchecks(int node, struct Changes **changes)
3294 remove_boundchecks(node, -1, changes, BOUNDCHECK_SPECIAL);
3297 /* Marks all basicblocks that are part of the loop
3299 void mark_loop_nodes(struct LoopContainer *lc)
3301 struct LoopElement *le = lc->nodes;
3303 while (le != NULL) {
3304 le->block->lflags |= LOOP_PART;
3309 /* Clears mark for all basicblocks that are part of the loop
3311 void unmark_loop_nodes(struct LoopContainer *lc)
3313 struct LoopElement *le = lc->nodes;
3315 while (le != NULL) {
3316 le->block->lflags = 0;
3322 /* This function performs the analysis of code in detected loops and trys to
3323 identify array accesses suitable for optimization (bound check removal). The
3324 intermediate code is then modified to reflect these optimizations.
3326 void optimize_single_loop(struct LoopContainer *lc)
3328 struct LoopElement *le;
3329 struct depthElement *d;
3331 struct Changes **changes;
3335 if ((changes = (struct Changes **) malloc(maxlocals * sizeof(struct Changes *))) == NULL)
3338 head = c_current_head = lc->loop_head;
3339 c_needed_instr = c_rs_needed_instr = 0;
3341 /* init array for null ptr checks */
3342 for (i=0; i<maxlocals; ++i)
3343 c_null_check[i] = 0;
3346 /* don't optimize root node (it is the main procedure, not a loop) */
3350 /* setup variables with initial values */
3352 for (i=0; i < block_count; ++i) {
3354 c_current_loop[i] = -1;
3355 if ((d = c_dTable[i]) != NULL)
3359 for (i=0; i < maxlocals; ++i) {
3360 c_var_modified[i] = 0;
3361 if (changes[i] != NULL) {
3366 for (i=0; i < (maxlocals+1); ++i) {
3367 if (c_constraints[i] != NULL) {
3368 c_constraints[i] = NULL;
3373 while (le != NULL) {
3377 c_current_loop[node] = 1; /* the header node gets 1 */
3378 else if (c_nestedLoops[node] == head)
3379 c_current_loop[node] = 2; /* top level nodes get 2 */
3381 c_current_loop[node] = 3; /* nodes, part of nested loop get 3 */
3383 c_toVisit[node] = 1;
3387 /* After setup work has been performed, start to analyse */
3389 printf("****** Starting analysis (%d)******\n", head);
3393 if (analyze_for_array_access(head) > 0) {/* loop contains array access */
3396 printf("analyze for array access finished and found\n");
3399 while (lv != NULL) {
3401 printf("Var --> %d\n", lv->value);
3406 /* for performance reasons the list of all interesting loop vars is */
3407 /* scaned and for all modified vars a flag in c_var_modified is set */
3411 printf("global list scanned\n");
3415 /* if the loop header contains or-conditions or an index variable */
3416 /* is modified in the catch-block within the loop, a conservative */
3417 /* approach is taken and optimizations are cancelled */
3418 if (analyze_or_exceptions(head, lc) > 0) {
3421 printf("Analyzed for or/exception - no problems \n");
3425 init_constraints(head); /* analyze dynamic bounds in header */
3431 if (c_rightside == NULL)
3434 /* single pass bound check removal - for all successors, do */
3435 remove_header_boundchecks(head, changes);
3439 remove_boundchecks(d->value, -1, changes, BOUNDCHECK_REGULAR);
3444 printf("Array-bound checks finished\n");
3448 mark_loop_nodes(lc);
3451 printf("START: create static checks\n");
3455 create_static_checks(lc); /* create checks */
3458 printf("END: create static checks\n");
3461 unmark_loop_nodes(lc);
3465 printf("No array accesses found\n"); */
3468 c_stat_num_loops++; /* increase number of loops */
3470 c_stat_sum_accesses += c_stat_array_accesses;
3471 c_stat_sum_full += c_stat_full_opt;
3472 c_stat_sum_no += c_stat_no_opt;
3473 c_stat_sum_lower += c_stat_lower_opt;
3474 c_stat_sum_upper += c_stat_upper_opt;
3475 c_stat_sum_or += c_stat_or;
3476 c_stat_sum_exception += c_stat_exception;
3478 c_stat_array_accesses = 0;
3479 c_stat_full_opt = 0;
3481 c_stat_lower_opt = 0;
3482 c_stat_upper_opt = 0;
3483 c_stat_or = c_stat_exception = 0;
3488 /* This function preforms necessary setup work, before the recursive function
3489 optimize_single loop can be called.
3491 void optimize_loops()
3493 struct LoopContainer *lc = c_allLoops;
3495 /* first, merge loops with same header node - all loops with the same */
3496 /* header node are optimizied in one pass, because they all depend on the */
3497 /* same dynamic loop condition */
3500 printf("start analyze_double_headers\n");
3504 analyze_double_headers();
3506 /* create array with loop nesting levels - nested loops cause problems, */
3507 /* especially, when they modify index variables used in surrounding loops */
3508 /* store results in array c_nestedLoops and c_hierarchie */
3511 printf("double done\n");
3518 printf("analyze nested done\n");
3522 /* create array with entries for current loop */
3523 c_current_loop = DMNEW(int, block_count);
3524 c_toVisit = DMNEW(int, block_count);
3525 c_var_modified = DMNEW(int, maxlocals);
3526 c_null_check = DMNEW(int, maxlocals);
3528 if ((c_constraints = (struct Constraint **) malloc((maxlocals+1) * sizeof(struct Constraint *))) == NULL)
3532 c_stat_num_loops = 0; /* set statistic vars to zero */
3533 c_stat_array_accesses = c_stat_sum_accesses = 0;
3534 c_stat_full_opt = c_stat_sum_full = 0;
3535 c_stat_no_opt = c_stat_sum_no = 0;
3536 c_stat_lower_opt = c_stat_sum_lower = 0;
3537 c_stat_upper_opt = c_stat_sum_upper = 0;
3538 c_stat_or = c_stat_sum_or = 0;
3539 c_stat_exception = c_stat_sum_exception = 0;
3542 /* init vars needed by all loops */
3543 c_needs_redirection = false;
3545 c_old_xtablelength = exceptiontablelength;
3547 /* loops have been topologically sorted */
3549 while (lc != NULL) {
3550 optimize_single_loop(lc);
3553 printf(" *** Optimized loop *** \n");
3560 printf("---*** All loops finished ***---\n");
3564 /* if global BB list start is modified, set block to new start */
3565 if (c_needs_redirection == true)
3570 * These are local overrides for various environment variables in Emacs.
3571 * Please do not remove this and leave it at the end of the file, where
3572 * Emacs will automagically detect them.
3573 * ---------------------------------------------------------------------
3576 * indent-tabs-mode: t