2007-10-19 Marek Habersack <mhabersack@novell.com>
[mono.git] / mono / monoburg / monoburg.c
index 36f5dd81486e7fbf0dd85fc7075399af01c952fc..006eacd1fe8aa7b0e6a89e50c24beb9b43dbdf6c 100644 (file)
@@ -23,6 +23,7 @@ static GList *prefix_list;
 
 FILE *inputfd;
 FILE *outputfd;
+GHashTable *definedvars;
 static FILE *deffd;
 static FILE *cfd;
 
@@ -39,16 +40,22 @@ static void output (char *fmt, ...)
        va_end (ap);
 }
 
-void     
-create_rule (char *id, Tree *tree, char *code, char *cost, char *cfunc)
+Rule*
+make_rule (char *id, Tree *tree)
 {
        Rule *rule = g_new0 (Rule, 1);
+       rule->lhs = nonterm (id);
+       rule->tree = tree;
+
+       return rule;
+}
 
+void
+rule_add (Rule *rule, char *code, char *cost, char *cfunc)
+{
        if (!cfunc && !cost)
                cost = g_strdup_printf ("%d", default_cost);
 
-       rule->lhs = nonterm (id);
-       rule->tree = tree;
        rule_list = g_list_append (rule_list, rule);
        rule->cost = g_strdup (cost);
        rule->cfunc = g_strdup (cfunc);
@@ -69,10 +76,18 @@ create_rule (char *id, Tree *tree, char *code, char *cost, char *cfunc)
 
        rule->lhs->rules = g_list_append (rule->lhs->rules, rule);
 
-       if (tree->op)
-               tree->op->rules = g_list_append (tree->op->rules, rule);
+       if (rule->tree->op)
+               rule->tree->op->rules = g_list_append (rule->tree->op->rules, rule);
        else 
-               tree->nonterm->chain = g_list_append (tree->nonterm->chain, rule);
+               rule->tree->nonterm->chain = g_list_append (rule->tree->nonterm->chain, rule);
+}
+
+void     
+create_rule (char *id, Tree *tree, char *code, char *cost, char *cfunc)
+{
+       Rule *rule = make_rule (id, tree);
+
+       rule_add (rule, code, cost, cfunc);
 }
 
 Tree *
@@ -85,7 +100,7 @@ create_tree (char *id, Tree *left, Tree *right)
        if (term_hash)
                term = g_hash_table_lookup (term_hash, id);
 
-       // try if id has termprefix
+       /* try if id has termprefix */
        if (!term) {
                GList *pl;
                for (pl = prefix_list; pl; pl = pl->next) {
@@ -146,7 +161,7 @@ create_term (char *id, int num)
        if (!term_hash) 
                term_hash = g_hash_table_new (g_str_hash , g_str_equal);
 
-       g_hash_table_foreach (term_hash, (GHFunc) check_term_num, (gpointer) num);
+       g_hash_table_foreach (term_hash, (GHFunc) check_term_num, GINT_TO_POINTER (num));
 
        term = g_new0 (Term, 1);
 
@@ -261,6 +276,7 @@ emit_header ()
        output ("#ifndef MBTREE_LEFT\n#define MBTREE_LEFT(t) ((t)->left)\n#endif\n");
        output ("#ifndef MBTREE_RIGHT\n#define MBTREE_RIGHT(t) ((t)->right)\n#endif\n");
        output ("#ifndef MBTREE_STATE\n#define MBTREE_STATE(t) ((t)->state)\n#endif\n");
+       output ("#ifndef MBREG_TYPE\n#define MBREG_TYPE gint32\n#endif\n");
        output ("#ifndef MBCGEN_TYPE\n#define MBCGEN_TYPE int\n#endif\n");
        output ("#ifndef MBALLOC_STATE\n#define MBALLOC_STATE g_new (MBState, 1)\n#endif\n");
        output ("#ifndef MBCOST_DATA\n#define MBCOST_DATA gpointer\n#endif\n");
@@ -319,7 +335,8 @@ emit_state ()
 
        if (dag_mode) {
                output ("\tMBTREE_TYPE\t *tree;\n");
-               output ("\tgint32 reg1, reg2;\n");
+               output ("\tMBREG_TYPE\t reg1;\n");
+               output ("\tMBREG_TYPE\t reg2;\n");
        }
        
        output ("\tMBState\t\t*left, *right;\n");
@@ -345,7 +362,7 @@ emit_decoders ()
 
        for (l = nonterm_list; l; l = l->next) {
                NonTerm *n = (NonTerm *)l->data;
-               output ("const int mono_burg_decode_%s[] = {\n", n->name);
+               output ("const short mono_burg_decode_%s[] = {\n", n->name);
                output ("\t0,\n");
                for (rl = n->rules; rl; rl = rl->next) {
                        Rule *rule = (Rule *)rl->data;
@@ -689,37 +706,47 @@ emit_emitter_func ()
 {
        GList *l;
        int i;
+       GHashTable *cache = g_hash_table_new (g_str_hash, g_str_equal);
 
        for (l =  rule_list, i = 0; l; l = l->next) {
                Rule *rule = (Rule *)l->data;
                
                if (rule->code) {
-                       output ("static void ");
-
-                       emit_rule_string (rule, "");
-
-                       if (dag_mode)
-                               output ("mono_burg_emit_%d (MBState *state, MBTREE_TYPE *tree, MBCGEN_TYPE *s)\n", i);
-                       else
-                               output ("mono_burg_emit_%d (MBTREE_TYPE *tree, MBCGEN_TYPE *s)\n", i);
-                       output ("{\n");
-                       output ("%s\n", rule->code);
-                       output ("}\n\n");
+                       GList *cases;
+                       if ((cases = g_hash_table_lookup (cache, rule->code))) {
+                               cases = g_list_append (cases, GINT_TO_POINTER (i));
+                       } else {
+                               cases = g_list_append (NULL, GINT_TO_POINTER (i));
+                       }
+                       g_hash_table_insert (cache, rule->code, cases);
                }
                i++;
        }
 
-       output ("MBEmitFunc const mono_burg_func [] = {\n");
-       output ("\tNULL,\n");
+       output ("void mono_burg_emit (int ern, MBState *state, MBTREE_TYPE *tree, MBCGEN_TYPE *s)\n {\n");
+       output ("\tswitch (ern) {");
        for (l =  rule_list, i = 0; l; l = l->next) {
                Rule *rule = (Rule *)l->data;
-               if (rule->code)
-                       output ("\tmono_burg_emit_%d,\n", i);
-               else
-                       output ("\tNULL,\n");
+
+               if (rule->code) {
+                       GList *cases, *tmp;
+                       cases = g_hash_table_lookup (cache, rule->code);
+                       if (cases && i != GPOINTER_TO_INT (cases->data)) {
+                               i++;
+                               continue;
+                       }
+                       emit_rule_string (rule, "");
+                       for (tmp = cases; tmp; tmp = tmp->next) {
+                               output ("\tcase %d:\n", GPOINTER_TO_INT (tmp->data) + 1);
+                       }
+                       output ("\t{\n");
+                       output ("%s\n", rule->code);
+                       output ("\t}\n\treturn;\n");
+               }
                i++;
        }
-       output ("};\n\n");
+       output ("\t}\n}\n\n");
+       g_hash_table_destroy (cache);
 }
 
 static void
@@ -793,26 +820,50 @@ compute_nonterms (Tree *tree)
        } 
 }
 
+static int
+count_nonterms (Tree *tree)
+{
+       if (!tree)
+               return 0;
+
+       if (tree->nonterm) {
+               return 1;
+       } else {
+               return count_nonterms (tree->left) + count_nonterms (tree->right);
+       } 
+}
+
 static void
 emit_vardefs ()
 {
        GList *l;
        int i, j, c, n, *si;
        char **sa;
+       int *nts_offsets;
+       int current_offset;
 
+       output ("\n");
        if (predefined_terms) {
+               output ("#if HAVE_ARRAY_ELEM_INIT\n");
+               output ("const guint8 mono_burg_arity [MBMAX_OPCODES] = {\n"); 
+               for (l = term_list, i = 0; l; l = l->next) {
+                       Term *t = (Term *)l->data;
+                       output ("\t [%s] = %d, /* %s */\n", t->name, t->arity, t->name);
+               }
+               output ("};\n\n");
+               output ("void\nmono_burg_init (void) {\n");
+               output ("}\n\n");
+               output ("#else\n");
                output ("guint8 mono_burg_arity [MBMAX_OPCODES];\n"); 
 
                output ("void\nmono_burg_init (void)\n{\n");
 
                for (l = term_list, i = 0; l; l = l->next) {
                        Term *t = (Term *)l->data;
-
                        output ("\tmono_burg_arity [%s] = %d; /* %s */\n", t->name, t->arity, t->name);
-
                }
-
                output ("}\n\n");
+               output ("#endif /* HAVE_ARRAY_ELEM_INIT */\n");
 
        } else {
                output ("const guint8 mono_burg_arity [] = {\n"); 
@@ -839,6 +890,7 @@ emit_vardefs ()
                output ("};\n\n");
        }
 
+       output ("#if MONOBURG_LOG\n");
        output ("const char * const mono_burg_rule_string [] = {\n");
        output ("\tNULL,\n");
        for (l = rule_list, i = 0; l; l = l->next) {
@@ -847,12 +899,17 @@ emit_vardefs ()
                emit_tree_string (rule->tree);
                output ("\",\n");
        }
-       output ("};\n\n");
+       output ("};\n");
+       output ("#endif /* MONOBURG_LOG */\n\n");
 
        n = g_list_length (rule_list);
        sa = g_new0 (char *, n);
        si = g_new0 (int, n);
+       nts_offsets = g_new0 (int, n);
 
+       /* at offset 0 we store 0 to mean end of list */
+       current_offset = 1;
+       output ("const guint16 mono_burg_nts_data [] = {\n\t0,\n");
        /* compress the _nts array */
        for (l = rule_list, i = 0, c = 0; l; l = l->next) {
                Rule *rule = (Rule *)l->data;
@@ -864,17 +921,20 @@ emit_vardefs ()
 
                si [i++] = j;
                if (j == c) {
-                       output ("static const guint16 mono_burg_nts_%d [] = { %s0 };\n", c, s);
+                       output ("\t%s0,\n", s);
+                       nts_offsets [c] = current_offset;
                        sa [c++] = s;
+                       current_offset += count_nonterms (rule->tree) + 1;
                }
        }       
-       output ("\n");
+       output ("\t0\n};\n\n");
 
-       output ("const guint16 *const mono_burg_nts [] = {\n");
+       output ("const guint8 mono_burg_nts [] = {\n");
        output ("\t0,\n");
        for (l = rule_list, i = 0; l; l = l->next) {
                Rule *rule = (Rule *)l->data;
-               output ("\tmono_burg_nts_%d, ", si [i++]);
+               output ("\t%d, /* %s */ ", nts_offsets [si [i]], sa [si [i]]);
+               ++i;
                emit_rule_string (rule, "");
        }
        output ("};\n\n");
@@ -883,15 +943,13 @@ emit_vardefs ()
 static void
 emit_prototypes ()
 {
-       if (dag_mode)
-               output ("typedef void (*MBEmitFunc) (MBState *state, MBTREE_TYPE *tree, MBCGEN_TYPE *s);\n\n");
-       else
-               output ("typedef void (*MBEmitFunc) (MBTREE_TYPE *tree, MBCGEN_TYPE *s);\n\n");
-       
        output ("extern const char * const mono_burg_term_string [];\n");
+       output ("#if MONOBURG_LOG\n");
        output ("extern const char * const mono_burg_rule_string [];\n");
-       output ("extern const guint16 *const mono_burg_nts [];\n");
-       output ("extern MBEmitFunc const mono_burg_func [];\n");
+       output ("#endif /* MONOBURG_LOG */\n");
+       output ("extern const guint16 mono_burg_nts_data [];\n");
+       output ("extern const guint8 mono_burg_nts [];\n");
+       output ("extern void mono_burg_emit (int ern, MBState *state, MBTREE_TYPE *tree, MBCGEN_TYPE *s);\n\n");
 
        output ("MBState *mono_burg_label (MBTREE_TYPE *tree, MBCOST_DATA *data);\n");
        output ("int mono_burg_rule (MBState *state, int goal);\n");
@@ -975,6 +1033,7 @@ main (int argc, char *argv [])
        GList *infiles = NULL;
        int i;
 
+        definedvars = g_hash_table_new (g_str_hash, g_str_equal);
        g_log_set_handler (NULL, G_LOG_LEVEL_WARNING, warning_handler, stderr);
 
        for (i = 1; i < argc; i++){
@@ -991,6 +1050,9 @@ main (int argc, char *argv [])
                                cfile = argv [++i];
                        } else if (argv [i][1] == 'c') {
                                default_cost = atoi (argv [++i]);
+                       } else if (argv [i][1] == 'D') {
+                                g_hash_table_insert (definedvars, &argv [i][2],
+                                                     GUINT_TO_POINTER (1));
                        } else {
                                usage ();
                        }
@@ -1061,16 +1123,6 @@ main (int argc, char *argv [])
                output ("#include \"%s\"\n\n", deffile);
        }
        
-       emit_vardefs ();
-       emit_cost_func ();
-       emit_emitter_func ();
-       emit_decoders ();
-
-       emit_closure ();
-       emit_label_func ();
-
-       emit_kids ();
-
        if (infiles) {
                GList *l = infiles;
                while (l) {
@@ -1083,6 +1135,16 @@ main (int argc, char *argv [])
                yyparsetail ();
        }
 
+       emit_vardefs ();
+       emit_cost_func ();
+       emit_emitter_func ();
+       emit_decoders ();
+
+       emit_closure ();
+       emit_label_func ();
+
+       emit_kids ();
+
        if (cfile)
                fclose (cfd);