%{ /* * gen-rules-parser.y - Bison grammar for the "gen-rules" program. * * Copyright (C) 2004, 2006-2007 Southern Storm Software, Pty Ltd. * * This file is part of the libjit library. * * The libjit library is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation, either version 2.1 of * the License, or (at your option) any later version. * * The libjit library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with the libjit library. If not, see * . */ #include #include #include #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_STRING_H # include #elif defined(HAVE_STRINGS_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; /* * Maximal number of input values in a pattern. */ #define MAX_INPUT 3 /* * Maximal number of scratch registers in a pattern. */ #define MAX_SCRATCH 6 /* * Maximal number of pattern elements. */ #define MAX_PATTERN (MAX_INPUT + MAX_SCRATCH) /* * Rule Options. */ #define GENSEL_OPT_TERNARY 1 #define GENSEL_OPT_BRANCH 2 #define GENSEL_OPT_NOTE 3 #define GENSEL_OPT_COPY 4 #define GENSEL_OPT_COMMUTATIVE 5 #define GENSEL_OPT_STACK 6 #define GENSEL_OPT_X87_ARITH 7 #define GENSEL_OPT_X87_ARITH_REVERSIBLE 8 #define GENSEL_OPT_MANUAL 9 #define GENSEL_OPT_MORE_SPACE 10 /* * Pattern values. */ #define GENSEL_PATT_ANY 1 #define GENSEL_PATT_REG 2 #define GENSEL_PATT_LREG 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_IMMS32 10 #define GENSEL_PATT_IMMU32 11 #define GENSEL_PATT_LOCAL 12 #define GENSEL_PATT_FRAME 13 #define GENSEL_PATT_SCRATCH 14 #define GENSEL_PATT_CLOBBER 15 #define GENSEL_PATT_IF 16 #define GENSEL_PATT_SPACE 17 /* * Value types. */ #define GENSEL_VALUE_STRING 1 #define GENSEL_VALUE_REGCLASS 2 #define GENSEL_VALUE_ALL 3 #define GENSEL_VALUE_CLOBBER 4 #define GENSEL_VALUE_EARLY_CLOBBER 5 /* * Register class. */ typedef struct gensel_regclass *gensel_regclass_t; struct gensel_regclass { char *id; char *def; int is_long; gensel_regclass_t next; }; /* * Option value. */ typedef struct gensel_value *gensel_value_t; struct gensel_value { int type; void *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 { int dest; gensel_option_t pattern; char *filename; long linenum; char *code; gensel_clause_t next; }; static char *gensel_args[] = { "dest", "value1", "value2" }; static char *gensel_imm_args[] = { "insn->dest->address", "insn->value1->address", "insn->value2->address" }; 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" }; static char *gensel_local_names[] = { "local_offset", "local_offset2", "local_offset3" }; /* * Register classes. */ static gensel_regclass_t gensel_regclass_list; /* * Create a register class. */ static void gensel_create_regclass(char *id, char *def, int is_long) { gensel_regclass_t rp; rp = (gensel_regclass_t) malloc(sizeof(struct gensel_regclass)); if(!rp) { exit(1); } rp->id = id; rp->def = def; rp->is_long = is_long; rp->next = gensel_regclass_list; gensel_regclass_list = rp; } gensel_regclass_t gensel_lookup_regclass(char *id) { gensel_regclass_t rp; rp = gensel_regclass_list; for(;;) { if(!rp) { gensel_error( gensel_filename, gensel_linenum, "invalid register class"); } if(strcmp(id, rp->id) == 0) { return rp; } rp = rp->next; } } /* * Create a value. */ static gensel_value_t gensel_create_value(int type) { gensel_value_t vp; vp = (gensel_value_t) malloc(sizeof(struct gensel_value)); if(!vp) { exit(1); } vp->type = type; vp->value = 0; vp->next = 0; return vp; } /* * Create literal string value. */ static gensel_value_t gensel_create_string_value(char *value) { gensel_value_t vp; vp = gensel_create_value(GENSEL_VALUE_STRING); vp->value = value; return vp; } /* * Create register class value. */ static gensel_value_t gensel_create_regclass_value(char *value) { gensel_value_t vp; vp = gensel_create_value(GENSEL_VALUE_REGCLASS); vp->value = gensel_lookup_regclass(value); return vp; } /* * 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; } /* * Create a register pattern element. */ static gensel_option_t gensel_create_register( int flags, gensel_value_t value, gensel_value_t values) { gensel_regclass_t regclass; if(flags) { value->next = gensel_create_value(flags); value->next->next = values; } else { value->next = values; } regclass = value->value; return gensel_create_option( regclass->is_long ? GENSEL_PATT_LREG : GENSEL_PATT_REG, value); } /* * Create a scratch register pattern element. */ static gensel_option_t gensel_create_scratch( gensel_value_t regclass, gensel_value_t values) { regclass->next = values; return gensel_create_option(GENSEL_PATT_SCRATCH, regclass); } /* * Free a list of values. */ static void gensel_free_values(gensel_value_t values) { gensel_value_t next; while(values) { next = values->next; if(values->type == GENSEL_VALUE_STRING) { 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; int regs, max_regs; int other_regs_mask; int imms, max_imms; int locals, max_locals; int scratch, others; max_regs = 0; other_regs_mask = 0; max_imms = 0; max_locals = 0; while(clauses != 0) { regs = 0; imms = 0; locals = 0; others = 0; scratch = 0; pattern = clauses->pattern; while(pattern) { switch(pattern->option) { case GENSEL_PATT_ANY: ++others; break; case GENSEL_PATT_REG: ++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: case GENSEL_PATT_IMMS32: case GENSEL_PATT_IMMU32: ++imms; break; case GENSEL_PATT_LOCAL: case GENSEL_PATT_FRAME: ++locals; break; case GENSEL_PATT_SCRATCH: ++scratch; } pattern = pattern->next; } if((regs + imms + locals + 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 + scratch)) { max_regs = regs + scratch; } if(max_imms < imms) { max_imms = imms; } if(max_locals < locals) { max_locals = locals; } clauses = clauses->next; } if(max_regs > 0) { printf("\tint reg"); for(scratch = 1; scratch < max_regs; scratch++) { printf(", reg%d", scratch + 1); } printf(";\n"); } 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, other_reg3;\n"); break; case 6: printf("\tint other_reg2, other_reg3;\n"); break; case 7: printf("\tint other_reg, other_reg2, other_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; } switch(max_locals) { case 1: printf("\tjit_nint local_offset;\n"); break; case 2: printf("\tjit_nint local_offset, local_offset2;\n"); break; case 3: printf("\tjit_nint local_offset, local_offset2, local_offset3;\n"); break; } } /* * Check if the pattern contains any registers. */ static int gensel_contains_registers(gensel_option_t pattern) { while(pattern) { switch(pattern->option) { case GENSEL_PATT_REG: case GENSEL_PATT_LREG: case GENSEL_PATT_SCRATCH: case GENSEL_PATT_CLOBBER: return 1; } pattern = pattern->next; } return 0; } /* * Returns first register in the pattern if any. */ static gensel_option_t gensel_get_first_register(gensel_option_t pattern) { while(pattern) { switch(pattern->option) { case GENSEL_PATT_REG: case GENSEL_PATT_LREG: return pattern; } pattern = pattern->next; } return 0; } static void gensel_init_names(int count, char *names[], char *other_names[]) { int index; for(index = 0; index < count; index++) { if(names) { names[index] = "undefined"; } if(other_names) { other_names[index] = "undefined"; } } } static void gensel_build_arg_index( gensel_option_t pattern, int count, char *names[], char *other_names[], int ternary, int free_dest) { int index; gensel_init_names(count, names, other_names); index = 0; while(pattern) { switch(pattern->option) { case GENSEL_PATT_ANY: ++index; break; case GENSEL_PATT_REG: case GENSEL_PATT_LREG: case GENSEL_PATT_LOCAL: case GENSEL_PATT_FRAME: 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_IMMS32: case GENSEL_PATT_IMMU32: if(ternary || free_dest) { if(index < 3) { names[index] = gensel_args[index]; } } else { if(index < 2) { names[index] = gensel_args[index + 1]; } } ++index; break; } pattern = pattern->next; } } static void gensel_build_imm_arg_index( gensel_option_t pattern, int count, char *names[], char *other_names[], int ternary, int free_dest) { int index; gensel_init_names(count, names, other_names); index = 0; while(pattern) { switch(pattern->option) { case GENSEL_PATT_ANY: case GENSEL_PATT_REG: case GENSEL_PATT_LREG: case GENSEL_PATT_LOCAL: case GENSEL_PATT_FRAME: 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: case GENSEL_PATT_IMMS32: case GENSEL_PATT_IMMU32: if(ternary || free_dest) { if(index < 3) { names[index] = gensel_imm_args[index]; } } else { if(index < 2) { names[index] = gensel_imm_args[index + 1]; } } ++index; break; } pattern = pattern->next; } } /* * Build index of input value names. */ static void gensel_build_var_index( gensel_option_t pattern, char *names[MAX_PATTERN], char *other_names[MAX_PATTERN]) { int regs, imms, locals, index; gensel_init_names(MAX_PATTERN, names, other_names); regs = 0; imms = 0; locals = 0; index = 0; while(pattern) { switch(pattern->option) { case GENSEL_PATT_ANY: ++index; break; case GENSEL_PATT_REG: 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: case GENSEL_PATT_IMMS32: case GENSEL_PATT_IMMU32: names[index] = gensel_imm_names[imms]; ++imms; ++index; break; case GENSEL_PATT_LOCAL: case GENSEL_PATT_FRAME: names[index] = gensel_local_names[locals]; ++locals; ++index; break; case GENSEL_PATT_SCRATCH: names[index] = gensel_reg_names[regs]; ++regs; ++index; } pattern = pattern->next; } } /* * Output the code. */ static void gensel_output_code( gensel_option_t pattern, char *code, char *names[MAX_PATTERN], char *other_names[MAX_PATTERN], int free_dest, int in_line) { char first; int index; /* Output the clause code */ if(!in_line) { printf("\t\t"); } while(*code != '\0') { first = '1'; if(*code == '$' && code[1] >= first && code[1] < (first + MAX_PATTERN)) { index = code[1] - first; printf(names[index]); code += 2; } else if(*code == '%' && code[1] >= first && code[1] < (first + MAX_PATTERN)) { index = code[1] - first; printf(other_names[index]); code += 2; } else if(*code == '\n') { putc(*code, stdout); putc('\t', stdout); ++code; } else { putc(*code, stdout); ++code; } } if(!in_line) { printf("\n"); } } /* * Output the code within a clause. */ static void gensel_output_clause_code( gensel_clause_t clause, char *names[MAX_PATTERN], char *other_names[MAX_PATTERN], int free_dest) { /* Output the line number information from the original file */ #if 0 printf("#line %ld \"%s\"\n", clause->linenum, clause->filename); #endif gensel_output_code(clause->pattern, clause->code, names, other_names, free_dest, 0); } static void gensel_output_register(char *name, gensel_regclass_t regclass, gensel_value_t values) { printf("\t\t_jit_regs_init_%s(®s, insn, ", name); switch(values ? values->type : 0) { case GENSEL_VALUE_CLOBBER: printf("_JIT_REGS_CLOBBER"); values = values->next; break; case GENSEL_VALUE_EARLY_CLOBBER: printf("_JIT_REGS_EARLY_CLOBBER"); values = values->next; break; default: printf("0"); break; } printf(", %s);\n", regclass->def); if(values && values->value) { char *reg; reg = values->value; if(values->next && values->next->value) { char *other_reg; other_reg = values->next->value; printf("\t\t_jit_regs_set_%s(gen, ®s, _jit_regs_lookup(\"%s\"), _jit_regs_lookup(\"%s\"));\n", name, reg, other_reg); } else { printf("\t\t_jit_regs_set_%s(gen, ®s, _jit_regs_lookup(\"%s\"), -1);\n", name, reg); } } } /* * Output value initialization code. */ static void gensel_output_register_pattern(char *name, gensel_option_t pattern) { gensel_output_register(name, pattern->values->value, pattern->values->next); } /* * Create an upper-case copy of a string. */ static char * gensel_string_upper(char *string) { char *cp; if(string) { string = strdup(string); for(cp = string; *cp; cp++) { *cp = toupper(*cp); } } return string; } /* * Output the clauses for a rule. */ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t options) { char *name; char *args[MAX_INPUT]; char *names[MAX_PATTERN]; char *other_names[MAX_PATTERN]; gensel_clause_t clause; gensel_option_t pattern; gensel_option_t space, more_space; gensel_value_t values; int regs, imms, locals, scratch, index; int first, seen_option; int ternary, free_dest; int contains_registers; gensel_regclass_t regclass; char *uc_arg; /* If the clause is manual, then output it as-is */ if(gensel_search_option(options, GENSEL_OPT_MANUAL)) { gensel_init_names(MAX_PATTERN, names, other_names); gensel_output_clause_code(clauses, names, other_names, 0); return; } clause = clauses; contains_registers = 0; while(clause) { contains_registers = gensel_contains_registers(clause->pattern); if(contains_registers) { break; } clause = clause->next; } printf("\t%s inst;\n", gensel_inst_type); if(contains_registers) { printf("\t_jit_regs_t regs;\n"); } gensel_declare_regs(clauses, options); ternary = (0 != gensel_search_option(options, GENSEL_OPT_TERNARY)); /* Output the clause checking and dispatching code */ clause = clauses; first = 1; while(clause) { contains_registers = gensel_contains_registers(clause->pattern); free_dest = clause->dest; gensel_build_arg_index(clause->pattern, 3, args, 0, ternary, free_dest); if(clause->next) { if(first) printf("\tif("); else printf("\telse if("); index = 0; seen_option = 0; pattern = clause->pattern; while(pattern) { switch(pattern->option) { case GENSEL_PATT_ANY: ++index; break; case GENSEL_PATT_REG: case GENSEL_PATT_LREG: /* Do not check if the value is in a register as the allocator will load them anyway as long as other conditions are met. */ #if 0 if(seen_option) { printf(" && "); } printf("insn->%s->in_register", args[index]); #endif ++index; break; case GENSEL_PATT_IMM: if(seen_option) { printf(" && "); } printf("insn->%s->is_constant", args[index]); seen_option = 1; ++index; break; case GENSEL_PATT_IMMZERO: if(seen_option) { printf(" && "); } printf("insn->%s->is_nint_constant && ", args[index]); printf("insn->%s->address == 0", args[index]); seen_option = 1; ++index; break; case GENSEL_PATT_IMMS8: if(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]); seen_option = 1; ++index; break; case GENSEL_PATT_IMMU8: if(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]); seen_option = 1; ++index; break; case GENSEL_PATT_IMMS16: if(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]); seen_option = 1; ++index; break; case GENSEL_PATT_IMMU16: if(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]); seen_option = 1; ++index; break; case GENSEL_PATT_IMMS32: if(seen_option) { printf(" && "); } printf("insn->%s->is_nint_constant && ", args[index]); printf("insn->%s->address >= -2147483648 && ", args[index]); printf("insn->%s->address <= 2147483647", args[index]); seen_option = 1; ++index; break; case GENSEL_PATT_IMMU32: if(seen_option) { printf(" && "); } printf("insn->%s->is_nint_constant && ", args[index]); printf("insn->%s->address >= 0 && ", args[index]); printf("insn->%s->address <= 4294967295", args[index]); seen_option = 1; ++index; break; case GENSEL_PATT_LOCAL: if(seen_option) { printf(" && "); } printf("!insn->%s->is_constant && ", args[index]); printf("!insn->%s->in_register && ", args[index]); printf("!insn->%s->has_global_register", args[index]); /* If the value is used again in the same basic block it is highly likely that using a register instead of the stack will be a win. Assume that if the "local" pattern is not the last one then it must be followed by a "reg" pattern. */ uc_arg = gensel_string_upper(args[index]); printf("&& (insn->flags & JIT_INSN_%s_NEXT_USE) == 0", uc_arg); free(uc_arg); seen_option = 1; ++index; break; case GENSEL_PATT_FRAME: if(seen_option) { printf(" && "); } printf("!insn->%s->is_constant && ", args[index]); printf("!insn->%s->has_global_register", args[index]); seen_option = 1; ++index; break; case GENSEL_PATT_IF: if(seen_option) { printf(" && "); } printf("("); gensel_build_imm_arg_index( clause->pattern, MAX_PATTERN, names, other_names, ternary, free_dest); gensel_output_code( clause->pattern, pattern->values->value, names, other_names, free_dest, 1); printf(")"); seen_option = 1; break; } pattern = pattern->next; } if(!seen_option) { printf("1"); } printf(")\n\t{\n"); } else if(first) { printf("\t{\n"); } else { printf("\telse\n\t{\n"); } if(contains_registers) { seen_option = 0; printf("\t\t_jit_regs_init(gen, ®s, "); if(ternary) { seen_option = 1; printf("_JIT_REGS_TERNARY"); } else if(free_dest) { seen_option = 1; printf("_JIT_REGS_FREE_DEST"); } if(gensel_search_option(options, GENSEL_OPT_BRANCH)) { if(seen_option) { printf(" | "); } else { seen_option = 1; } printf("_JIT_REGS_BRANCH"); } if(gensel_search_option(options, GENSEL_OPT_COPY)) { if(seen_option) { printf(" | "); } else { seen_option = 1; } printf("_JIT_REGS_COPY"); } 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_COMMUTATIVE)) { if(seen_option) { printf(" | "); } else { seen_option = 1; } printf("_JIT_REGS_COMMUTATIVE"); } /* x87 options */ if(gensel_search_option(options, GENSEL_OPT_X87_ARITH)) { if(seen_option) { printf(" | "); } else { seen_option = 1; } printf("_JIT_REGS_X87_ARITH"); } else if(gensel_search_option(options, GENSEL_OPT_X87_ARITH_REVERSIBLE)) { if(seen_option) { printf(" | "); } else { seen_option = 1; } printf("_JIT_REGS_X87_ARITH | _JIT_REGS_REVERSIBLE"); } if(!seen_option) { printf("0"); } printf(");\n"); if(!(ternary || free_dest || gensel_search_option(options, GENSEL_OPT_NOTE) || gensel_search_option(options, GENSEL_OPT_BRANCH))) { pattern = gensel_get_first_register(clause->pattern); gensel_output_register("dest", pattern ? pattern->values->value : 0, 0); } } regs = 0; index = 0; scratch = 0; pattern = clause->pattern; while(pattern) { switch(pattern->option) { case GENSEL_PATT_ANY: ++index; break; case GENSEL_PATT_REG: case GENSEL_PATT_LREG: gensel_output_register_pattern(args[index], pattern); ++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_IMMS32: case GENSEL_PATT_IMMU32: ++index; break; case GENSEL_PATT_LOCAL: printf("\t\t_jit_gen_fix_value(insn->%s);\n", args[index]); ++index; break; case GENSEL_PATT_FRAME: printf("\t\t_jit_regs_force_out(gen, insn->%s, %d);\n", args[index], (free_dest && index == 0)); printf("\t\t_jit_gen_fix_value(insn->%s);\n", args[index]); ++index; break; case GENSEL_PATT_SCRATCH: regclass = pattern->values->value; printf("\t\t_jit_regs_add_scratch(®s, %s);\n", regclass->def); if(pattern->values->next && pattern->values->next->value) { name = pattern->values->next->value; printf("\t\t_jit_regs_set_scratch(gen, ®s, %d, _jit_regs_lookup(\"%s\"));\n", scratch, name); } ++regs; ++scratch; ++index; break; case GENSEL_PATT_CLOBBER: values = pattern->values; while(values) { if(!values->value) { continue; } switch(values->type) { case GENSEL_VALUE_STRING: name = values->value; printf("\t\t_jit_regs_clobber(®s, _jit_regs_lookup(\"%s\"));\n", name); break; case GENSEL_VALUE_REGCLASS: regclass = values->value; printf("\t\t_jit_regs_clobber_class(gen, ®s, %s);\n", regclass->def); break; case GENSEL_VALUE_ALL: printf("\t\t_jit_regs_clobber_all(gen, ®s);\n"); break; } values = values->next; } break; } pattern = pattern->next; } if(gensel_search_option(options, GENSEL_OPT_BRANCH)) { /* Spill all other registers back to their original positions */ if(contains_registers) { printf("\t\t_jit_regs_clobber_all(gen, ®s);\n"); } else { printf("\t\t_jit_regs_spill_all(gen);\n"); } } if(gensel_new_inst_type) { if(contains_registers) { printf("\t\t_jit_regs_assign(gen, ®s);\n"); printf("\t\t_jit_regs_gen(gen, ®s);\n"); } 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); if(contains_registers) { printf("\t\t_jit_regs_begin(gen, ®s, "); } else { printf("\t\t_jit_gen_check_space(gen, "); } if(space && space->values && space->values->value) { printf("("); gensel_build_imm_arg_index( clause->pattern, MAX_PATTERN, names, other_names, ternary, free_dest); gensel_output_code( clause->pattern, space->values->value, names, other_names, free_dest, 1); printf(")"); } else { printf("%d", ((more_space == 0) ? gensel_reserve_space : gensel_reserve_more_space)); } printf(");\n"); } printf("\t\tinst = (%s)(gen->ptr);\n", gensel_inst_type); regs = 0; imms = 0; locals = 0; index = 0; scratch = 0; pattern = clause->pattern; while(pattern) { switch(pattern->option) { case GENSEL_PATT_ANY: ++index; break; case GENSEL_PATT_REG: printf("\t\t%s = _jit_reg_info[_jit_regs_get_%s(®s)].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_get_%s(®s)].cpu_reg;\n", gensel_reg_names[regs], args[index]); printf("\t\t%s = _jit_reg_info[_jit_regs_get_%s_other(®s)].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: case GENSEL_PATT_IMMS32: case GENSEL_PATT_IMMU32: printf("\t\t%s = insn->%s->address;\n", gensel_imm_names[imms], args[index]); ++imms; ++index; break; case GENSEL_PATT_LOCAL: case GENSEL_PATT_FRAME: printf("\t\t%s = insn->%s->frame_offset;\n", gensel_local_names[locals], args[index]); ++locals; ++index; break; case GENSEL_PATT_SCRATCH: printf("\t\t%s = _jit_reg_info[_jit_regs_get_scratch(®s, %d)].cpu_reg;\n", gensel_reg_names[regs], scratch); ++regs; ++scratch; ++index; break; } pattern = pattern->next; } gensel_build_var_index(clause->pattern, names, other_names); gensel_output_clause_code(clause, names, other_names, free_dest); /* 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->ptr = (unsigned char *)inst;\n"); } if(contains_registers) { 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_ANY "any value" %token K_ALL "all registers" %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_IMMS32 "immediate signed 32-bit value" %token K_IMMU32 "immediate unsigned 32-bit value" %token K_LOCAL "local variable" %token K_FRAME "local variable forced out into the stack frame" %token K_NOTE "`note'" %token K_TERNARY "`ternary'" %token K_BRANCH "`branch'" %token K_COPY "`copy'" %token K_COMMUTATIVE "`commutative'" %token K_IF "`if'" %token K_CLOBBER "`clobber'" %token K_SCRATCH "`scratch'" %token K_SPACE "`space'" %token K_STACK "`stack'" %token K_X87_ARITH "`x87_arith'" %token K_X87_ARITH_REVERSIBLE "`x87_arith_reversible'" %token K_INST_TYPE "`%inst_type'" %token K_REG_CLASS "`%reg_class'" %token K_LREG_CLASS "`%lreg_class'" /* deperecated keywords */ %token K_MANUAL "`manual'" %token K_MORE_SPACE "`more_space'" /* * Define the yylval types of the various non-terminals. */ %type CODE_BLOCK %type IDENTIFIER LITERAL %type IfClause IdentifierList Literal %type OptionTag InputTag DestFlag RegFlag %type Clauses Clause %type Options Pattern %type