CACAO
cfg.cpp
Go to the documentation of this file.
1 /* src/vm/jit/cfg.c - build a control-flow graph
2 
3  Copyright (C) 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates,
4  R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
5  C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
6  J. Wenninger, Institut f. Computersprachen - TU Wien
7 
8  This file is part of CACAO.
9 
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.
14 
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.
19 
20  You should have received a copy of the GNU General Public License
21  along with this program; if not, write to the Free Software
22  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23  02110-1301, USA.
24 
25 */
26 
27 #include "vm/jit/cfg.hpp"
28 #include <assert.h> // for assert
29 #include "config.h"
30 #include "mm/dumpmemory.hpp" // for DMNEW
31 #include "vm/jit/ir/icmd.hpp" // for ::ICMD_NOP, etc
32 #include "vm/jit/ir/instruction.hpp" // for instruction, etc
33 #include "vm/jit/jit.hpp" // for basicblock, jitdata, etc
34 #include "vm/jit/stack.hpp"
35 
36 
37 /* cfg_allocate_predecessors ***************************************************
38 
39  Allocates the predecessor array, if there is none, and resets the
40  predecessor count.
41 
42 *******************************************************************************/
43 
45 {
46  if (bptr->predecessors == NULL) {
48 
49  bptr->predecessorcount = 0;
50  }
51 }
52 
53 
54 /* cfg_allocate_successors *****************************************************
55 
56  Allocates the succecessor array, if there is none, and resets the
57  predecessor count.
58 
59 *******************************************************************************/
60 
62 {
63  if (bptr->successors == NULL) {
64  bptr->successors = DMNEW(basicblock*, bptr->successorcount);
65 
66  bptr->successorcount = 0;
67  }
68 }
69 
70 
71 /* cfg_insert_predecessor ******************************************************
72 
73  Inserts a predecessor into the array, but checks for duplicate
74  entries. This is used for TABLESWITCH and LOOKUPSWITCH.
75 
76 *******************************************************************************/
77 
78 static void cfg_insert_predecessors(basicblock *bptr, basicblock *pbptr)
79 {
80  basicblock **tbptr;
81  int i;
82 
83  tbptr = bptr->predecessors;
84 
85  /* check if the predecessors is already stored in the array */
86 
87  for (i = 0; i < bptr->predecessorcount; i++, tbptr++)
88  if (*tbptr == pbptr)
89  return;
90 
91  /* not found, insert it */
92 
93  bptr->predecessors[bptr->predecessorcount] = pbptr;
94  bptr->predecessorcount++;
95 }
96 
97 static void cfg_insert_successors(basicblock *bptr, basicblock *pbptr)
98 {
99  basicblock **tbptr;
100  int i;
101 
102  tbptr = bptr->successors;
103 
104  /* check if the successor is already stored in the array */
105 
106  for (i = 0; i < bptr->successorcount; i++, tbptr++)
107  if (*tbptr == pbptr)
108  return;
109 
110  /* not found, insert it */
111 
112  bptr->successors[bptr->successorcount] = pbptr;
113  bptr->successorcount++;
114 }
115 
116 
117 /* cfg_build *******************************************************************
118 
119  Build a control-flow graph in finding all predecessors and
120  successors for the basic blocks.
121 
122 *******************************************************************************/
123 
125 {
126  basicblock *bptr;
127  basicblock *tbptr;
128  basicblock *ntbptr;
129  instruction *iptr;
130  branch_target_t *table;
131  lookup_target_t *lookup;
132  int i;
133  bool has_fallthrough;
134 
135  /* process all basic blocks to find the predecessor/successor counts */
136 
137  bptr = jd->basicblocks;
138 
139  for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) {
140 
141  if (bptr->type == basicblock::TYPE_EXH) {
142  /* predecessorcount for exception handlers is initialized to -1,
143  so we need to fix it to 0. */
144  bptr->predecessorcount += 1;
145  }
146 
147  if ((bptr->icount == 0) || (bptr->state == basicblock::UNDEF))
148  continue;
149 
150  iptr = bptr->iinstr + bptr->icount - 1;
151 
152  /* skip NOPs at the end of the block */
153 
154  while (iptr->opc == ICMD_NOP) {
155  if (iptr == bptr->iinstr)
156  break;
157  iptr--;
158  }
159 
160  if (iptr->opc == ICMD_GOTO) {
161 
162  /*
163  This is needed for the following special case caused by
164  stack_reach_next_block:
165  I.e. there might be instructions causing control flow before
166  a GOTO:
167 
168  ....
169  129: 192: IFEQ Ti102 0 (0x00000000) --> L052
170  131: 193: NOP
171  0: 0: GOTO --> L060
172  */
173 
174  bptr->successorcount++;
175 
176  tbptr = iptr->dst.block;
177  tbptr->predecessorcount++;
178 
179  if (iptr == bptr->iinstr) {
180  continue;
181  }
182 
183  iptr--;
184 
185  while (iptr->opc == ICMD_NOP) {
186  if (iptr == bptr->iinstr) {
187  break;
188  }
189  iptr--;
190  }
191 
192  has_fallthrough = false;
193  } else {
194  has_fallthrough = true;
195  }
196 
197  switch (icmd_table[iptr->opc].controlflow) {
198 
199  case CF_END:
200  break;
201 
202  case CF_IF:
203 
204  bptr->successorcount += 2;
205 
206  tbptr = iptr->dst.block;
207  tbptr->predecessorcount++;
208 
209  if (has_fallthrough) {
210  ntbptr = bptr->next;
211  ntbptr->predecessorcount++;
212  }
213  break;
214 
215  case CF_JSR:
216  bptr->successorcount++;
217 
218  tbptr = iptr->sx.s23.s3.jsrtarget.block;
219  tbptr->predecessorcount++;
220  break;
221 
222  case CF_GOTO:
223  case CF_RET:
224  bptr->successorcount++;
225 
226  tbptr = iptr->dst.block;
227  tbptr->predecessorcount++;
228  break;
229 
230  case CF_TABLE:
231  table = iptr->dst.table;
232 
233  bptr->successorcount++;
234 
235  tbptr = table->block;
236  tbptr->predecessorcount++;
237  table++;
238 
239  i = iptr->sx.s23.s3.tablehigh - iptr->sx.s23.s2.tablelow + 1;
240 
241  while (--i >= 0) {
242  bptr->successorcount++;
243 
244  tbptr = table->block;
245  tbptr->predecessorcount++;
246  table++;
247  }
248  break;
249 
250  case CF_LOOKUP:
251  lookup = iptr->dst.lookup;
252 
253  bptr->successorcount++;
254 
255  tbptr = iptr->sx.s23.s3.lookupdefault.block;
256  tbptr->predecessorcount++;
257 
258  i = iptr->sx.s23.s2.lookupcount;
259 
260  while (--i >= 0) {
261  bptr->successorcount++;
262 
263  tbptr = lookup->target.block;
264  tbptr->predecessorcount++;
265  lookup++;
266  }
267  break;
268 
269  default:
270  if (has_fallthrough) {
271  bptr->successorcount++;
272 
273  tbptr = bptr->next;
274 
275  /* An exception handler has no predecessors. */
276 
277  if (tbptr->type != basicblock::TYPE_EXH)
278  tbptr->predecessorcount++;
279  }
280  break;
281  }
282  }
283 
284  /* Second iteration to allocate the arrays and insert the basic
285  block pointers. */
286 
287  bptr = jd->basicblocks;
288 
289  for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) {
290  if ((bptr->icount == 0) || (bptr->state == basicblock::UNDEF))
291  continue;
292 
293  iptr = bptr->iinstr + bptr->icount - 1;
294 
295  /* skip NOPs at the end of the block */
296 
297  while (iptr->opc == ICMD_NOP) {
298  if (iptr == bptr->iinstr)
299  break;
300  iptr--;
301  }
302 
303  if (iptr->opc == ICMD_GOTO) {
304  tbptr = iptr->dst.block;
305 
307 
308  cfg_insert_successors(bptr, tbptr);
309 
311 
312  cfg_insert_predecessors(tbptr, bptr);
313 
314  if (iptr == bptr->iinstr) {
315  continue;
316  }
317 
318  iptr--;
319 
320  while (iptr->opc == ICMD_NOP) {
321  if (iptr == bptr->iinstr) {
322  break;
323  }
324  iptr--;
325  }
326 
327  has_fallthrough = false;
328 
329  } else {
330  has_fallthrough = true;
331  }
332 
333  switch (icmd_table[iptr->opc].controlflow) {
334 
335  case CF_END:
336  break;
337 
338  case CF_IF:
339 
340  tbptr = iptr->dst.block;
341  ntbptr = bptr->next;
342 
344 
345  cfg_insert_successors(bptr, tbptr);
346  if (has_fallthrough) {
347  cfg_insert_successors(bptr, ntbptr);
348  }
349 
351  if (has_fallthrough) {
353  }
354 
355  cfg_insert_predecessors(tbptr, bptr);
356  if (has_fallthrough) {
357  cfg_insert_predecessors(ntbptr, bptr);
358  }
359  break;
360 
361  case CF_JSR:
362  tbptr = iptr->sx.s23.s3.jsrtarget.block;
363  goto goto_tail;
364 
365  case CF_GOTO:
366  case CF_RET:
367 
368  tbptr = iptr->dst.block;
369 goto_tail:
371 
372  cfg_insert_successors(bptr, tbptr);
373 
375 
376  cfg_insert_predecessors(tbptr, bptr);
377  break;
378 
379  case CF_TABLE:
380  table = iptr->dst.table;
381 
382  tbptr = table->block;
383  table++;
384 
386 
387  cfg_insert_successors(bptr, tbptr);
388 
390 
391  cfg_insert_predecessors(tbptr, bptr);
392 
393  i = iptr->sx.s23.s3.tablehigh - iptr->sx.s23.s2.tablelow + 1;
394 
395  while (--i >= 0) {
396  tbptr = table->block;
397  table++;
398 
399  cfg_insert_successors(bptr, tbptr);
400 
402  cfg_insert_predecessors(tbptr, bptr);
403  }
404  break;
405 
406  case CF_LOOKUP:
407  lookup = iptr->dst.lookup;
408 
409  tbptr = iptr->sx.s23.s3.lookupdefault.block;
410 
412 
413  cfg_insert_successors(bptr, tbptr);
414 
416 
417  cfg_insert_predecessors(tbptr, bptr);
418 
419  i = iptr->sx.s23.s2.lookupcount;
420 
421  while (--i >= 0) {
422  tbptr = lookup->target.block;
423  lookup++;
424 
425  cfg_insert_successors(bptr, tbptr);
426 
428  cfg_insert_predecessors(tbptr, bptr);
429  }
430  break;
431 
432  default:
433  if (has_fallthrough) {
434  tbptr = bptr->next;
435 
437 
438  bptr->successors[0] = tbptr;
439  bptr->successorcount++;
440 
441  /* An exception handler has no predecessors. */
442 
443  if (tbptr->type != basicblock::TYPE_EXH) {
445 
446  tbptr->predecessors[tbptr->predecessorcount] = bptr;
447  tbptr->predecessorcount++;
448  }
449  }
450  break;
451  }
452  }
453 
454  /* everything's ok */
455 
456  return true;
457 }
458 
459 /* cfg_add_root ****************************************************************
460 
461  Adds an empty root basicblock.
462  The numbers of all other basicblocks are set off by one.
463  Needed for some analyses that require the root basicblock to have no
464  predecessors and to perform special initializations.
465 
466 *******************************************************************************/
467 
469  basicblock *root, *zero, *it;
470 
471  zero = jd->basicblocks;
472 
473  root = DNEW(basicblock);
474  MZERO(root, basicblock, 1);
475 
476  root->successorcount = 1;
477  root->successors = DMNEW(basicblock *, 1);
478  root->successors[0] = zero;
479  root->next = zero;
480  root->nr = 0;
481  root->type = basicblock::TYPE_STD;
482  root->method = jd->m;
483 
484  if (zero->predecessorcount == 0) {
485  zero->predecessors = DNEW(basicblock *);
486  } else {
488  }
489  zero->predecessors[zero->predecessorcount] = root;
490  zero->predecessorcount += 1;
491 
492  jd->basicblocks = root;
493  jd->basicblockcount += 1;
494 
495  for (it = zero; it; it = it->next) {
496  it->nr += 1;
497  }
498 }
499 
501  basicblock *root, *zero, *it;
502 
503  root = jd->basicblocks;
504  zero = root->next;
505 
506  zero->predecessorcount -= 1;
507 
508  jd->basicblocks = zero;
509 
510  for (it = zero; it; it = it->next) {
511  it->nr -= 1;
512  }
513 }
514 
516 {
517 
518  for (basicblock *b = jd->basicblocks; b != NULL; b = b->next)
519  {
520  b->predecessorcount = (b->type == basicblock::TYPE_EXH) ? -1 : 0;
521  b->successorcount = 0;
522  b->predecessors = NULL;
523  b->successors = NULL;
524  }
525 }
526 
527 #if defined(ENABLE_SSA)
528 
529 static void cfg_eliminate_edges_to_unreachable(jitdata *jd);
530 
531 /* cfg_add_exceptional_edges ***************************************************
532 
533  Edges from basicblocks to their exception handlers and from exception
534  handlers to the blocks they handle exceptions for are added. Further
535  the number of potentially throwing instructions in the basicblocks are
536  counted.
537 
538  We don't consider nor do we determine the types of exceptions thrown. Edges
539  are added from every block to every potential handler.
540 
541 *******************************************************************************/
542 
544  basicblock *bptr;
545  instruction *iptr;
546  exception_entry *ee;
547  bool unreachable_exh = false;
548 
549  /* Count the number of exceptional exits for every block.
550  * Every PEI is an exceptional out.
551  */
552 
553  FOR_EACH_BASICBLOCK(jd, bptr) {
554 
555  /* Prepare for reachability calculation. */
556  bptr->vp = NULL;
557 
558  if (bptr->state == basicblock::UNDEF) {
559  continue;
560  }
561 
562  FOR_EACH_INSTRUCTION(bptr, iptr) {
563  if (icmd_table[iptr->opc].flags & ICMDTABLE_PEI) {
564  bptr->exouts += 1;
565  }
566  }
567  }
568 
569  /* Count the number of exception handlers for every block. */
570 
571  for (ee = jd->exceptiontable; ee; ee = ee->down) {
572  for (bptr = ee->start; bptr != ee->end; bptr = bptr->next) {
573  /* Linking a block with a handler, even if there are no exceptional exits
574  breaks stuff in other passes. */
575  if (bptr->exouts > 0) {
576  bptr->exhandlercount += 1;
577  ee->handler->expredecessorcount += 1;
578  }
579  }
580  }
581 
582  /* Allocate and fill exception handler arrays. */
583 
584  for (ee = jd->exceptiontable; ee; ee = ee->down) {
585 
586  if (ee->handler->expredecessorcount == 0) {
587  /* An exception handler that is unreachable.
588  This is inconsistent with the semantics of the CFG,
589  we need to recalculate reachability. */
590  unreachable_exh = true;
591  }
592 
593  for (bptr = ee->start; bptr != ee->end; bptr = bptr->next) {
594  if (bptr->exouts > 0) {
595 
596  if (bptr->exhandlers == NULL) {
597  bptr->exhandlers = DMNEW(basicblock *, bptr->exhandlercount);
598  /* Move pointer past the end of the array,
599  * It will be filled in the reverse order.
600  */
601  bptr->exhandlers += bptr->exhandlercount;
602  }
603 
604  bptr->exhandlers -= 1;
605  *(bptr->exhandlers) = ee->handler;
606 
607  if (ee->handler->expredecessors == NULL) {
608  ee->handler->expredecessors = DMNEW(basicblock *, ee->handler->expredecessorcount);
609  ee->handler->expredecessors += ee->handler->expredecessorcount;
610  }
611 
612  ee->handler->expredecessors -= 1;
613  *(ee->handler->expredecessors) = bptr;
614  }
615  }
616  }
617 
618  if (unreachable_exh) {
619 
620  /* This is rare in ``normal'' compiler generated code.
621 
622  The dead block [EXH] is a predecessor of [BB1],
623  but the edge [EXH] -> [BB1] will never be traversed.
624 
625  [BB1] --[next]--> [BB2, no peis] ==[exhandler]==> [EXH] --[next]--+
626  ^ |
627  +---------------------------------------------------------------+
628  */
629 
630  /*
631  fprintf(stderr, "Found unreachable exh, adjusting %s %s",
632  UTF_TEXT(jd->m->klazz->name), UTF_TEXT(jd->m->name));
633  fprintf(stderr, "<before>\n");
634  show_method(jd, 3);
635  fprintf(stderr, "</before>\n");
636  */
637 
638  cfg_eliminate_edges_to_unreachable(jd);
639 
640  /*
641  fprintf(stderr, "<after>\n");
642  show_method(jd, 3);
643  fprintf(stderr, "</after>\n");
644  */
645  }
646 }
647 
648 static void cfg_calculate_reachability(basicblock *bptr) {
649  basicblock **itsucc;
650 
651  /* Block not marked. */
652  assert(bptr->vp == NULL);
653 
654  bptr->vp = bptr; /* Mark block */
655 
656  FOR_EACH_SUCCESSOR(bptr, itsucc) {
657  if ((*itsucc)->vp == NULL) {
658  cfg_calculate_reachability(*itsucc);
659  }
660  }
661 
662  if (bptr->exouts > 0) {
663  FOR_EACH_EXHANDLER(bptr, itsucc) {
664  if ((*itsucc)->vp == NULL) {
665  cfg_calculate_reachability(*itsucc);
666  }
667  }
668  }
669 }
670 
671 static void cfg_remove_predecessors(basicblock *bptr, basicblock *pbptr) {
672  s4 i;
673 
674  for (i = 0; i < bptr->predecessorcount; ++i) {
675  /* Search item. */
676  if (bptr->predecessors[i] == pbptr) {
677  if (i != (bptr->predecessorcount - 1)) {
678  /* If not last element, replace element with last element. */
679  bptr->predecessors[i] = bptr->predecessors[bptr->predecessorcount - 1];
680  }
681 
682  /* Decrease element count. */
683  bptr->predecessorcount -= 1;
684 
685  return;
686  }
687  }
688 }
689 
690 static void cfg_eliminate_edges_to_unreachable(jitdata *jd) {
691  basicblock *it;
692  basicblock **itsucc;
693 
694  cfg_calculate_reachability(jd->basicblocks);
695 
696  FOR_EACH_BASICBLOCK(jd, it) {
697  if (it->vp == NULL) {
698 
699  /* Mark as unreachable. */
700 
701  it->state = basicblock::UNDEF;
702 
703  /* As this block got unreachable, it is no more a predecessor
704  of its successors. */
705 
706  FOR_EACH_SUCCESSOR(it, itsucc) {
707  cfg_remove_predecessors(*itsucc, it);
708  }
709 
710  /* Eliminiate all CFG edges of this block. */
711 
712  it->predecessorcount = 0;
713  it->successorcount = 0;
714  it->expredecessorcount = 0;
715  }
716  }
717 }
718 
719 #endif
720 
721 /*
722  * These are local overrides for various environment variables in Emacs.
723  * Please do not remove this and leave it at the end of the file, where
724  * Emacs will automagically detect them.
725  * ---------------------------------------------------------------------
726  * Local variables:
727  * mode: c++
728  * indent-tabs-mode: t
729  * c-basic-offset: 4
730  * tab-width: 4
731  * End:
732  * vim:noexpandtab:sw=4:ts=4:
733  */
#define zero
Definition: md-asm.hpp:83
bool cfg_build(jitdata *jd)
Definition: cfg.cpp:124
basicblock * block
#define CF_GOTO
Definition: icmd.hpp:376
basicblock * basicblocks
Definition: jit.hpp:141
Definition: jit.hpp:126
void cfg_add_root(jitdata *jd)
Definition: cfg.cpp:468
exception_entry * exceptiontable
Definition: jit.hpp:168
#define CF_RET
Definition: icmd.hpp:380
void cfg_clear(jitdata *jd)
Definition: cfg.cpp:515
State state
Definition: jit.hpp:320
#define DMREALLOC(ptr, type, num1, num2)
Definition: dumpmemory.hpp:372
basicblock * next
Definition: jit.hpp:344
#define CF_JSR
Definition: icmd.hpp:379
s4 successorcount
Definition: jit.hpp:338
#define CF_TABLE
Definition: icmd.hpp:377
#define CF_END
Definition: icmd.hpp:375
lookup_target_t * lookup
instruction * iinstr
Definition: jit.hpp:326
s4 icount
Definition: jit.hpp:325
void cfg_remove_root(jitdata *jd)
Definition: cfg.cpp:500
#define FOR_EACH_SUCCESSOR(bptr, it)
Definition: jit.hpp:381
#define DNEW(type)
Definition: dumpmemory.hpp:370
static void cfg_allocate_predecessors(basicblock *bptr)
Definition: cfg.cpp:44
#define ICMDTABLE_PEI
Definition: icmd.hpp:384
branch_target_t target
Definition: instruction.hpp:57
dst_operand_t dst
basicblock ** predecessors
Definition: jit.hpp:339
OptionPrefix & root()
Definition: Option.cpp:34
basicblock * start
Definition: jit.hpp:241
s4 predecessorcount
Definition: jit.hpp:337
basicblock * handler
Definition: jit.hpp:243
#define CF_IF
Definition: icmd.hpp:371
#define MZERO(ptr, type, num)
Definition: memory.hpp:105
static void cfg_insert_predecessors(basicblock *bptr, basicblock *pbptr)
Definition: cfg.cpp:78
MIIterator i
#define FOR_EACH_BASICBLOCK(jd, it)
Definition: jit.hpp:181
int32_t s4
Definition: types.hpp:45
union instruction::@12 sx
exception_entry * down
Definition: jit.hpp:247
#define CF_LOOKUP
Definition: icmd.hpp:378
icmdtable_entry_t icmd_table[256]
Definition: icmd.cpp:60
basicblock * block
Definition: instruction.hpp:50
int32_t controlflow
Definition: icmd.hpp:396
void cfg_add_exceptional_edges(jitdata *jd)
methodinfo * m
Definition: jit.hpp:127
basicblock * end
Definition: jit.hpp:242
methodinfo * method
Definition: jit.hpp:349
#define FOR_EACH_INSTRUCTION(bptr, it)
Definition: jit.hpp:391
s4 nr
Definition: jit.hpp:319
s4 basicblockcount
Definition: jit.hpp:144
#define DMNEW(type, num)
Definition: dumpmemory.hpp:371
struct instruction::@12::@13 s23
static void cfg_insert_successors(basicblock *bptr, basicblock *pbptr)
Definition: cfg.cpp:97
basicblock ** successors
Definition: jit.hpp:340
Definition: jit.hpp:240
Type type
Definition: jit.hpp:322
static void cfg_allocate_successors(basicblock *bptr)
Definition: cfg.cpp:61
branch_target_t * table
int32_t flags
Definition: icmd.hpp:397