From b18b0e6cd3e754f60f72f71814dd213f091d37f8 Mon Sep 17 00:00:00 2001 From: Aleksey Demakov Date: Wed, 22 Mar 2006 18:48:02 +0000 Subject: [PATCH] added gen-rules tool --- ChangeLog | 7 + tools/Makefile.am | 9 +- tools/gen-rules-parser.y | 1542 +++++++++++++++++++++++++++++++++++++ tools/gen-rules-scanner.l | 286 +++++++ 4 files changed, 1842 insertions(+), 2 deletions(-) create mode 100644 tools/gen-rules-parser.y create mode 100644 tools/gen-rules-scanner.l diff --git a/ChangeLog b/ChangeLog index 9a290d5..9dc4185 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2006-03-23 Aleksey Demakov + + * tools/Makefile.am: + * tools/gen-rules-parser.y, tools/gen-rules-scanner.l: add + "gen-rules" tool that is similar to "gen-sel" but uses new + register allocator. + 2006-03-12 Klaus Treichel * jit/jit-insn.c: Pop the setjump context on return from functions with diff --git a/tools/Makefile.am b/tools/Makefile.am index 6898a15..959d824 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -1,13 +1,17 @@ -noinst_PROGRAMS = gen-apply gen-sel +noinst_PROGRAMS = gen-apply gen-rules gen-sel gen_apply_SOURCES = gen-apply.c +gen_rules_SOURCES = gen-rules-parser.y gen-rules-scanner.l + gen_sel_SOURCES = gen-sel-parser.y \ gen-sel-scanner.l AM_YFLAGS = -d +gen-rules-scanner.l: gen-rules-parser.c + gen-sel-scanner.l: gen-sel-parser.c all-local: $(top_builddir)/jit/jit-apply-rules.h @@ -19,4 +23,5 @@ AM_CFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include \ -I$(top_srcdir)/jit -I$(top_builddir)/jit CLEANFILES = $(top_builddir)/jit/jit-apply-rules.h \ - gen-sel-parser.c gen-sel-parser.h gen-sel-scanner.c + gen-rules-parser.c gen-rules-parser.h gen-rules-scanner.c \ + gen-sel-parser.c gen-sel-parser.h gen-sel-scanner.c diff --git a/tools/gen-rules-parser.y b/tools/gen-rules-parser.y new file mode 100644 index 0000000..bdb5dd9 --- /dev/null +++ b/tools/gen-rules-parser.y @@ -0,0 +1,1542 @@ +%{ +/* + * gen-rules-parser.y - Bison grammar for the "gen-rules" program. + * + * Copyright (C) 2006 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#ifdef HAVE_STRING_H + #include +#elif defined(HAVE_STRINGS_H) + #include +#endif +#ifdef HAVE_STDLIB_H + #include +#endif + +/* + * Imports from the lexical analyser. + */ +extern int yylex(void); +extern void yyrestart(FILE *file); +#ifdef YYTEXT_POINTER +extern char *yytext; +#else +extern char yytext[]; +#endif + +/* + * Current file and line number. + */ +extern char *gensel_filename; +extern long gensel_linenum; + +/* + * Report error message. + */ +static void +gensel_error_message(char *filename, long linenum, char *msg) +{ + fprintf(stderr, "%s(%ld): %s\n", filename, linenum, msg); +} + +/* + * Report error message and exit. + */ +static void +gensel_error(char *filename, long linenum, char *msg) +{ + gensel_error_message(filename, linenum, msg); + exit(1); +} + +/* + * Report error messages from the parser. + */ +static void +yyerror(char *msg) +{ + gensel_error_message(gensel_filename, gensel_linenum, msg); +} + +/* + * Instruction type for the "inst" variable. + */ +static char *gensel_inst_type = "unsigned char *"; +static int gensel_new_inst_type = 0; + +/* + * Amount of space to reserve for the primary instruction output. + */ +static int gensel_reserve_space = 32; +static int gensel_reserve_more_space = 128; + +/* + * First register in a stack arrangement. + */ +static int gensel_first_stack_reg = 8; /* st0 under x86 */ + +/* + * Maximal number of input values in a pattern. + */ +#define MAX_INPUT 3 + +/* + * Maximal number of scratch registers in a pattern. + */ +#define MAX_SCRATCH 6 + +/* + * Options. + */ +#define GENSEL_OPT_BINARY 1 +#define GENSEL_OPT_UNARY 2 +#define GENSEL_OPT_UNARY_BRANCH 3 +#define GENSEL_OPT_BINARY_BRANCH 4 +#define GENSEL_OPT_UNARY_NOTE 5 +#define GENSEL_OPT_BINARY_NOTE 6 +#define GENSEL_OPT_TERNARY 7 +#define GENSEL_OPT_STACK 8 +#define GENSEL_OPT_ONLY 9 +#define GENSEL_OPT_COMMUTATIVE 10 + +#define GENSEL_OPT_MANUAL 11 +#define GENSEL_OPT_MORE_SPACE 12 +#define GENSEL_OPT_SPILL_BEFORE 13 + +/* + * Pattern values. + */ +#define GENSEL_PATT_REG 1 +#define GENSEL_PATT_LREG 2 +#define GENSEL_PATT_FREG 3 +#define GENSEL_PATT_IMM 4 +#define GENSEL_PATT_IMMZERO 5 +#define GENSEL_PATT_IMMS8 6 +#define GENSEL_PATT_IMMU8 7 +#define GENSEL_PATT_IMMS16 8 +#define GENSEL_PATT_IMMU16 9 +#define GENSEL_PATT_LOCAL 10 +#define GENSEL_PATT_SCRATCH 11 +#define GENSEL_PATT_CLOBBER 12 +#define GENSEL_PATT_IF 13 +#define GENSEL_PATT_SPACE 14 + +/* + * Option value. + */ +typedef struct gensel_value *gensel_value_t; +struct gensel_value +{ + char *value; + gensel_value_t next; +}; + +/* + * Option information. + */ +typedef struct gensel_option *gensel_option_t; +struct gensel_option +{ + int option; + gensel_value_t values; + gensel_option_t next; +}; + +/* + * Information about clauses. + */ +typedef struct gensel_clause *gensel_clause_t; +struct gensel_clause +{ + gensel_option_t pattern; + char *filename; + long linenum; + char *code; + gensel_clause_t next; +}; + +static char *gensel_reg_names[] = { + "reg", "reg2", "reg3", "reg4", "reg5", "reg6", "reg7", "reg8", "reg9" +}; +static char *gensel_other_reg_names[] = { + "other_reg", "other_reg2", "other_reg3" +}; +static char *gensel_imm_names[] = { + "imm_value", "imm_value2", "imm_value3" +}; + +/* + * Create an option. + */ +static gensel_option_t +gensel_create_option(int option, gensel_value_t values) +{ + gensel_option_t op; + + op = (gensel_option_t) malloc(sizeof(struct gensel_option)); + if(!op) + { + exit(1); + } + + op->option = option; + op->values = values; + op->next = 0; + return op; +} + +/* + * Free a list of values. + */ +static void +gensel_free_values(gensel_value_t values) +{ + gensel_value_t next; + while(values) + { + next = values->next; + free(values->value); + free(values); + values = next; + } +} + +/* + * Free a list of options. + */ +static void +gensel_free_options(gensel_option_t options) +{ + gensel_option_t next; + while(options) + { + next = options->next; + gensel_free_values(options->values); + free(options); + options = next; + } +} + +/* + * Free a list of clauses. + */ +static void +gensel_free_clauses(gensel_clause_t clauses) +{ + gensel_clause_t next; + while(clauses != 0) + { + next = clauses->next; + gensel_free_options(clauses->pattern); + free(clauses->code); + free(clauses); + clauses = next; + } +} + +/* + * Look for the option. + */ +static gensel_option_t +gensel_search_option(gensel_option_t options, int tag) +{ + while(options && options->option != tag) + { + options = options->next; + } + return options; +} + +/* + * Declare the register variables that are needed for a set of clauses. + */ +static void gensel_declare_regs(gensel_clause_t clauses, gensel_option_t options) +{ + gensel_option_t pattern; + gensel_value_t values; + int regs, max_regs; + int other_regs_mask; + int imms, max_imms; + int have_local; + int scratch, max_scratch; + int have_clobber; + int others; + + max_regs = 0; + other_regs_mask = 0; + max_imms = 0; + have_local = 0; + max_scratch = 0; + have_clobber = 0; + while(clauses != 0) + { + regs = 0; + imms = 0; + others = 0; + scratch = 0; + pattern = clauses->pattern; + while(pattern) + { + switch(pattern->option) + { + case GENSEL_PATT_REG: + case GENSEL_PATT_FREG: + ++regs; + break; + + case GENSEL_PATT_LREG: + other_regs_mask |= (1 << regs); + ++regs; + break; + + case GENSEL_PATT_IMMZERO: + ++others; + break; + + case GENSEL_PATT_IMM: + case GENSEL_PATT_IMMS8: + case GENSEL_PATT_IMMU8: + case GENSEL_PATT_IMMS16: + case GENSEL_PATT_IMMU16: + ++imms; + break; + + case GENSEL_PATT_LOCAL: + have_local = 1; + ++others; + break; + + case GENSEL_PATT_SCRATCH: + values = pattern->values; + while(values) + { + ++scratch; + values = values->next; + } + + case GENSEL_PATT_CLOBBER: + values = pattern->values; + while(values) + { + if(values->value && strcmp(values->value, "*") != 0) + { + have_clobber = 1; + break; + } + values = values->next; + } + } + pattern = pattern->next; + } + if((regs + imms + others) > MAX_INPUT) + { + gensel_error( + clauses->filename, + clauses->linenum, + "too many input args in the pattern"); + } + if(scratch > MAX_SCRATCH) + { + gensel_error( + clauses->filename, + clauses->linenum, + "too many scratch args in the pattern"); + } + if(max_regs < regs) + { + max_regs = regs; + } + if(max_imms < imms) + { + max_imms = imms; + } + if(max_scratch < scratch) + { + max_scratch = scratch; + } + clauses = clauses->next; + } + switch(max_regs) + { + case 1: + printf("\tint reg;\n"); + break; + case 2: + printf("\tint reg, reg2;\n"); + break; + case 3: + printf("\tint reg, reg2, reg3;\n"); + break; + } + if(other_regs_mask) + { + switch(other_regs_mask) + { + case 1: + printf("\tint other_reg;\n"); + break; + case 2: + printf("\tint other_reg2;\n"); + break; + case 3: + printf("\tint other_reg, other_reg2;\n"); + break; + case 4: + printf("\tint other_reg3;\n"); + break; + case 5: + printf("\tint other_reg, othre_reg3;\n"); + break; + case 6: + printf("\tint other_reg2, othre_reg3;\n"); + break; + case 7: + printf("\tint other_reg, other_reg2, othre_reg3;\n"); + break; + } + } + switch(max_imms) + { + case 1: + printf("\tjit_nint imm_value;\n"); + break; + case 2: + printf("\tjit_nint imm_value, imm_value2;\n"); + break; + case 3: + printf("\tjit_nint imm_value, imm_value2, imm_value3;\n"); + break; + } + for(scratch = 0; scratch < max_scratch; scratch++) + { + if((scratch + max_regs) == 0) + { + printf("\tint reg;\n"); + } + else + { + printf("\tint reg%d;\n", scratch + max_regs + 1); + } + } + if(have_local) + { + printf("\tjit_nint local_offset;\n"); + } + if(have_clobber) + { + printf("\tint clobber;\n"); + } +} + +/* + * Build index of input value names. + */ +static void +gensel_build_index(gensel_option_t pattern, char *names[9], char *other_names[9]) +{ + gensel_value_t values; + int regs, imms, index; + + for(index = 0; index < 9; index++) + { + names[index] = "undefined"; + other_names[index] = "undefined"; + } + + regs = 0; + imms = 0; + index = 0; + while(pattern) + { + switch(pattern->option) + { + case GENSEL_PATT_REG: + case GENSEL_PATT_FREG: + names[index] = gensel_reg_names[regs]; + ++regs; + ++index; + break; + + case GENSEL_PATT_LREG: + names[index] = gensel_reg_names[regs]; + other_names[index] = gensel_other_reg_names[regs]; + ++regs; + ++index; + break; + + case GENSEL_PATT_IMMZERO: + ++index; + break; + + case GENSEL_PATT_IMM: + case GENSEL_PATT_IMMS8: + case GENSEL_PATT_IMMU8: + case GENSEL_PATT_IMMS16: + case GENSEL_PATT_IMMU16: + names[index] = gensel_imm_names[imms]; + ++imms; + ++index; + break; + + case GENSEL_PATT_LOCAL: + names[index] = "local_offset"; + ++index; + break; + + case GENSEL_PATT_SCRATCH: + values = pattern->values; + while(values) + { + names[index] = gensel_reg_names[regs]; + ++regs; + ++index; + values = values->next; + } + } + pattern = pattern->next; + } +} + +/* + * Output the code. + */ +static void +gensel_output_code(gensel_option_t pattern, char *code) +{ + char *names[9]; + char *other_names[9]; + int index; + + gensel_build_index(pattern, names, other_names); + + /* Output the clause code */ + printf("\t\t"); + while(*code != '\0') + { + if(*code == '$' && code[1] >= '1' && code[1] <= '9') + { + index = code[1] - '1'; + printf(names[index]); + code += 2; + } + else if(*code == '%' && code[1] >= '1' && code[1] <= '9') + { + index = code[1] - '1'; + printf(other_names[index]); + code += 2; + } + else if(*code == '\n') + { + putc(*code, stdout); + putc('\t', stdout); + ++code; + } + else + { + putc(*code, stdout); + ++code; + } + } + printf("\n"); +} + +/* + * Output the code within a clause. + */ +static void +gensel_output_clause_code(gensel_clause_t clause) +{ + /* Output the line number information from the original file */ + printf("#line %ld \"%s\"\n", clause->linenum, clause->filename); + + gensel_output_code(clause->pattern, clause->code); +} + +/* + * Output a single clause for a rule. + */ +static void gensel_output_clause(gensel_clause_t clause, gensel_option_t options) +{ + gensel_option_t space, more_space; + + /* Cache the instruction pointer into "inst" */ + if(gensel_new_inst_type) + { + printf("\t\tjit_gen_load_inst_ptr(gen, inst);\n"); + } + else + { + space = gensel_search_option(clause->pattern, GENSEL_PATT_SPACE); + more_space = gensel_search_option(options, GENSEL_OPT_MORE_SPACE); + + printf("\t\tinst = (%s)(gen->posn.ptr);\n", gensel_inst_type); + printf("\t\tif(!jit_cache_check_for_n(&(gen->posn), "); + if(space && space->values && space->values->value) + { + printf("("); + gensel_output_code(clause->pattern, space->values->value); + printf(")"); + } + else + { + printf("%d", ((more_space == 0) + ? gensel_reserve_space + : gensel_reserve_more_space)); + } + printf("))\n"); + printf("\t\t{\n"); + printf("\t\t\tjit_cache_mark_full(&(gen->posn));\n"); + printf("\t\t\treturn;\n"); + printf("\t\t}\n"); + } + + /* Output the clause code */ + gensel_output_clause_code(clause); + + /* Copy "inst" back into the generation context */ + if(gensel_new_inst_type) + { + printf("\t\tjit_gen_save_inst_ptr(gen, inst);\n"); + } + else + { + printf("\t\tgen->posn.ptr = (unsigned char *)inst;\n"); + } +} + +/* + * Output the clauses for a rule. + */ +static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t options) +{ + char *args[MAX_INPUT]; + gensel_clause_t clause; + gensel_option_t pattern; + gensel_value_t values; + int first, seen_option; + int regs, imms, index; + int scratch, clobber_all; + + /* If the clause is manual, then output it as-is */ + if(gensel_search_option(options, GENSEL_OPT_MANUAL)) + { + if(gensel_search_option(options, GENSEL_OPT_SPILL_BEFORE)) + { + printf("\t_jit_regs_spill_all(gen);\n"); + } + gensel_output_clause_code(clauses); + return; + } + + printf("\t%s inst;\n", gensel_inst_type); + printf("\t_jit_regs_t regs;\n"); + gensel_declare_regs(clauses, options); + if(gensel_search_option(options, GENSEL_OPT_SPILL_BEFORE)) + { + printf("\t_jit_regs_spill_all(gen);\n"); + } + + /* Determine the location of this instruction's arguments */ + if(gensel_search_option(options, GENSEL_OPT_TERNARY)) + { + args[0] = "dest"; + args[1] = "value1"; + args[2] = "value2"; + } + else + { + args[0] = "value1"; + args[1] = "value2"; + args[2] = "??"; + } + + /* Output the clause checking and dispatching code */ + clause = clauses; + first = 1; + while(clause != 0) + { + if(clause->next) + { + if(first) + printf("\tif("); + else + printf("\telse if("); + + index = 0; + seen_option = 0; + pattern = clause->pattern; + while(pattern && index < MAX_INPUT) + { + switch(pattern->option) + { + case GENSEL_PATT_REG: + case GENSEL_PATT_LREG: + case GENSEL_PATT_FREG: + if(index > 0 || seen_option) + { + printf(" && "); + } + printf("insn->%s->in_register", args[index]); + ++index; + break; + + case GENSEL_PATT_IMM: + if(index > 0 || seen_option) + { + printf(" && "); + } + printf("insn->%s->is_constant", args[index]); + ++index; + break; + + case GENSEL_PATT_IMMZERO: + if(index > 0 || seen_option) + { + printf(" && "); + } + printf("insn->%s->is_nint_constant && ", args[index]); + printf("insn->%s->address == 0", args[index]); + ++index; + break; + + case GENSEL_PATT_IMMS8: + if(index > 0 || seen_option) + { + printf(" && "); + } + printf("insn->%s->is_nint_constant && ", args[index]); + printf("insn->%s->address >= -128 && ", args[index]); + printf("insn->%s->address <= 127", args[index]); + ++index; + break; + + case GENSEL_PATT_IMMU8: + if(index > 0 || seen_option) + { + printf(" && "); + } + printf("insn->%s->is_nint_constant && ", args[index]); + printf("insn->%s->address >= 0 && ", args[index]); + printf("insn->%s->address <= 255", args[index]); + ++index; + break; + + case GENSEL_PATT_IMMS16: + if(index > 0 || seen_option) + { + printf(" && "); + } + printf("insn->%s->is_nint_constant && ", args[index]); + printf("insn->%s->address >= -32768 && ", args[index]); + printf("insn->%s->address <= 32767", args[index]); + ++index; + break; + + case GENSEL_PATT_IMMU16: + if(index > 0 || seen_option) + { + printf(" && "); + } + printf("insn->%s->is_nint_constant && ", args[index]); + printf("insn->%s->address >= 0 && ", args[index]); + printf("insn->%s->address <= 65535", args[index]); + ++index; + break; + + case GENSEL_PATT_LOCAL: + if(index > 0 || seen_option) + { + printf(" && "); + } + printf("insn->%s->in_frame && !(insn->%s->in_register)", + args[index], args[index]); + ++index; + break; + + case GENSEL_PATT_IF: + if(index > 0 || seen_option) + { + printf(" && "); + } + printf("("); + gensel_output_code(clause->pattern, pattern->values->value); + printf(")"); + seen_option = 1; + break; + } + pattern = pattern->next; + } + printf(")\n\t{\n"); + } + else if(first) + { + printf("\t{\n"); + } + else + { + printf("\telse\n\t{\n"); + } + + if(gensel_search_option(options, GENSEL_OPT_STACK) + && gensel_search_option(options, GENSEL_OPT_ONLY)) + { + printf("\t\tif(!_jit_regs_is_top(gen, insn->value1) ||\n"); + printf("\t\t _jit_regs_num_used(gen, %d) != 1)\n", + gensel_first_stack_reg); + printf("\t\t{\n"); + printf("\t\t\t_jit_regs_spill_all(gen);\n"); + printf("\t\t}\n"); + } + + clobber_all = 0; + pattern = gensel_search_option(clause->pattern, GENSEL_PATT_CLOBBER); + if(pattern) + { + values = pattern->values; + while(values) + { + if(values->value && strcmp(values->value, "*") == 0) + { + clobber_all = 1; + break; + } + values = values->next; + } + } + + seen_option = 0; + printf("\t\t_jit_regs_init(®s, "); + if(clobber_all) + { + seen_option = 1; + printf("_JIT_REGS_CLOBBER_ALL"); + } + if(gensel_search_option(options, GENSEL_OPT_TERNARY)) + { + if(seen_option) + { + printf(" | "); + } + else + { + seen_option = 1; + } + printf("_JIT_REGS_TERNARY"); + } + if(gensel_search_option(options, GENSEL_OPT_COMMUTATIVE)) + { + if(seen_option) + { + printf(" | "); + } + else + { + seen_option = 1; + } + printf("_JIT_REGS_COMMUTATIVE"); + } + if(gensel_search_option(options, GENSEL_OPT_STACK)) + { + if(seen_option) + { + printf(" | "); + } + else + { + seen_option = 1; + } + printf("_JIT_REGS_STACK"); + } +/* + if(gensel_search_option(options, GENSEL_OPT_)) + { + if(seen_option) + { + printf(" | "); + } + else + { + seen_option = 1; + } + printf("_JIT_REGS_"); + } +*/ + if(!seen_option) + { + printf("0"); + } + printf(");\n"); + + regs = 0; + index = 0; + pattern = clause->pattern; + while(pattern && index < MAX_INPUT) + { + switch(pattern->option) + { + case GENSEL_PATT_REG: + case GENSEL_PATT_FREG: + if(pattern->values && pattern->values->value) + { + printf("\t\t%s = _jit_regs_lookup(\"%s\")];\n", + gensel_reg_names[regs], + pattern->values->value); + printf("\t\t_jit_regs_set_%s(®s, insn, %s, -1);\n", + args[index], gensel_reg_names[regs]); + } + else + { + printf("\t\t_jit_regs_set_%s(®s, insn, -1, -1);\n", + args[index]); + } + ++regs; + ++index; + break; + + case GENSEL_PATT_LREG: + if(pattern->values && pattern->values->value) + { + if(pattern->values->next + && pattern->values->next->value) + { + printf("\t\t%s = _jit_regs_lookup(\"%s\")];\n", + gensel_reg_names[regs], + pattern->values->value); + printf("\t\t%s = _jit_regs_lookup(\"%s\")];\n", + gensel_other_reg_names[regs], + pattern->values->next->value); + printf("\t\t_jit_regs_set_%s(®s, insn, %s, %s);\n", + args[index], + gensel_reg_names[regs], + gensel_other_reg_names[regs]); + } + else + { + printf("\t\t%s = _jit_regs_lookup(\"%s\")];\n", + gensel_reg_names[regs], + pattern->values->value); + printf("\t\t_jit_regs_set_%s(®s, insn, %s, -1);\n", + args[index], gensel_reg_names[regs]); + } + } + else + { + printf("\t\t_jit_regs_set_%s(®s, insn, -1, -1);\n", + args[index]); + } + ++regs; + ++index; + break; + + case GENSEL_PATT_IMMZERO: + case GENSEL_PATT_IMM: + case GENSEL_PATT_IMMS8: + case GENSEL_PATT_IMMU8: + case GENSEL_PATT_IMMS16: + case GENSEL_PATT_IMMU16: + case GENSEL_PATT_LOCAL: + ++index; + break; + + case GENSEL_PATT_SCRATCH: + values = pattern->values; + while(values) + { + if(values->value && strcmp(values->value, "?") != 0) + { + printf("\t\t%s = _jit_regs_lookup(\"%s\")];\n", + gensel_reg_names[regs], + pattern->values->value); + printf("\t\t_jit_regs_set_scratch(®s, clobber);\n"); + } + else + { + printf("\t\t_jit_regs_set_scratch(®s, -1);\n"); + } + ++regs; + ++index; + values = values->next; + } + break; + + case GENSEL_PATT_CLOBBER: + values = pattern->values; + while(values) + { + if(values->value && strcmp(values->value, "*") != 0) + { + printf("\t\tclobber = _jit_regs_lookup(\"%s\")];\n", + pattern->values->value); + printf("\t\t_jit_regs_set_clobber(®s, clobber);\n"); + } + values = values->next; + } + break; + } + pattern = pattern->next; + } + + printf("\t\tif(!_jit_regs_assign(gen, ®s))\n"); + printf("\t\t{\n"); + printf("\t\t\treturn;\n"); + printf("\t\t}\n"); + printf("\t\tif(!_jit_regs_gen(gen, ®s))\n"); + printf("\t\t{\n"); + printf("\t\t\treturn;\n"); + printf("\t\t}\n"); + + regs = 0; + imms = 0; + index = 0; + scratch = 0; + pattern = clause->pattern; + while(pattern && index < MAX_INPUT) + { + switch(pattern->option) + { + case GENSEL_PATT_REG: + case GENSEL_PATT_FREG: + printf("\t\t%s = _jit_reg_info[_jit_regs_%s(regs)].cpu_reg;\n", + gensel_reg_names[regs], args[index]); + ++regs; + ++index; + break; + + case GENSEL_PATT_LREG: + printf("\t\t%s = _jit_reg_info[_jit_regs_%s(regs)].cpu_reg;\n", + gensel_reg_names[regs], args[index]); + printf("\t\t%s = _jit_reg_info[_jit_regs_%s_other(regs)].cpu_reg;\n", + gensel_other_reg_names[regs], args[index]); + ++regs; + ++index; + break; + + case GENSEL_PATT_IMMZERO: + ++index; + break; + + case GENSEL_PATT_IMM: + case GENSEL_PATT_IMMS8: + case GENSEL_PATT_IMMU8: + case GENSEL_PATT_IMMS16: + case GENSEL_PATT_IMMU16: + printf("\t\t%s = insn->%s->address;\n", + gensel_imm_names[imms], args[index]); + ++imms; + ++index; + break; + + case GENSEL_PATT_LOCAL: + printf("\t\tlocal_offset = insn->%s->frame_offset;\n", + args[index]); + index++; + break; + + case GENSEL_PATT_SCRATCH: + values = pattern->values; + while(values) + { + printf("\t\t%s = _jit_regs_scratch(®s, %d);\n", + gensel_reg_names[regs], scratch); + ++regs; + ++scratch; + values = values->next; + } + break; + + } + pattern = pattern->next; + } + + if(gensel_search_option(options, GENSEL_OPT_BINARY_BRANCH) + || gensel_search_option(options, GENSEL_OPT_UNARY_BRANCH)) + { + /* Spill all other registers back to their original positions */ + printf("\t\t_jit_regs_spill_all(gen);\n"); + } + + gensel_output_clause(clause, options); + + printf("\t\t_jit_regs_commit(gen, ®s);\n"); + + printf("\t}\n"); + first = 0; + clause = clause->next; + } +} + +/* + * List of opcodes that are supported by the input rules. + */ +static char **supported = 0; +static char **supported_options = 0; +static int num_supported = 0; + +/* + * Add an opcode to the supported list. + */ +static void gensel_add_supported(char *name, char *option) +{ + supported = (char **)realloc + (supported, (num_supported + 1) * sizeof(char *)); + if(!supported) + { + exit(1); + } + supported[num_supported] = name; + supported_options = (char **)realloc + (supported_options, (num_supported + 1) * sizeof(char *)); + if(!supported_options) + { + exit(1); + } + supported_options[num_supported++] = option; +} + +/* + * Output the list of supported opcodes. + */ +static void gensel_output_supported(void) +{ + int index; + for(index = 0; index < num_supported; ++index) + { + if(supported_options[index]) + { + if(supported_options[index][0] == '!') + { + printf("#ifndef %s\n", supported_options[index] + 1); + } + else + { + printf("#ifdef %s\n", supported_options[index]); + } + printf("case %s:\n", supported[index]); + printf("#endif\n"); + } + else + { + printf("case %s:\n", supported[index]); + } + } + printf("\treturn 1;\n\n"); +} + +%} + +/* + * Define the structure of yylval. + */ +%union { + int tag; + char *name; + struct gensel_value *value; + struct gensel_option *option; + struct + { + char *filename; + long linenum; + char *block; + + } code; + struct + { + struct gensel_value *head; + struct gensel_value *tail; + + } values; + struct + { + struct gensel_option *head; + struct gensel_option *tail; + + } options; + struct + { + struct gensel_clause *head; + struct gensel_clause *tail; + + } clauses; +} + +/* + * Primitive lexical tokens and keywords. + */ +%token IDENTIFIER "an identifier" +%token CODE_BLOCK "a code block" +%token LITERAL "literal string" +%token K_PTR "`->'" +%token K_REG "word register" +%token K_LREG "long register" +%token K_FREG "float register" +%token K_IMM "immediate value" +%token K_IMMZERO "immediate zero value" +%token K_IMMS8 "immediate signed 8-bit value" +%token K_IMMU8 "immediate unsigned 8-bit value" +%token K_IMMS16 "immediate signed 16-bit value" +%token K_IMMU16 "immediate unsigned 16-bit value" +%token K_LOCAL "local variable" +%token K_BINARY "`binary'" +%token K_UNARY "`unary'" +%token K_UNARY_BRANCH "`unary_branch'" +%token K_BINARY_BRANCH "`binary_branch'" +%token K_UNARY_NOTE "`unary_note'" +%token K_BINARY_NOTE "`binary_note'" +%token K_TERNARY "`ternary'" +%token K_STACK "`stack'" +%token K_ONLY "`only'" +%token K_COMMUTATIVE "`commutative'" +%token K_IF "`if'" +%token K_CLOBBER "`clobber'" +%token K_SCRATCH "`scratch'" +%token K_SPACE "`space'" +%token K_INST_TYPE "`%inst_type'" + +/* deperecated keywords */ + +%token K_MANUAL "`manual'" +%token K_MORE_SPACE "`more_space'" +%token K_SPILL_BEFORE "`spill_before'" + +/* + * Define the yylval types of the various non-terminals. + */ +%type CODE_BLOCK +%type IDENTIFIER LITERAL +%type IfClause IdentifierList Literal +%type OptionTag InputTag RegTag LRegTag +%type Clauses Clause +%type Options OptionList Pattern Pattern2 +%type