filename | src/tools/gendec.c |
changeset | 1084:852412cf56e0 |
prev | 979:2cc7b486ea6c |
next | 1296:30ecee61f811 |
author | nkeynes |
date | Thu Feb 23 15:24:47 2012 +1000 (11 years ago) |
permissions | -rw-r--r-- |
last change | Check for existence of glDrawBuffer (assuming that glReadBuffer will follow). Note only need to guard the common code in gl_fbo.c |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 *
4 * Parse the instruction and action files and generate an appropriate
5 * instruction decoder.
6 *
7 * Copyright (c) 2005 Nathan Keynes.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 */
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <getopt.h>
24 #include <errno.h>
25 #include <ctype.h>
26 #include <glib/gstrfuncs.h>
27 #include <assert.h>
28 #include "tools/gendec.h"
30 #define DEFAULT_OUT_EXT ".c"
32 const char *ins_filename = NULL;
33 const char *act_filename = NULL;
34 const char *out_filename = NULL;
36 #define GEN_SOURCE 1
37 #define GEN_TEMPLATE 2
39 FILE *ins_file, *act_file, *out_file;
41 char *option_list = "tmho:w";
42 int gen_mode = GEN_SOURCE;
43 int emit_warnings = 0;
45 struct option longopts[] = {
46 { "help", no_argument, NULL, 'h' },
47 { "output", required_argument, NULL, 'o' },
48 { "template", no_argument, NULL, 't' },
49 { "warnings", no_argument, NULL, 'w' },
50 { NULL, 0, 0, 0 } };
52 static void usage() {
53 printf( "Usage: gendec [options] <instruction-file> <action-file> [ -o <output-file> ]\n" );
54 printf( "Options:\n" );
55 printf( " -h, --help Print this help message\n" );
56 printf( " -o, --output=FILE Generate output to the given file\n" );
57 printf( " -t, --template Generate a template skeleton instead of an instruction matcher\n" );
58 printf( " -w, --warnings Emit warnings when unmatched instructions are found\n" );
59 }
61 /**
62 * Check that rules are provided for all actions
63 */
64 static void check_actions( struct ruleset *rules, const actiontoken_t token )
65 {
66 int i;
67 int warnings = 0;
68 for( i=0; i<rules->rule_count; i++ ) {
69 if( token->actions[i].text == NULL ) {
70 if( warnings == 0 ) {
71 fprintf( stderr, "In action block starting at line %d of file %s:\n",
72 token->lineno, token->filename );
73 }
74 fprintf( stderr, "Warning: No action matches rule %d %s\n", i, rules->rules[i]->format );
75 warnings++;
76 } else {
77 const char *s = token->actions[i].text;
78 while( *s ) {
79 if( !isspace(*s) )
80 break;
81 s++;
82 }
83 if( !*s ) {
84 if( warnings == 0 ) {
85 fprintf( stderr, "In action block starting at line %d of file %s:\n",
86 token->lineno, token->filename );
87 }
88 fprintf( stderr, "Warning: Empty action for rule %d %s at line %d\n", i, rules->rules[i]->format,
89 token->actions[i].lineno );
90 warnings++;
91 }
92 }
93 }
94 }
96 /**
97 * Find a mask that can be used to split up the given rules
98 */
99 static uint32_t find_mask( struct ruleset *rules, int ruleidx[], int rule_count,
100 uint32_t input_mask )
101 {
102 int i;
103 uint32_t mask = rules->rules[ruleidx[0]]->mask;
105 for( i=1; i<rule_count; i++ ) {
106 mask = mask & rules->rules[ruleidx[i]]->mask;
107 }
109 assert( (mask & input_mask) == input_mask ); /* input_mask should always be included in the mask */
111 return mask & (~input_mask); /* but we don't want to see the input mask again */
112 }
114 static int get_option_count_for_mask( uint32_t mask ) {
115 int count = 0;
117 while( mask ) {
118 if( mask&1 )
119 count++;
120 mask >>= 1;
121 }
122 return 1<<count;
123 }
125 int get_bitshift_for_mask( uint32_t mask ) {
126 int shift = 0;
127 while( mask && !(mask&1) ) {
128 shift++;
129 mask >>= 1;
130 }
131 return shift;
132 }
134 static void get_option_values_for_mask( uint32_t *options,
135 uint32_t mask )
136 {
137 /* This could be a lot smarter. But it's not */
138 int i;
139 *options = 0;
140 for( i=1; i<=mask; i++ ) {
141 if( (i & mask) > *options ) {
142 options++;
143 *options = (i&mask);
144 }
145 }
146 }
148 static void fprint_indent( const char *action, int depth, FILE *f )
149 {
150 int spaces = 0, needed = depth*8, i;
151 const char *text = action;
153 /* Determine number of spaces in first line of input */
154 for( i=0; isspace(action[i]); i++ ) {
155 if( action[i] == '\n' ) {
156 spaces = 0;
157 text = &action[i+1];
158 } else {
159 spaces++;
160 }
161 }
163 needed -= spaces;
164 fprintf( f, "%*c", needed, ' ' );
165 for( i=0; text[i] != '\0'; i++ ) {
166 fputc( text[i], f );
167 if( text[i] == '\n' && text[i+1] != '\0' ) {
168 fprintf( f, "%*c", needed, ' ' );
169 }
170 }
171 if( text[i-1] != '\n' ) {
172 fprintf( f, "\n" );
173 }
174 }
176 static void fprint_action( struct rule *rule, const struct action *action, int depth, FILE *f )
177 {
178 int i;
179 if( action == NULL ) {
180 fprintf( f, "%*cUNIMP(ir); /* %s */\n", depth*8, ' ', rule->format );
181 } else {
182 fprintf( f, "%*c{ /* %s */", depth*8, ' ', rule->format );
183 if( rule->operand_count != 0 ) {
184 fprintf( f, "\n%*c", depth*8, ' ' );
185 for( i=0; i<rule->operand_count; i++ ) {
186 if( rule->operands[i].is_signed ) {
187 fprintf( f, "int32_t %s = SIGNEXT%d", rule->operands[i].name, rule->operands[i].bit_count );
188 } else {
189 fprintf( f, "uint32_t %s = ", rule->operands[i].name );
190 }
191 if( rule->operands[i].bit_shift == 0 ) {
192 fprintf( f, "(ir&0x%X)", (1<<(rule->operands[i].bit_count))-1 );
193 } else {
194 fprintf( f, "((ir>>%d)&0x%X)", rule->operands[i].bit_shift,
195 (1<<(rule->operands[i].bit_count))-1 );
196 }
197 if( rule->operands[i].left_shift != 0 ) {
198 fprintf( f, "<<%d", rule->operands[i].left_shift );
199 }
200 fprintf( f, "; " );
201 }
202 }
203 fputs( "\n", f );
204 if( action->text && action->text[0] != '\0' ) {
205 fprintf( f, "#line %d \"%s\"\n", action->lineno, action->filename );
206 fprint_indent( action->text, depth, f );
207 }
208 fprintf( f, "%*c}\n", depth*8, ' ' );
209 }
210 }
212 static void split_and_generate( struct ruleset *rules, const struct action *actions,
213 int ruleidx[], int rule_count, int input_mask,
214 int depth, FILE *f ) {
215 uint32_t mask;
216 int i,j;
218 if( rule_count == 0 ) {
219 fprintf( f, "%*cUNDEF(ir);\n", depth*8, ' ' );
220 } else if( rule_count == 1 ) {
221 fprint_action( rules->rules[ruleidx[0]], &actions[ruleidx[0]], depth, f );
222 } else {
224 mask = find_mask(rules, ruleidx, rule_count, input_mask);
225 if( mask == 0 ) { /* No matching mask? */
226 fprintf( stderr, "Error: unable to find a valid bitmask (%d rules, %08X input mask)\n", rule_count, input_mask );
227 dump_rulesubset( rules, ruleidx, rule_count, stderr );
228 return;
229 }
231 /* break up the rules into sub-sets, and process each sub-set.
232 * NB: We could do this in one pass at the cost of more complex
233 * data structures. For now though, this keeps it simple
234 */
235 int option_count = get_option_count_for_mask( mask );
236 uint32_t options[option_count];
237 int subruleidx[rule_count];
238 int subrule_count;
239 int mask_shift = get_bitshift_for_mask( mask );
240 int has_empty_options = 0;
241 get_option_values_for_mask( options, mask );
243 if( mask_shift == 0 ) {
244 fprintf( f, "%*cswitch( ir&0x%X ) {\n", depth*8, ' ', mask );
245 } else {
246 fprintf( f, "%*cswitch( (ir&0x%X) >> %d ) {\n", depth*8, ' ',
247 mask, mask_shift);
248 }
249 for( i=0; i<option_count; i++ ) {
250 subrule_count = 0;
251 for( j=0; j<rule_count; j++ ) {
252 int match = rules->rules[ruleidx[j]]->bits & mask;
253 if( match == options[i] ) {
254 subruleidx[subrule_count++] = ruleidx[j];
255 }
256 }
257 if( subrule_count == 0 ) {
258 has_empty_options = 1;
259 } else {
260 fprintf( f, "%*ccase 0x%X:\n", depth*8+4, ' ', options[i]>>mask_shift );
261 split_and_generate( rules, actions, subruleidx, subrule_count,
262 mask|input_mask, depth+1, f );
263 fprintf( f, "%*cbreak;\n", depth*8+8, ' ' );
264 }
265 }
266 if( has_empty_options ) {
267 fprintf( f, "%*cdefault:\n%*cUNDEF(ir);\n%*cbreak;\n",
268 depth*8+4, ' ', depth*8+8, ' ', depth*8 + 8, ' ' );
269 }
270 fprintf( f, "%*c}\n", depth*8, ' ' );
271 }
272 }
274 static int generate_decoder( struct ruleset *rules, actionfile_t af, FILE *out )
275 {
276 int ruleidx[rules->rule_count];
277 int i;
279 for( i=0; i<rules->rule_count; i++ ) {
280 ruleidx[i] = i;
281 }
283 actiontoken_t token = action_file_next(af);
284 while( token->symbol != END ) {
285 if( token->symbol == TEXT ) {
286 fprintf( out, "#line %d \"%s\"\n", token->lineno, token->filename );
287 fputs( token->text, out );
288 } else if( token->symbol == ERROR ) {
289 fprintf( stderr, "Error parsing action file" );
290 return -1;
291 } else {
292 if( emit_warnings ) {
293 check_actions( rules, token );
294 }
295 split_and_generate( rules, token->actions, ruleidx, rules->rule_count, 0, 1, out );
296 }
297 token = action_file_next(af);
298 }
299 return 0;
300 }
302 static int generate_template( struct ruleset *rules, actionfile_t af, FILE *out )
303 {
304 int i;
306 actiontoken_t token = action_file_next(af);
307 while( token->symbol != END ) {
308 if( token->symbol == TEXT ) {
309 fputs( token->text, out );
310 } else if( token->symbol == ERROR ) {
311 fprintf( stderr, "Error parsing action file" );
312 return -1;
313 } else {
314 fputs( "%%\n", out );
315 for( i=0; i<rules->rule_count; i++ ) {
316 fprintf( out, "%s {: %s :}\n", rules->rules[i]->format,
317 token->actions[i].text == NULL ? "" : token->actions[i].text );
318 }
319 fputs( "%%\n", out );
320 }
321 token = action_file_next(af);
322 }
324 return 0;
325 }
328 int main( int argc, char *argv[] )
329 {
330 int opt;
332 /* Parse the command line */
333 while( (opt = getopt_long( argc, argv, option_list, longopts, NULL )) != -1 ) {
334 switch( opt ) {
335 case 't':
336 gen_mode = GEN_TEMPLATE;
337 break;
338 case 'o':
339 out_filename = optarg;
340 break;
341 case 'w':
342 emit_warnings = 1;
343 break;
344 case 'h':
345 usage();
346 exit(0);
347 }
348 }
349 if( optind < argc ) {
350 ins_filename = argv[optind++];
351 }
352 if( optind < argc ) {
353 act_filename = argv[optind++];
354 }
356 if( optind < argc || ins_filename == NULL || act_filename == NULL ) {
357 usage();
358 exit(1);
359 }
361 if( out_filename == NULL ) {
362 if( gen_mode == GEN_TEMPLATE ) {
363 out_filename = act_filename;
364 } else {
365 char tmp[strlen(act_filename)+1];
366 strcpy( tmp, act_filename);
367 char *c = strrchr( tmp, '.' );
368 if( c != NULL ) {
369 *c = '\0';
370 }
371 out_filename = g_strconcat( tmp, DEFAULT_OUT_EXT, NULL );
372 }
373 }
375 /* Open the files */
376 ins_file = fopen( ins_filename, "ro" );
377 if( ins_file == NULL ) {
378 fprintf( stderr, "Unable to open '%s' for reading (%s)\n", ins_filename, strerror(errno) );
379 exit(2);
380 }
382 /* Parse the input */
383 struct ruleset *rules = parse_ruleset_file( ins_file );
384 fclose( ins_file );
385 if( rules == NULL ) {
386 exit(5);
387 }
389 actionfile_t af = action_file_open( act_filename, rules );
390 if( af == NULL ) {
391 fprintf( stderr, "Unable to open '%s' for reading (%s)\n", act_filename, strerror(errno) );
392 exit(3);
393 }
396 /* Open the output file */
397 out_file = fopen( out_filename, "wo" );
398 if( out_file == NULL ) {
399 fprintf( stderr, "Unable to open '%s' for writing (%s)\n", out_filename, strerror(errno) );
400 exit(4);
401 }
403 switch( gen_mode ) {
404 case GEN_SOURCE:
405 if( generate_decoder( rules, af, out_file ) != 0 ) {
406 exit(7);
407 }
408 break;
409 case GEN_TEMPLATE:
410 if( generate_template( rules, af, out_file ) != 0 ) {
411 exit(7);
412 }
413 break;
414 }
416 action_file_close(af);
417 fclose( out_file );
418 return 0;
419 }
.