[tests] Disable tests that crash on android sdks (#17255)
[mono-project.git] / mono / mini / genmdesc.c
blobf2103082835c7c309596d8400adbb5441f1f0972
1 /**
2 * \file
3 * Generates the machine description
5 * Authors:
6 * Paolo Molaro (lupus@ximian.com)
8 * (C) 2003 Ximian, Inc.
9 */
10 #include "mini.h"
11 #include <ctype.h>
12 #include <string.h>
13 #include <mono/metadata/opcodes.h>
15 #define MINI_OP(a,b,dest,src1,src2) b,
16 #define MINI_OP3(a,b,dest,src1,src2,src3) b,
17 /* keep in sync with the enum in mini.h */
18 static const char* const
19 opnames[] = {
20 #include "mini-ops.h"
22 #undef MINI_OP
23 #undef MINI_OP3
26 * Duplicate this from helpers.c, so the opcode name array can be omitted when
27 * DISABLE_JIT is set.
29 static const char*
30 inst_name (int op) {
31 if (op >= OP_LOAD && op <= OP_LAST)
32 return opnames [op - OP_LOAD];
33 if (op < OP_LOAD)
34 return mono_opcode_name (op);
35 g_error ("unknown opcode name for %d", op);
36 return NULL;
39 typedef struct {
40 int num;
41 const char *name;
42 char *desc;
43 char *comment;
44 MonoInstSpec spec;
45 } OpDesc;
47 static int nacl = 0;
48 static GHashTable *table;
49 static GHashTable *template_table;
51 #define eat_whitespace(s) while (*(s) && isspace (*(s))) s++;
53 // Per spec isalnum() expects input in the range 0-255
54 // and can misbehave if you pass in a signed char.
55 static int
56 isalnum_char(char c)
58 return isalnum ((unsigned char)c);
61 static int
62 load_file (const char *name) {
63 FILE *f;
64 char buf [256];
65 char *str, *p;
66 int line;
67 OpDesc *desc;
68 GString *comment;
70 if (!(f = fopen (name, "r")))
71 g_error ("Cannot open file '%s'", name);
73 comment = g_string_new ("");
75 * The format of the lines are:
76 * # comment
77 * opcode: [dest:format] [src1:format] [src2:format] [flags:format] [clob:format]
78 * [cost:num] [res:format] [delay:num] [len:num] [nacl:num]
79 * format is a single letter that depends on the field
80 * NOTE: no space between the field name and the ':'
82 * len: maximum instruction length
84 line = 0;
85 while ((str = fgets (buf, sizeof (buf), f))) {
86 gboolean is_template = FALSE;
87 gboolean nacl_length_set = FALSE;
89 ++line;
90 eat_whitespace (str);
91 if (!str [0])
92 continue;
93 if (str [0] == '#') {
94 g_string_append (comment, str);
95 continue;
97 p = strchr (str, '#');
98 if (p)
99 *p = 0;
100 p = strchr (str, ':');
101 if (!p)
102 g_error ("Invalid format at line %d in %s\n", line, name);
103 *p++ = 0;
104 eat_whitespace (p);
105 if (strcmp (str, "template") == 0) {
106 is_template = TRUE;
107 desc = g_new0 (OpDesc, 1);
108 } else {
109 desc = (OpDesc *)g_hash_table_lookup (table, str);
110 if (!desc)
111 g_error ("Invalid opcode '%s' at line %d in %s\n", str, line, name);
112 if (desc->desc)
113 g_error ("Duplicated opcode %s at line %d in %s\n", str, line, name);
115 desc->desc = g_strdup (p);
116 desc->comment = g_strdup (comment->str);
117 g_string_truncate (comment, 0);
118 while (*p) {
119 if (strncmp (p, "dest:", 5) == 0) {
120 desc->spec.dest = p [5];
121 p += 6;
122 } else if (strncmp (p, "src1:", 5) == 0) {
123 desc->spec.src1 = p [5];
124 p += 6;
125 } else if (strncmp (p, "src2:", 5) == 0) {
126 desc->spec.src2 = p [5];
127 p += 6;
128 } else if (strncmp (p, "src3:", 5) == 0) {
129 desc->spec.src3 = p [5];
130 p += 6;
131 } else if (strncmp (p, "clob:", 5) == 0) {
132 desc->spec.clob = p [5];
133 p += 6;
134 /* Currently unused fields
135 } else if (strncmp (p, "cost:", 5) == 0) {
136 desc->spec.cost = p [5];
137 p += 6;
138 } else if (strncmp (p, "res:", 4) == 0) {
139 desc->spec.res = p [4];
140 p += 5;
141 } else if (strncmp (p, "flags:", 6) == 0) {
142 desc->spec.flags = p [6];
143 p += 7;
144 } else if (strncmp (p, "delay:", 6) == 0) {
145 desc->spec.delay = p [6];
146 p += 7;
148 } else if (strncmp (p, "len:", 4) == 0) {
149 unsigned long size;
150 char* endptr;
151 p += 4;
152 size = strtoul (p, &endptr, 10);
153 if (size == 0 && p == endptr)
154 g_error ("Invalid length '%s' at line %d in %s\n", p, line, name);
155 p = endptr;
156 if (!nacl_length_set) {
157 desc->spec.len = size;
159 } else if (strncmp (p, "nacl:", 5) == 0) {
160 unsigned long size;
161 p += 5;
162 size = strtoul (p, &p, 10);
163 if (nacl) {
164 desc->spec.len = size;
165 nacl_length_set = TRUE;
167 } else if (strncmp (p, "template:", 9) == 0) {
168 char *tname;
169 int i;
170 OpDesc *tdesc;
171 p += 9;
172 tname = p;
173 while (*p && isalnum_char (*p)) ++p;
174 *p++ = 0;
175 tdesc = (OpDesc *)g_hash_table_lookup (template_table, tname);
176 if (!tdesc)
177 g_error ("Invalid template name %s at '%s' at line %d in %s\n", tname, p, line, name);
178 for (i = 0; i < MONO_INST_MAX; ++i) {
179 if (desc->spec.bytes [i])
180 g_error ("The template overrides any previous value set at line %d in %s\n", line, name);
182 desc->spec = tdesc->spec;
183 } else if (strncmp (p, "name:", 5) == 0) {
184 char *tname;
185 if (!is_template)
186 g_error ("name tag only valid in templates at '%s' at line %d in %s\n", p, line, name);
187 if (desc->name)
188 g_error ("Duplicated name tag in template %s at '%s' at line %d in %s\n", desc->name, p, line, name);
189 p += 5;
190 tname = p;
191 while (*p && isalnum_char (*p)) ++p;
192 *p++ = 0;
193 if (g_hash_table_lookup (template_table, tname))
194 g_error ("Duplicated template %s at line %d in %s\n", tname, line, name);
195 desc->name = g_strdup (tname);
196 g_hash_table_insert (template_table, (void*)desc->name, desc);
197 } else {
198 g_error ("Parse error at '%s' at line %d in %s\n", p, line, name);
200 eat_whitespace (p);
202 if (is_template && !desc->name)
203 g_error ("Template without name at line %d in %s\n", line, name);
205 g_string_free (comment,TRUE);
206 fclose (f);
207 return 0;
210 static OpDesc *opcodes = NULL;
212 static void
213 init_table (void) {
214 int i;
215 OpDesc *desc;
217 template_table = g_hash_table_new (g_str_hash, g_str_equal);
218 table = g_hash_table_new (g_str_hash, g_str_equal);
220 opcodes = g_new0 (OpDesc, OP_LAST);
221 for (i = OP_LOAD; i < OP_LAST; ++i) {
222 desc = opcodes + i;
223 desc->num = i;
224 desc->name = inst_name (i);
225 g_hash_table_insert (table, (char *)desc->name, desc);
229 static void
230 output_char (FILE *f, char c) {
231 if (isalnum_char (c))
232 fprintf (f, " '%c'", c);
233 else if (c < 9)
234 fprintf (f, " %u", (guint8)c);
235 else
236 fprintf (f, "0x%02X", (guint8)c);
239 static void
240 build_table (const char *fname, const char *name) {
241 FILE *f;
242 int i, j, idx;
243 OpDesc *desc;
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 MonoInstSpec mono_%s [ ] = {\n {{", name);
252 for (j = 0; j < MONO_INST_MAX; ++j)
253 fprintf (f, "0%s", (j < MONO_INST_MAX - 1) ? ", " : "");
254 fprintf (f, "}}, // null entry\n");
255 idx = 1;
256 g_string_append_printf (idx_array, "const guint16 mono_%s_idx [] = {\n", name);
258 int row = 40;
260 for (i = OP_LOAD; i < OP_LAST; ++i) {
261 if (row == 40) {
262 fprintf (f, "// dest src1 src2 src3 len clob\n");
263 fprintf (f, "// ----- ----- ----- ---- ----- -----\n");
264 row = 0;
265 } else
266 row += 1;
267 desc = opcodes + i;
268 if (!desc->desc)
269 g_string_append_printf (idx_array, " 0, // %s\n", desc->name ? desc->name : "");
270 else {
271 fprintf (f, " {{");
272 for (j = 0; j < MONO_INST_MAX; ++j) {
273 output_char (f, desc->spec.bytes [j]);
274 if (j < MONO_INST_MAX - 1)
275 fprintf (f, ", ");
277 fprintf (f, " }}, // %s\n", desc->name);
278 g_string_append_printf (idx_array, " %d, // %s\n", idx, desc->name);
279 ++idx;
282 fprintf (f, "};\n\n");
283 fprintf (f, "%s};\n\n", idx_array->str);
284 fclose (f);
285 g_string_free (idx_array, TRUE);
286 g_hash_table_destroy (desc_ht);
289 static void
290 dump (void) {
291 int i;
292 OpDesc *desc;
294 for (i = 0; i < MONO_CEE_LAST; ++i) {
295 desc = opcodes + i;
296 if (desc->comment)
297 g_print ("%s", desc->comment);
298 if (!desc->desc)
299 g_print ("%s:\n", desc->name);
300 else {
301 g_print ("%s: %s", desc->name, desc->desc);
302 if (!strchr (desc->desc, '\n'))
303 g_print ("\n");
306 for (i = OP_LOAD; i < OP_LAST; ++i) {
307 desc = opcodes + i;
308 if (!desc->desc)
309 g_print ("%s:\n", desc->name);
310 else {
311 g_print ("%s: %s", desc->name, desc->desc);
312 if (!strchr (desc->desc, '\n'))
313 g_print ("\n");
319 * TODO: output the table (possibly merged), in the input format
321 int
322 main (int argc, char* argv [])
324 init_table ();
325 if (argc == 2) {
326 /* useful to get a new file when some opcodes are added: looses the comments, though */
327 load_file (argv [1]);
328 dump ();
329 } else if (argc < 4) {
330 g_print ("Usage: genmdesc arguments\n");
331 g_print ("\tgenmdesc desc Output to stdout the description file.\n");
332 g_print ("\tgenmdesc [--nacl] output name desc [desc1...]\n"
333 " Write to output the description in a table named 'name',\n"
334 " use --nacl to generate Google NativeClient code\n");
335 return 1;
336 } else {
337 int i = 3;
338 if (strcmp (argv [1], "--nacl") == 0) {
339 nacl = 1;
340 i++;
343 for (; i < argc; ++i)
344 load_file (argv [i]);
346 build_table (argv [1 + nacl], argv [2 + nacl]);
348 return 0;