* src/vm/jit/jit.c: Moved to .cpp.
[cacao.git] / src / vm / jit / cfg.c
index 2df6dd7baa6be195a94fdb75c038ce4e49744156..4772b95f2f71d984b7cb776122ff305233e7527e 100644 (file)
@@ -34,7 +34,7 @@
 
 #include "vm/global.h"
 
-#include "vm/jit/jit.h"
+#include "vm/jit/jit.hpp"
 #include "vm/jit/stack.h"
 
 
@@ -134,12 +134,20 @@ bool cfg_build(jitdata *jd)
        branch_target_t *table;
        lookup_target_t *lookup;
        int              i;
+       bool             has_fallthrough;
 
        /* process all basic blocks to find the predecessor/successor counts */
 
        bptr = jd->basicblocks;
 
        for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) {
+
+               if (bptr->type == BBTYPE_EXH) {
+                       /* predecessorcount for exception handlers is initialized to -1,
+                          so we need to fix it to 0. */
+                       bptr->predecessorcount += 1;
+               }
+
                if ((bptr->icount == 0) || (bptr->flags == BBUNDEF))
                        continue;
 
@@ -153,6 +161,43 @@ bool cfg_build(jitdata *jd)
                        iptr--;
                }
 
+               if (iptr->opc == ICMD_GOTO) {
+
+                       /*
+                        This is needed for the following special case caused by
+                        stack_reach_next_block:
+                        I.e. there might be instructions causing control flow before
+                        a GOTO:
+
+                        ....
+                        129: 192:  IFEQ            Ti102 0 (0x00000000) --> L052
+                        131: 193:  NOP
+                          0:   0:  GOTO            --> L060
+                       */
+
+                       bptr->successorcount++;
+
+                       tbptr = iptr->dst.block;
+                       tbptr->predecessorcount++;
+
+                       if (iptr == bptr->iinstr) {
+                               continue;
+                       }
+                       
+                       iptr--;
+
+                       while (iptr->opc == ICMD_NOP) {
+                               if (iptr == bptr->iinstr) {
+                                       break;
+                               }
+                               iptr--;
+                       }
+
+                       has_fallthrough = false;
+               } else {
+                       has_fallthrough = true;
+               }
+
                switch (icmd_table[iptr->opc].controlflow) {
 
                case CF_END:
@@ -163,10 +208,12 @@ bool cfg_build(jitdata *jd)
                        bptr->successorcount += 2;
 
                        tbptr  = iptr->dst.block;
-                       ntbptr = bptr->next;
-
                        tbptr->predecessorcount++;
-                       ntbptr->predecessorcount++;
+
+                       if (has_fallthrough) {
+                               ntbptr = bptr->next;
+                               ntbptr->predecessorcount++;
+                       }
                        break;
 
                case CF_JSR:
@@ -224,14 +271,16 @@ bool cfg_build(jitdata *jd)
                        break;
 
                default:
-                       bptr->successorcount++;
+                       if (has_fallthrough) {
+                               bptr->successorcount++;
 
-                       tbptr = bptr->next;
+                               tbptr = bptr->next;
 
-                       /* An exception handler has no predecessors. */
+                               /* An exception handler has no predecessors. */
 
-                       if (tbptr->type != BBTYPE_EXH)
-                               tbptr->predecessorcount++;
+                               if (tbptr->type != BBTYPE_EXH)
+                                       tbptr->predecessorcount++;
+                       }
                        break;
                }
        }
@@ -255,6 +304,36 @@ bool cfg_build(jitdata *jd)
                        iptr--;
                }
 
+               if (iptr->opc == ICMD_GOTO) {
+                       tbptr = iptr->dst.block;
+
+                       cfg_allocate_successors(bptr);
+
+                       cfg_insert_successors(bptr, tbptr);
+
+                       cfg_allocate_predecessors(tbptr);
+
+                       cfg_insert_predecessors(tbptr, bptr);
+
+                       if (iptr == bptr->iinstr) {
+                               continue;
+                       }
+                       
+                       iptr--;
+
+                       while (iptr->opc == ICMD_NOP) {
+                               if (iptr == bptr->iinstr) {
+                                       break;
+                               }
+                               iptr--;
+                       }
+
+                       has_fallthrough = false;
+
+               } else {
+                       has_fallthrough = true;
+               }
+
                switch (icmd_table[iptr->opc].controlflow) {
 
                case CF_END:
@@ -268,13 +347,19 @@ bool cfg_build(jitdata *jd)
                        cfg_allocate_successors(bptr);
 
                        cfg_insert_successors(bptr, tbptr);
-                       cfg_insert_successors(bptr, ntbptr);
+                       if (has_fallthrough) {
+                               cfg_insert_successors(bptr, ntbptr);
+                       }
 
                        cfg_allocate_predecessors(tbptr);
-                       cfg_allocate_predecessors(ntbptr);
+                       if (has_fallthrough) {
+                               cfg_allocate_predecessors(ntbptr);
+                       }
 
                        cfg_insert_predecessors(tbptr, bptr);
-                       cfg_insert_predecessors(ntbptr, bptr);
+                       if (has_fallthrough) {
+                               cfg_insert_predecessors(ntbptr, bptr);
+                       }
                        break;
 
                case CF_JSR:
@@ -349,20 +434,22 @@ goto_tail:
                        break;
 
                default:
-                       tbptr = bptr->next;
+                       if (has_fallthrough) {
+                               tbptr = bptr->next;
 
-                       cfg_allocate_successors(bptr);
+                               cfg_allocate_successors(bptr);
 
-                       bptr->successors[0] = tbptr;
-                       bptr->successorcount++;
+                               bptr->successors[0] = tbptr;
+                               bptr->successorcount++;
 
-                       /* An exception handler has no predecessors. */
+                               /* An exception handler has no predecessors. */
 
-                       if (tbptr->type != BBTYPE_EXH) {
-                               cfg_allocate_predecessors(tbptr);
+                               if (tbptr->type != BBTYPE_EXH) {
+                                       cfg_allocate_predecessors(tbptr);
 
-                               tbptr->predecessors[tbptr->predecessorcount] = bptr;
-                               tbptr->predecessorcount++;
+                                       tbptr->predecessors[tbptr->predecessorcount] = bptr;
+                                       tbptr->predecessorcount++;
+                               }
                        }
                        break;
                }
@@ -396,6 +483,7 @@ void cfg_add_root(jitdata *jd) {
        root->next = zero;
        root->nr = 0;
        root->type = BBTYPE_STD;
+       root->method = jd->m;
 
        if (zero->predecessorcount == 0) {
                zero->predecessors = DNEW(basicblock *);
@@ -413,6 +501,216 @@ void cfg_add_root(jitdata *jd) {
        }
 }
 
+void cfg_remove_root(jitdata *jd) {
+       basicblock *root, *zero, *it;
+
+       root = jd->basicblocks;
+       zero = root->next;
+
+       zero->predecessorcount -= 1;
+
+       jd->basicblocks = zero;
+
+       for (it = zero; it; it = it->next) {
+               it->nr -= 1;
+       }
+}
+
+#if defined(ENABLE_SSA)
+
+static void cfg_eliminate_edges_to_unreachable(jitdata *jd);
+
+/* cfg_add_exceptional_edges ***************************************************
+   Edges from basicblocks to their exception handlers and from exception 
+   handlers to the blocks they handle exceptions for are added. Further
+   the number of potentially throwing instructions in the basicblocks are 
+   counted.
+
+   We don't consider nor do we determine the types of exceptions thrown. Edges
+   are added from every block to every potential handler.
+
+*******************************************************************************/
+
+void cfg_add_exceptional_edges(jitdata *jd) {
+       basicblock *bptr;
+       instruction *iptr;
+       exception_entry *ee;
+       bool unreachable_exh = false;
+
+       /* Count the number of exceptional exits for every block.
+        * Every PEI is an exceptional out.
+        */
+
+       FOR_EACH_BASICBLOCK(jd, bptr) {
+
+               /* Prepare for reachability calculation. */
+               bptr->vp = NULL;
+
+               if (bptr->flags == BBUNDEF) {
+                       continue;
+               }
+
+               FOR_EACH_INSTRUCTION(bptr, iptr) {
+                       if (icmd_table[iptr->opc].flags & ICMDTABLE_PEI) {      
+                               bptr->exouts += 1;
+                       }
+               }
+       }
+
+       /* Count the number of exception handlers for every block. */
+
+       for (ee = jd->exceptiontable; ee; ee = ee->down) {
+               for (bptr = ee->start; bptr != ee->end; bptr = bptr->next) {
+                       /* Linking a block with a handler, even if there are no exceptional exits
+                          breaks stuff in other passes. */
+                       if (bptr->exouts > 0) {
+                               bptr->exhandlercount += 1;
+                               ee->handler->expredecessorcount += 1;
+                       }
+               }
+       }
+
+       /* Allocate and fill exception handler arrays. */
+
+       for (ee = jd->exceptiontable; ee; ee = ee->down) {
+
+               if (ee->handler->expredecessorcount == 0) {
+                       /* An exception handler that is unreachable.
+                          This is inconsistent with the semantics of the CFG,
+                          we need to recalculate reachability. */
+                       unreachable_exh = true;
+               }
+
+               for (bptr = ee->start; bptr != ee->end; bptr = bptr->next) {
+                       if (bptr->exouts > 0) {
+
+                               if (bptr->exhandlers == NULL) {
+                                       bptr->exhandlers = DMNEW(basicblock *, bptr->exhandlercount);
+                                       /* Move pointer past the end of the array, 
+                                        * It will be filled in the reverse order.
+                                        */
+                                       bptr->exhandlers += bptr->exhandlercount;
+                               }
+
+                               bptr->exhandlers -= 1;
+                               *(bptr->exhandlers) = ee->handler;
+
+                               if (ee->handler->expredecessors == NULL) {
+                                       ee->handler->expredecessors = DMNEW(basicblock *, ee->handler->expredecessorcount);
+                                       ee->handler->expredecessors += ee->handler->expredecessorcount;
+                               }
+
+                               ee->handler->expredecessors -= 1;
+                               *(ee->handler->expredecessors) = bptr;
+                       }
+               }
+       }
+
+       if (unreachable_exh) {
+
+               /* This is rare in ``normal'' compiler generated code.
+                 
+                  The dead block [EXH] is a predecessor of [BB1],
+                  but the edge [EXH] -> [BB1] will never be traversed.
+
+                  [BB1] --[next]--> [BB2, no peis] ==[exhandler]==> [EXH] --[next]--+
+             ^                                                               |
+                    +---------------------------------------------------------------+
+               */
+
+               /*
+               fprintf(stderr, "Found unreachable exh, adjusting %s %s", 
+                       jd->m->klazz->name->text, jd->m->name->text);
+               fprintf(stderr, "<before>\n");
+               show_method(jd, 3);
+               fprintf(stderr, "</before>\n");
+               */
+
+               cfg_eliminate_edges_to_unreachable(jd);
+
+               /*
+               fprintf(stderr, "<after>\n");
+               show_method(jd, 3);
+               fprintf(stderr, "</after>\n");
+               */
+       }
+}
+
+static void cfg_calculate_reachability(basicblock *bptr) {
+       basicblock **itsucc;
+
+       /* Block not marked. */
+       assert(bptr->vp == NULL);
+
+       bptr->vp = bptr; /* Mark block */
+
+       FOR_EACH_SUCCESSOR(bptr, itsucc) {
+               if ((*itsucc)->vp == NULL) {
+                       cfg_calculate_reachability(*itsucc);
+               }
+       }
+
+       if (bptr->exouts > 0) {
+               FOR_EACH_EXHANDLER(bptr, itsucc) {
+                       if ((*itsucc)->vp == NULL) {
+                               cfg_calculate_reachability(*itsucc);
+                       }
+               }
+       }
+}
+
+static void cfg_remove_predecessors(basicblock *bptr, basicblock *pbptr) {
+       s4 i;
+
+       for (i = 0; i < bptr->predecessorcount; ++i) {
+               /* Search item. */
+               if (bptr->predecessors[i] == pbptr) {
+                       if (i != (bptr->predecessorcount - 1)) {
+                               /* If not last element, replace element with last element. */
+                               bptr->predecessors[i] = bptr->predecessors[bptr->predecessorcount - 1];
+                       }
+
+                       /* Decrease element count. */
+                       bptr->predecessorcount -= 1;
+
+                       return;
+               }
+       }
+}
+
+static void cfg_eliminate_edges_to_unreachable(jitdata *jd) {
+       basicblock *it;
+       basicblock **itsucc;
+
+       cfg_calculate_reachability(jd->basicblocks);
+
+       FOR_EACH_BASICBLOCK(jd, it) {
+               if (it->vp == NULL) {
+
+                       /* Mark as unreachable. */
+
+                       it->flags = BBUNDEF;
+
+                       /* As this block got unreachable, it is no more a predecessor
+                          of its successors. */
+
+                       FOR_EACH_SUCCESSOR(it, itsucc) {
+                               cfg_remove_predecessors(*itsucc, it);
+                       }
+
+                       /* Eliminiate all CFG edges of this block. */
+
+                       it->predecessorcount = 0;
+                       it->successorcount = 0;
+                       it->expredecessorcount = 0;
+               }
+       }
+}
+
+
+#endif
+
 /*
  * These are local overrides for various environment variables in Emacs.
  * Please do not remove this and leave it at the end of the file, where