2010-01-03 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / genmdesc.c
1 /*
2  * genmdesc: Generates the machine description
3  *
4  * Authors:
5  *   Paolo Molaro (lupus@ximian.com)
6  *
7  * (C) 2003 Ximian, Inc.
8  */
9 #include "mini.h"
10 #include <ctype.h>
11 #include <string.h>
12 #include <mono/metadata/opcodes.h>
13
14 typedef struct {
15         int num;
16         const char *name;
17         char *desc;
18         char *comment;
19         char spec [MONO_INST_MAX];
20 } OpDesc;
21
22 static GHashTable *table;
23
24 #define eat_whitespace(s) while (*(s) && isspace (*(s))) s++;
25
26 static int
27 load_file (const char *name) {
28         FILE *f;
29         char buf [256];
30         char *str, *p;
31         int line;
32         OpDesc *desc;
33         GString *comment;
34
35         if (!(f = fopen (name, "r")))
36                 g_error ("Cannot open file '%s'", name);
37
38         comment = g_string_new ("");
39         /*
40          * The format of the lines are:
41          * # comment
42          * opcode: [dest:format] [src1:format] [src2:format] [flags:format] [clob:format] 
43          *      [cost:num] [res:format] [delay:num] [len:num]
44          * format is a single letter that depends on the field
45          * NOTE: no space between the field name and the ':'
46          *
47          * len: maximum instruction length
48          */
49         line = 0;
50         while ((str = fgets (buf, sizeof (buf), f))) {
51                 ++line;
52                 eat_whitespace (str);
53                 if (!str [0])
54                         continue;
55                 if (str [0] == '#') {
56                         g_string_append (comment, str);
57                         continue;
58                 }
59                 p = strchr (str, ':');
60                 if (!p)
61                         g_error ("Invalid format at line %d in %s\n", line, name);
62                 *p++ = 0;
63                 eat_whitespace (p);
64                 desc = g_hash_table_lookup (table, str);
65                 if (!desc)
66                         g_error ("Invalid opcode '%s' at line %d in %s\n", str, line, name);
67                 if (desc->desc)
68                         g_error ("Duplicated opcode '%s' at line %d in %s\n", str, line, name);
69                 desc->desc = g_strdup (p);
70                 desc->comment = g_strdup (comment->str);
71                 g_string_truncate (comment, 0);
72                 while (*p) {
73                         if (strncmp (p, "dest:", 5) == 0) {
74                                 desc->spec [MONO_INST_DEST] = p [5];
75                                 p += 6;
76                         } else if (strncmp (p, "src1:", 5) == 0) {
77                                 desc->spec [MONO_INST_SRC1] = p [5];
78                                 p += 6;
79                         } else if (strncmp (p, "src2:", 5) == 0) {
80                                 desc->spec [MONO_INST_SRC2] = p [5];
81                                 p += 6;
82                         } else if (strncmp (p, "src3:", 5) == 0) {
83                                 desc->spec [MONO_INST_SRC3] = p [5];
84                                 p += 6;
85                         } else if (strncmp (p, "clob:", 5) == 0) {
86                                 desc->spec [MONO_INST_CLOB] = p [5];
87                                 p += 6;
88                                 /* Currently unused fields
89                         } else if (strncmp (p, "cost:", 5) == 0) {
90                                 desc->spec [MONO_INST_COST] = p [5];
91                                 p += 6;
92                         } else if (strncmp (p, "res:", 4) == 0) {
93                                 desc->spec [MONO_INST_RES] = p [4];
94                                 p += 5;
95                         } else if (strncmp (p, "flags:", 6) == 0) {
96                                 desc->spec [MONO_INST_FLAGS] = p [6];
97                                 p += 7;
98                         } else if (strncmp (p, "delay:", 6) == 0) {
99                                 desc->spec [MONO_INST_DELAY] = p [6];
100                                 p += 7;
101                                 */
102                         } else if (strncmp (p, "len:", 4) == 0) {
103                                 p += 4;
104                                 desc->spec [MONO_INST_LEN] = strtoul (p, &p, 10);
105                         } else {
106                                 g_error ("Parse error at '%s' at line %d in %s\n", p, line, name);
107                         }
108                         eat_whitespace (p);
109                 }
110         }
111         fclose (f);
112         return 0;
113 }
114
115 static OpDesc *opcodes = NULL;
116
117 static void
118 init_table (void) {
119         int i;
120         OpDesc *desc;
121
122         table = g_hash_table_new (g_str_hash, g_str_equal);
123
124         opcodes = g_new0 (OpDesc, OP_LAST);
125         for (i = OP_LOAD; i < OP_LAST; ++i) {
126                 desc = opcodes + i;
127                 desc->num = i;
128                 desc->name = mono_inst_name (i);
129                 g_hash_table_insert (table, (char *)desc->name, desc);
130         }
131 }
132
133 static void
134 output_char (FILE *f, char c) {
135         if (isalnum (c))
136                 fprintf (f, "%c", c);
137         else
138                 fprintf (f, "\\x%x\" \"", c);
139 }
140
141 static void
142 build_table (const char *fname, const char *name) {
143         FILE *f;
144         int i, j, idx;
145         OpDesc *desc;
146         GString *idx_array =  g_string_new ("");
147         /* use this to remove duplicates */
148         GHashTable *desc_ht = g_hash_table_new (g_str_hash, g_str_equal);
149
150         if (!(f = fopen (fname, "w")))
151                 g_error ("Cannot open file '%s'", fname);
152         fprintf (f, "/* File automatically generated by genmdesc, don't change */\n\n");
153         fprintf (f, "const char %s [] = {\n", name);
154         fprintf (f, "\t\"");
155         for (j = 0; j < MONO_INST_MAX; ++j)
156                 fprintf (f, "\\x0");
157         fprintf (f, "\"\t/* null entry */\n");
158         idx = 1;
159         g_string_append_printf (idx_array, "const guint16 %s_idx [] = {\n", name);
160
161         for (i = OP_LOAD; i < OP_LAST; ++i) {
162                 desc = opcodes + i;
163                 if (!desc->desc)
164                         g_string_append_printf (idx_array, "\t0,\t/* %s */\n", desc->name ? desc->name : "");
165                 else {
166                         fprintf (f, "\t\"");
167                         for (j = 0; j < MONO_INST_MAX; ++j)
168                                 output_char (f, desc->spec [j]);
169                         fprintf (f, "\"\t/* %s */\n", desc->name);
170                         g_string_append_printf (idx_array, "\t%d,\t/* %s */\n", idx * MONO_INST_MAX, desc->name);
171                         ++idx;
172                 }
173         }
174         fprintf (f, "};\n\n");
175         fprintf (f, "%s};\n\n", idx_array->str);
176         fclose (f);
177         g_string_free (idx_array, TRUE);
178         g_hash_table_destroy (desc_ht);
179 }
180
181 static void
182 dump (void) {
183         int i;
184         OpDesc *desc;
185         
186         for (i = 0; i < MONO_CEE_LAST; ++i) {
187                 desc = opcodes + i;
188                 if (desc->comment)
189                         g_print ("%s", desc->comment);
190                 if (!desc->desc)
191                         g_print ("%s:\n", desc->name);
192                 else {
193                         g_print ("%s: %s", desc->name, desc->desc);
194                         if (!strchr (desc->desc, '\n'))
195                                 g_print ("\n");
196                 }
197         }
198         for (i = OP_LOAD; i < OP_LAST; ++i) {
199                 desc = opcodes + i;
200                 if (!desc->desc)
201                         g_print ("%s:\n", desc->name);
202                 else {
203                         g_print ("%s: %s", desc->name, desc->desc);
204                         if (!strchr (desc->desc, '\n'))
205                                 g_print ("\n");
206                 }
207         }
208 }
209
210 /*
211  * TODO: output the table (possibly merged), in the input format 
212  */
213 int 
214 main (int argc, char* argv [])
215 {
216         init_table ();
217         if (argc == 2) {
218                 /* useful to get a new file when some opcodes are added: looses the comments, though */
219                 load_file (argv [1]);
220                 dump ();
221         } else if (argc < 4) {
222                 g_print ("Usage: genmdesc arguments\n");
223                 g_print ("\tgenmdesc desc                        Output to stdout the description file.\n");
224                 g_print ("\tgenmdesc output name desc [desc1...] Write to output the description in a table named 'name'.\n");
225                 return 1;
226         } else {
227                 int i;
228                 for (i = 3; i < argc; ++i)
229                         load_file (argv [i]);
230                 build_table (argv [1], argv [2]);
231         }
232         return 0;
233 }
234