3 * Generates the machine description
6 * Paolo Molaro (lupus@ximian.com)
8 * (C) 2003 Ximian, Inc.
13 #include <mono/metadata/opcodes.h>
15 #if defined(__native_client__) || defined(__native_client_codegen__)
16 volatile int __nacl_thread_suspension_needed = 0;
17 void __nacl_suspend_thread_if_needed() {}
20 #define MINI_OP(a,b,dest,src1,src2) b,
21 #define MINI_OP3(a,b,dest,src1,src2,src3) b,
22 /* keep in sync with the enum in mini.h */
23 static const char* const
31 * Duplicate this from helpers.c, so the opcode name array can be omitted when
36 if (op >= OP_LOAD && op <= OP_LAST)
37 return opnames [op - OP_LOAD];
39 return mono_opcode_name (op);
40 g_error ("unknown opcode name for %d", op);
49 char spec [MONO_INST_MAX];
53 static GHashTable *table;
54 static GHashTable *template_table;
56 #define eat_whitespace(s) while (*(s) && isspace (*(s))) s++;
58 // Per spec isalnum() expects input in the range 0-255
59 // and can misbehave if you pass in a signed char.
63 return isalnum ((unsigned char)c);
67 load_file (const char *name) {
75 if (!(f = fopen (name, "r")))
76 g_error ("Cannot open file '%s'", name);
78 comment = g_string_new ("");
80 * The format of the lines are:
82 * opcode: [dest:format] [src1:format] [src2:format] [flags:format] [clob:format]
83 * [cost:num] [res:format] [delay:num] [len:num] [nacl:num]
84 * format is a single letter that depends on the field
85 * NOTE: no space between the field name and the ':'
87 * len: maximum instruction length
90 while ((str = fgets (buf, sizeof (buf), f))) {
91 gboolean is_template = FALSE;
92 gboolean nacl_length_set = FALSE;
99 g_string_append (comment, str);
102 p = strchr (str, ':');
104 g_error ("Invalid format at line %d in %s\n", line, name);
107 if (strcmp (str, "template") == 0) {
109 desc = g_new0 (OpDesc, 1);
111 desc = (OpDesc *)g_hash_table_lookup (table, str);
113 g_error ("Invalid opcode '%s' at line %d in %s\n", str, line, name);
115 g_error ("Duplicated opcode %s at line %d in %s\n", str, line, name);
117 desc->desc = g_strdup (p);
118 desc->comment = g_strdup (comment->str);
119 g_string_truncate (comment, 0);
121 if (strncmp (p, "dest:", 5) == 0) {
122 desc->spec [MONO_INST_DEST] = p [5];
124 } else if (strncmp (p, "src1:", 5) == 0) {
125 desc->spec [MONO_INST_SRC1] = p [5];
127 } else if (strncmp (p, "src2:", 5) == 0) {
128 desc->spec [MONO_INST_SRC2] = p [5];
130 } else if (strncmp (p, "src3:", 5) == 0) {
131 desc->spec [MONO_INST_SRC3] = p [5];
133 } else if (strncmp (p, "clob:", 5) == 0) {
134 desc->spec [MONO_INST_CLOB] = p [5];
136 /* Currently unused fields
137 } else if (strncmp (p, "cost:", 5) == 0) {
138 desc->spec [MONO_INST_COST] = p [5];
140 } else if (strncmp (p, "res:", 4) == 0) {
141 desc->spec [MONO_INST_RES] = p [4];
143 } else if (strncmp (p, "flags:", 6) == 0) {
144 desc->spec [MONO_INST_FLAGS] = p [6];
146 } else if (strncmp (p, "delay:", 6) == 0) {
147 desc->spec [MONO_INST_DELAY] = p [6];
150 } else if (strncmp (p, "len:", 4) == 0) {
154 size = strtoul (p, &endptr, 10);
155 if (size == 0 && p == endptr)
156 g_error ("Invalid length '%s' at line %d in %s\n", p, line, name);
158 if (!nacl_length_set) {
159 desc->spec [MONO_INST_LEN] = size;
161 } else if (strncmp (p, "nacl:", 5) == 0) {
164 size = strtoul (p, &p, 10);
166 desc->spec [MONO_INST_LEN] = size;
167 nacl_length_set = TRUE;
169 } else if (strncmp (p, "template:", 9) == 0) {
175 while (*p && isalnum_char (*p)) ++p;
177 tdesc = (OpDesc *)g_hash_table_lookup (template_table, tname);
179 g_error ("Invalid template name %s at '%s' at line %d in %s\n", tname, p, line, name);
180 for (i = 0; i < MONO_INST_MAX; ++i) {
182 g_error ("The template overrides any previous value set at line %d in %s\n", line, name);
184 memcpy (desc->spec, tdesc->spec, sizeof (desc->spec));
185 } else if (strncmp (p, "name:", 5) == 0) {
188 g_error ("name tag only valid in templates at '%s' at line %d in %s\n", p, line, name);
190 g_error ("Duplicated name tag in template %s at '%s' at line %d in %s\n", desc->name, p, line, name);
193 while (*p && isalnum_char (*p)) ++p;
195 if (g_hash_table_lookup (template_table, tname))
196 g_error ("Duplicated template %s at line %d in %s\n", tname, line, name);
197 desc->name = g_strdup (tname);
198 g_hash_table_insert (template_table, (void*)desc->name, desc);
200 g_error ("Parse error at '%s' at line %d in %s\n", p, line, name);
204 if (is_template && !desc->name)
205 g_error ("Template without name at line %d in %s\n", line, name);
207 g_string_free (comment,TRUE);
212 static OpDesc *opcodes = NULL;
219 template_table = g_hash_table_new (g_str_hash, g_str_equal);
220 table = g_hash_table_new (g_str_hash, g_str_equal);
222 opcodes = g_new0 (OpDesc, OP_LAST);
223 for (i = OP_LOAD; i < OP_LAST; ++i) {
226 desc->name = inst_name (i);
227 g_hash_table_insert (table, (char *)desc->name, desc);
232 output_char (FILE *f, char c) {
233 if (isalnum_char (c))
234 fprintf (f, "%c", c);
236 fprintf (f, "\\x%x\" \"", (guint8)c);
240 build_table (const char *fname, const char *name) {
244 GString *idx_array = g_string_new ("");
245 /* use this to remove duplicates */
246 GHashTable *desc_ht = g_hash_table_new (g_str_hash, g_str_equal);
248 if (!(f = fopen (fname, "w")))
249 g_error ("Cannot open file '%s'", fname);
250 fprintf (f, "/* File automatically generated by genmdesc, don't change */\n\n");
251 fprintf (f, "const char mono_%s [] = {\n", name);
253 for (j = 0; j < MONO_INST_MAX; ++j)
255 fprintf (f, "\"\t/* null entry */\n");
257 g_string_append_printf (idx_array, "const guint16 mono_%s_idx [] = {\n", name);
259 for (i = OP_LOAD; i < OP_LAST; ++i) {
262 g_string_append_printf (idx_array, "\t0,\t/* %s */\n", desc->name ? desc->name : "");
265 for (j = 0; j < MONO_INST_MAX; ++j)
266 output_char (f, desc->spec [j]);
267 fprintf (f, "\"\t/* %s */\n", desc->name);
268 g_string_append_printf (idx_array, "\t%d,\t/* %s */\n", idx * MONO_INST_MAX, desc->name);
272 fprintf (f, "};\n\n");
273 fprintf (f, "%s};\n\n", idx_array->str);
275 g_string_free (idx_array, TRUE);
276 g_hash_table_destroy (desc_ht);
284 for (i = 0; i < MONO_CEE_LAST; ++i) {
287 g_print ("%s", desc->comment);
289 g_print ("%s:\n", desc->name);
291 g_print ("%s: %s", desc->name, desc->desc);
292 if (!strchr (desc->desc, '\n'))
296 for (i = OP_LOAD; i < OP_LAST; ++i) {
299 g_print ("%s:\n", desc->name);
301 g_print ("%s: %s", desc->name, desc->desc);
302 if (!strchr (desc->desc, '\n'))
309 * TODO: output the table (possibly merged), in the input format
312 main (int argc, char* argv [])
316 /* useful to get a new file when some opcodes are added: looses the comments, though */
317 load_file (argv [1]);
319 } else if (argc < 4) {
320 g_print ("Usage: genmdesc arguments\n");
321 g_print ("\tgenmdesc desc Output to stdout the description file.\n");
322 g_print ("\tgenmdesc [--nacl] output name desc [desc1...]\n"
323 " Write to output the description in a table named 'name',\n"
324 " use --nacl to generate Google NativeClient code\n");
328 if (strcmp (argv [1], "--nacl") == 0) {
333 for (; i < argc; ++i)
334 load_file (argv [i]);
336 build_table (argv [1 + nacl], argv [2 + nacl]);