3 * Generates the machine description
6 * Paolo Molaro (lupus@ximian.com)
8 * (C) 2003 Ximian, Inc.
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
26 * Duplicate this from helpers.c, so the opcode name array can be omitted when
31 if (op
>= OP_LOAD
&& op
<= OP_LAST
)
32 return opnames
[op
- OP_LOAD
];
34 return mono_opcode_name (op
);
35 g_error ("unknown opcode name for %d", op
);
44 char spec
[MONO_INST_MAX
];
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.
58 return isalnum ((unsigned char)c
);
62 load_file (const char *name
) {
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:
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
85 while ((str
= fgets (buf
, sizeof (buf
), f
))) {
86 gboolean is_template
= FALSE
;
87 gboolean nacl_length_set
= FALSE
;
94 g_string_append (comment
, str
);
97 p
= strchr (str
, '#');
100 p
= strchr (str
, ':');
102 g_error ("Invalid format at line %d in %s\n", line
, name
);
105 if (strcmp (str
, "template") == 0) {
107 desc
= g_new0 (OpDesc
, 1);
109 desc
= (OpDesc
*)g_hash_table_lookup (table
, str
);
111 g_error ("Invalid opcode '%s' at line %d in %s\n", str
, line
, name
);
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);
119 if (strncmp (p
, "dest:", 5) == 0) {
120 desc
->spec
[MONO_INST_DEST
] = p
[5];
122 } else if (strncmp (p
, "src1:", 5) == 0) {
123 desc
->spec
[MONO_INST_SRC1
] = p
[5];
125 } else if (strncmp (p
, "src2:", 5) == 0) {
126 desc
->spec
[MONO_INST_SRC2
] = p
[5];
128 } else if (strncmp (p
, "src3:", 5) == 0) {
129 desc
->spec
[MONO_INST_SRC3
] = p
[5];
131 } else if (strncmp (p
, "clob:", 5) == 0) {
132 desc
->spec
[MONO_INST_CLOB
] = p
[5];
134 /* Currently unused fields
135 } else if (strncmp (p, "cost:", 5) == 0) {
136 desc->spec [MONO_INST_COST] = p [5];
138 } else if (strncmp (p, "res:", 4) == 0) {
139 desc->spec [MONO_INST_RES] = p [4];
141 } else if (strncmp (p, "flags:", 6) == 0) {
142 desc->spec [MONO_INST_FLAGS] = p [6];
144 } else if (strncmp (p, "delay:", 6) == 0) {
145 desc->spec [MONO_INST_DELAY] = p [6];
148 } else if (strncmp (p
, "len:", 4) == 0) {
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
);
156 if (!nacl_length_set
) {
157 desc
->spec
[MONO_INST_LEN
] = size
;
159 } else if (strncmp (p
, "nacl:", 5) == 0) {
162 size
= strtoul (p
, &p
, 10);
164 desc
->spec
[MONO_INST_LEN
] = size
;
165 nacl_length_set
= TRUE
;
167 } else if (strncmp (p
, "template:", 9) == 0) {
173 while (*p
&& isalnum_char (*p
)) ++p
;
175 tdesc
= (OpDesc
*)g_hash_table_lookup (template_table
, tname
);
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
) {
180 g_error ("The template overrides any previous value set at line %d in %s\n", line
, name
);
182 memcpy (desc
->spec
, tdesc
->spec
, sizeof (desc
->spec
));
183 } else if (strncmp (p
, "name:", 5) == 0) {
186 g_error ("name tag only valid in templates at '%s' at line %d in %s\n", p
, line
, name
);
188 g_error ("Duplicated name tag in template %s at '%s' at line %d in %s\n", desc
->name
, p
, line
, name
);
191 while (*p
&& isalnum_char (*p
)) ++p
;
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
);
198 g_error ("Parse error at '%s' at line %d in %s\n", p
, line
, name
);
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
);
210 static OpDesc
*opcodes
= NULL
;
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
) {
224 desc
->name
= inst_name (i
);
225 g_hash_table_insert (table
, (char *)desc
->name
, desc
);
230 output_char (FILE *f
, char c
) {
231 if (isalnum_char (c
))
232 fprintf (f
, "%c", c
);
234 fprintf (f
, "\\x%x\" \"", (guint8
)c
);
238 build_table (const char *fname
, const char *name
) {
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
);
251 for (j
= 0; j
< MONO_INST_MAX
; ++j
)
253 fprintf (f
, "\"\t/* null entry */\n");
255 g_string_append_printf (idx_array
, "const guint16 mono_%s_idx [] = {\n", name
);
257 for (i
= OP_LOAD
; i
< OP_LAST
; ++i
) {
260 g_string_append_printf (idx_array
, "\t0,\t/* %s */\n", desc
->name
? desc
->name
: "");
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
);
270 fprintf (f
, "};\n\n");
271 fprintf (f
, "%s};\n\n", idx_array
->str
);
273 g_string_free (idx_array
, TRUE
);
274 g_hash_table_destroy (desc_ht
);
282 for (i
= 0; i
< MONO_CEE_LAST
; ++i
) {
285 g_print ("%s", desc
->comment
);
287 g_print ("%s:\n", desc
->name
);
289 g_print ("%s: %s", desc
->name
, desc
->desc
);
290 if (!strchr (desc
->desc
, '\n'))
294 for (i
= OP_LOAD
; i
< OP_LAST
; ++i
) {
297 g_print ("%s:\n", desc
->name
);
299 g_print ("%s: %s", desc
->name
, desc
->desc
);
300 if (!strchr (desc
->desc
, '\n'))
307 * TODO: output the table (possibly merged), in the input format
310 main (int argc
, char* argv
[])
314 /* useful to get a new file when some opcodes are added: looses the comments, though */
315 load_file (argv
[1]);
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");
326 if (strcmp (argv
[1], "--nacl") == 0) {
331 for (; i
< argc
; ++i
)
332 load_file (argv
[i
]);
334 build_table (argv
[1 + nacl
], argv
[2 + nacl
]);