Fix debug Windows builds in MSVC 2015
[mono-project.git] / mono / mini / genmdesc.c
blob7118e19c8cec06cd9fb7588d5e7c89f2e9564706
1 /*
2 * genmdesc: Generates the machine description
4 * Authors:
5 * Paolo Molaro (lupus@ximian.com)
7 * (C) 2003 Ximian, Inc.
8 */
9 #include "mini.h"
10 #include <ctype.h>
11 #include <string.h>
12 #include <mono/metadata/opcodes.h>
14 #if defined(__native_client__) || defined(__native_client_codegen__)
15 volatile int __nacl_thread_suspension_needed = 0;
16 void __nacl_suspend_thread_if_needed() {}
17 #endif
19 #define MINI_OP(a,b,dest,src1,src2) b,
20 #define MINI_OP3(a,b,dest,src1,src2,src3) b,
21 /* keep in sync with the enum in mini.h */
22 static const char* const
23 opnames[] = {
24 #include "mini-ops.h"
26 #undef MINI_OP
27 #undef MINI_OP3
30 * Duplicate this from helpers.c, so the opcode name array can be omitted when
31 * DISABLE_JIT is set.
33 static const char*
34 inst_name (int op) {
35 if (op >= OP_LOAD && op <= OP_LAST)
36 return opnames [op - OP_LOAD];
37 if (op < OP_LOAD)
38 return mono_opcode_name (op);
39 g_error ("unknown opcode name for %d", op);
40 return NULL;
43 typedef struct {
44 int num;
45 const char *name;
46 char *desc;
47 char *comment;
48 char spec [MONO_INST_MAX];
49 } OpDesc;
51 static int nacl = 0;
52 static GHashTable *table;
53 static GHashTable *template_table;
55 #define eat_whitespace(s) while (*(s) && isspace (*(s))) s++;
57 // Per spec isalnum() expects input in the range 0-255
58 // and can misbehave if you pass in a signed char.
59 static int
60 isalnum_char(char c)
62 return isalnum ((unsigned char)c);
65 static int
66 load_file (const char *name) {
67 FILE *f;
68 char buf [256];
69 char *str, *p;
70 int line;
71 OpDesc *desc;
72 GString *comment;
74 if (!(f = fopen (name, "r")))
75 g_error ("Cannot open file '%s'", name);
77 comment = g_string_new ("");
79 * The format of the lines are:
80 * # comment
81 * opcode: [dest:format] [src1:format] [src2:format] [flags:format] [clob:format]
82 * [cost:num] [res:format] [delay:num] [len:num] [nacl:num]
83 * format is a single letter that depends on the field
84 * NOTE: no space between the field name and the ':'
86 * len: maximum instruction length
88 line = 0;
89 while ((str = fgets (buf, sizeof (buf), f))) {
90 gboolean is_template = FALSE;
91 gboolean nacl_length_set = FALSE;
93 ++line;
94 eat_whitespace (str);
95 if (!str [0])
96 continue;
97 if (str [0] == '#') {
98 g_string_append (comment, str);
99 continue;
101 p = strchr (str, ':');
102 if (!p)
103 g_error ("Invalid format at line %d in %s\n", line, name);
104 *p++ = 0;
105 eat_whitespace (p);
106 if (strcmp (str, "template") == 0) {
107 is_template = TRUE;
108 desc = g_new0 (OpDesc, 1);
109 } else {
110 desc = (OpDesc *)g_hash_table_lookup (table, str);
111 if (!desc)
112 g_error ("Invalid opcode '%s' at line %d in %s\n", str, line, name);
113 if (desc->desc)
114 g_error ("Duplicated opcode %s at line %d in %s\n", str, line, name);
116 desc->desc = g_strdup (p);
117 desc->comment = g_strdup (comment->str);
118 g_string_truncate (comment, 0);
119 while (*p) {
120 if (strncmp (p, "dest:", 5) == 0) {
121 desc->spec [MONO_INST_DEST] = p [5];
122 p += 6;
123 } else if (strncmp (p, "src1:", 5) == 0) {
124 desc->spec [MONO_INST_SRC1] = p [5];
125 p += 6;
126 } else if (strncmp (p, "src2:", 5) == 0) {
127 desc->spec [MONO_INST_SRC2] = p [5];
128 p += 6;
129 } else if (strncmp (p, "src3:", 5) == 0) {
130 desc->spec [MONO_INST_SRC3] = p [5];
131 p += 6;
132 } else if (strncmp (p, "clob:", 5) == 0) {
133 desc->spec [MONO_INST_CLOB] = p [5];
134 p += 6;
135 /* Currently unused fields
136 } else if (strncmp (p, "cost:", 5) == 0) {
137 desc->spec [MONO_INST_COST] = p [5];
138 p += 6;
139 } else if (strncmp (p, "res:", 4) == 0) {
140 desc->spec [MONO_INST_RES] = p [4];
141 p += 5;
142 } else if (strncmp (p, "flags:", 6) == 0) {
143 desc->spec [MONO_INST_FLAGS] = p [6];
144 p += 7;
145 } else if (strncmp (p, "delay:", 6) == 0) {
146 desc->spec [MONO_INST_DELAY] = p [6];
147 p += 7;
149 } else if (strncmp (p, "len:", 4) == 0) {
150 unsigned long size;
151 char* endptr;
152 p += 4;
153 size = strtoul (p, &endptr, 10);
154 if (size == 0 && p == endptr)
155 g_error ("Invalid length '%s' at line %d in %s\n", p, line, name);
156 p = endptr;
157 if (!nacl_length_set) {
158 desc->spec [MONO_INST_LEN] = size;
160 } else if (strncmp (p, "nacl:", 5) == 0) {
161 unsigned long size;
162 p += 5;
163 size = strtoul (p, &p, 10);
164 if (nacl) {
165 desc->spec [MONO_INST_LEN] = size;
166 nacl_length_set = TRUE;
168 } else if (strncmp (p, "template:", 9) == 0) {
169 char *tname;
170 int i;
171 OpDesc *tdesc;
172 p += 9;
173 tname = p;
174 while (*p && isalnum_char (*p)) ++p;
175 *p++ = 0;
176 tdesc = (OpDesc *)g_hash_table_lookup (template_table, tname);
177 if (!tdesc)
178 g_error ("Invalid template name %s at '%s' at line %d in %s\n", tname, p, line, name);
179 for (i = 0; i < MONO_INST_MAX; ++i) {
180 if (desc->spec [i])
181 g_error ("The template overrides any previous value set at line %d in %s\n", line, name);
183 memcpy (desc->spec, tdesc->spec, sizeof (desc->spec));
184 } else if (strncmp (p, "name:", 5) == 0) {
185 char *tname;
186 if (!is_template)
187 g_error ("name tag only valid in templates at '%s' at line %d in %s\n", p, line, name);
188 if (desc->name)
189 g_error ("Duplicated name tag in template %s at '%s' at line %d in %s\n", desc->name, p, line, name);
190 p += 5;
191 tname = p;
192 while (*p && isalnum_char (*p)) ++p;
193 *p++ = 0;
194 if (g_hash_table_lookup (template_table, tname))
195 g_error ("Duplicated template %s at line %d in %s\n", tname, line, name);
196 desc->name = g_strdup (tname);
197 g_hash_table_insert (template_table, (void*)desc->name, desc);
198 } else {
199 g_error ("Parse error at '%s' at line %d in %s\n", p, line, name);
201 eat_whitespace (p);
203 if (is_template && !desc->name)
204 g_error ("Template without name at line %d in %s\n", line, name);
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
234 fprintf (f, "\\x%x\" \"", (guint8)c);
237 static void
238 build_table (const char *fname, const char *name) {
239 FILE *f;
240 int i, j, idx;
241 OpDesc *desc;
242 GString *idx_array = g_string_new ("");
243 /* use this to remove duplicates */
244 GHashTable *desc_ht = g_hash_table_new (g_str_hash, g_str_equal);
246 if (!(f = fopen (fname, "w")))
247 g_error ("Cannot open file '%s'", fname);
248 fprintf (f, "/* File automatically generated by genmdesc, don't change */\n\n");
249 fprintf (f, "const char mono_%s [] = {\n", name);
250 fprintf (f, "\t\"");
251 for (j = 0; j < MONO_INST_MAX; ++j)
252 fprintf (f, "\\x0");
253 fprintf (f, "\"\t/* null entry */\n");
254 idx = 1;
255 g_string_append_printf (idx_array, "const guint16 mono_%s_idx [] = {\n", name);
257 for (i = OP_LOAD; i < OP_LAST; ++i) {
258 desc = opcodes + i;
259 if (!desc->desc)
260 g_string_append_printf (idx_array, "\t0,\t/* %s */\n", desc->name ? desc->name : "");
261 else {
262 fprintf (f, "\t\"");
263 for (j = 0; j < MONO_INST_MAX; ++j)
264 output_char (f, desc->spec [j]);
265 fprintf (f, "\"\t/* %s */\n", desc->name);
266 g_string_append_printf (idx_array, "\t%d,\t/* %s */\n", idx * MONO_INST_MAX, desc->name);
267 ++idx;
270 fprintf (f, "};\n\n");
271 fprintf (f, "%s};\n\n", idx_array->str);
272 fclose (f);
273 g_string_free (idx_array, TRUE);
274 g_hash_table_destroy (desc_ht);
277 static void
278 dump (void) {
279 int i;
280 OpDesc *desc;
282 for (i = 0; i < MONO_CEE_LAST; ++i) {
283 desc = opcodes + i;
284 if (desc->comment)
285 g_print ("%s", desc->comment);
286 if (!desc->desc)
287 g_print ("%s:\n", desc->name);
288 else {
289 g_print ("%s: %s", desc->name, desc->desc);
290 if (!strchr (desc->desc, '\n'))
291 g_print ("\n");
294 for (i = OP_LOAD; i < OP_LAST; ++i) {
295 desc = opcodes + i;
296 if (!desc->desc)
297 g_print ("%s:\n", desc->name);
298 else {
299 g_print ("%s: %s", desc->name, desc->desc);
300 if (!strchr (desc->desc, '\n'))
301 g_print ("\n");
307 * TODO: output the table (possibly merged), in the input format
309 int
310 main (int argc, char* argv [])
312 init_table ();
313 if (argc == 2) {
314 /* useful to get a new file when some opcodes are added: looses the comments, though */
315 load_file (argv [1]);
316 dump ();
317 } else if (argc < 4) {
318 g_print ("Usage: genmdesc arguments\n");
319 g_print ("\tgenmdesc desc Output to stdout the description file.\n");
320 g_print ("\tgenmdesc [--nacl] output name desc [desc1...]\n"
321 " Write to output the description in a table named 'name',\n"
322 " use --nacl to generate Google NativeClient code\n");
323 return 1;
324 } else {
325 int i = 3;
326 if (strcmp (argv [1], "--nacl") == 0) {
327 nacl = 1;
328 i++;
331 for (; i < argc; ++i)
332 load_file (argv [i]);
334 build_table (argv [1 + nacl], argv [2 + nacl]);
336 return 0;