2 * genmdesc: Generates the machine description
5 * Paolo Molaro (lupus@ximian.com)
7 * (C) 2003 Ximian, Inc.
12 #include <mono/metadata/opcodes.h>
19 char spec [MONO_INST_MAX];
22 static GHashTable *table;
23 static GHashTable *template_table;
25 #define eat_whitespace(s) while (*(s) && isspace (*(s))) s++;
28 load_file (const char *name) {
36 if (!(f = fopen (name, "r")))
37 g_error ("Cannot open file '%s'", name);
39 comment = g_string_new ("");
41 * The format of the lines are:
43 * opcode: [dest:format] [src1:format] [src2:format] [flags:format] [clob:format]
44 * [cost:num] [res:format] [delay:num] [len:num]
45 * format is a single letter that depends on the field
46 * NOTE: no space between the field name and the ':'
48 * len: maximum instruction length
51 while ((str = fgets (buf, sizeof (buf), f))) {
52 gboolean is_template = FALSE;
58 g_string_append (comment, str);
61 p = strchr (str, ':');
63 g_error ("Invalid format at line %d in %s\n", line, name);
66 if (strcmp (str, "template") == 0) {
68 desc = g_new0 (OpDesc, 1);
70 desc = g_hash_table_lookup (table, str);
72 g_error ("Invalid opcode '%s' at line %d in %s\n", str, line, name);
74 g_error ("Duplicated opcode %s at line %d in %s\n", str, line, name);
76 desc->desc = g_strdup (p);
77 desc->comment = g_strdup (comment->str);
78 g_string_truncate (comment, 0);
80 if (strncmp (p, "dest:", 5) == 0) {
81 desc->spec [MONO_INST_DEST] = p [5];
83 } else if (strncmp (p, "src1:", 5) == 0) {
84 desc->spec [MONO_INST_SRC1] = p [5];
86 } else if (strncmp (p, "src2:", 5) == 0) {
87 desc->spec [MONO_INST_SRC2] = p [5];
89 } else if (strncmp (p, "src3:", 5) == 0) {
90 desc->spec [MONO_INST_SRC3] = p [5];
92 } else if (strncmp (p, "clob:", 5) == 0) {
93 desc->spec [MONO_INST_CLOB] = p [5];
95 /* Currently unused fields
96 } else if (strncmp (p, "cost:", 5) == 0) {
97 desc->spec [MONO_INST_COST] = p [5];
99 } else if (strncmp (p, "res:", 4) == 0) {
100 desc->spec [MONO_INST_RES] = p [4];
102 } else if (strncmp (p, "flags:", 6) == 0) {
103 desc->spec [MONO_INST_FLAGS] = p [6];
105 } else if (strncmp (p, "delay:", 6) == 0) {
106 desc->spec [MONO_INST_DELAY] = p [6];
109 } else if (strncmp (p, "len:", 4) == 0) {
111 desc->spec [MONO_INST_LEN] = strtoul (p, &p, 10);
112 } else if (strncmp (p, "template:", 9) == 0) {
118 while (*p && isalnum (*p)) ++p;
120 tdesc = g_hash_table_lookup (template_table, tname);
122 g_error ("Invalid template name %s at '%s' at line %d in %s\n", tname, p, line, name);
123 for (i = 0; i < MONO_INST_MAX; ++i) {
125 g_error ("The template overrides any previous value set at line %d in %s\n", line, name);
127 memcpy (desc->spec, tdesc->spec, sizeof (desc->spec));
128 } else if (strncmp (p, "name:", 5) == 0) {
131 g_error ("name tag only valid in templates at '%s' at line %d in %s\n", p, line, name);
133 g_error ("Duplicated name tag in template %s at '%s' at line %d in %s\n", desc->name, p, line, name);
136 while (*p && isalnum (*p)) ++p;
138 if (g_hash_table_lookup (template_table, tname))
139 g_error ("Duplicated template %s at line %d in %s\n", tname, line, name);
140 desc->name = g_strdup (tname);
141 g_hash_table_insert (template_table, (void*)desc->name, desc);
143 g_error ("Parse error at '%s' at line %d in %s\n", p, line, name);
147 if (is_template && !desc->name)
148 g_error ("Template without name at line %d in %s\n", line, name);
154 static OpDesc *opcodes = NULL;
161 template_table = g_hash_table_new (g_str_hash, g_str_equal);
162 table = g_hash_table_new (g_str_hash, g_str_equal);
164 opcodes = g_new0 (OpDesc, OP_LAST);
165 for (i = OP_LOAD; i < OP_LAST; ++i) {
168 desc->name = mono_inst_name (i);
169 g_hash_table_insert (table, (char *)desc->name, desc);
174 output_char (FILE *f, char c) {
176 fprintf (f, "%c", c);
178 fprintf (f, "\\x%x\" \"", c);
182 build_table (const char *fname, const char *name) {
186 GString *idx_array = g_string_new ("");
187 /* use this to remove duplicates */
188 GHashTable *desc_ht = g_hash_table_new (g_str_hash, g_str_equal);
190 if (!(f = fopen (fname, "w")))
191 g_error ("Cannot open file '%s'", fname);
192 fprintf (f, "/* File automatically generated by genmdesc, don't change */\n\n");
193 fprintf (f, "const char %s [] = {\n", name);
195 for (j = 0; j < MONO_INST_MAX; ++j)
197 fprintf (f, "\"\t/* null entry */\n");
199 g_string_append_printf (idx_array, "const guint16 %s_idx [] = {\n", name);
201 for (i = OP_LOAD; i < OP_LAST; ++i) {
204 g_string_append_printf (idx_array, "\t0,\t/* %s */\n", desc->name ? desc->name : "");
207 for (j = 0; j < MONO_INST_MAX; ++j)
208 output_char (f, desc->spec [j]);
209 fprintf (f, "\"\t/* %s */\n", desc->name);
210 g_string_append_printf (idx_array, "\t%d,\t/* %s */\n", idx * MONO_INST_MAX, desc->name);
214 fprintf (f, "};\n\n");
215 fprintf (f, "%s};\n\n", idx_array->str);
217 g_string_free (idx_array, TRUE);
218 g_hash_table_destroy (desc_ht);
226 for (i = 0; i < MONO_CEE_LAST; ++i) {
229 g_print ("%s", desc->comment);
231 g_print ("%s:\n", desc->name);
233 g_print ("%s: %s", desc->name, desc->desc);
234 if (!strchr (desc->desc, '\n'))
238 for (i = OP_LOAD; i < OP_LAST; ++i) {
241 g_print ("%s:\n", desc->name);
243 g_print ("%s: %s", desc->name, desc->desc);
244 if (!strchr (desc->desc, '\n'))
251 * TODO: output the table (possibly merged), in the input format
254 main (int argc, char* argv [])
258 /* useful to get a new file when some opcodes are added: looses the comments, though */
259 load_file (argv [1]);
261 } else if (argc < 4) {
262 g_print ("Usage: genmdesc arguments\n");
263 g_print ("\tgenmdesc desc Output to stdout the description file.\n");
264 g_print ("\tgenmdesc output name desc [desc1...] Write to output the description in a table named 'name'.\n");
268 for (i = 3; i < argc; ++i)
269 load_file (argv [i]);
270 build_table (argv [1], argv [2]);