mirror of https://github.com/ademakov/libjit
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
995 lines
22 KiB
995 lines
22 KiB
%{
|
|
/*
|
|
* gen-sel-parser.y - Bison grammar for the "gen-sel" program.
|
|
*
|
|
* Copyright (C) 2004 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 <config.h>
|
|
#include <stdio.h>
|
|
#ifdef HAVE_STRING_H
|
|
#include <string.h>
|
|
#elif defined(HAVE_STRINGS_H)
|
|
#include <strings.h>
|
|
#endif
|
|
#ifdef HAVE_STDLIB_H
|
|
#include <stdlib.h>
|
|
#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
|
|
|
|
/*
|
|
* Report error messages from the parser.
|
|
*/
|
|
static void yyerror(char *msg)
|
|
{
|
|
puts(msg);
|
|
}
|
|
|
|
/*
|
|
* Current file and line number.
|
|
*/
|
|
extern char *gensel_filename;
|
|
extern long gensel_linenum;
|
|
|
|
/*
|
|
* 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 */
|
|
|
|
/*
|
|
* Option values.
|
|
*/
|
|
#define GENSEL_OPT_SPILL_BEFORE 0x0001
|
|
#define GENSEL_OPT_BINARY 0x0002
|
|
#define GENSEL_OPT_UNARY 0x0004
|
|
#define GENSEL_OPT_TERNARY 0x0008
|
|
#define GENSEL_OPT_STACK 0x0010
|
|
#define GENSEL_OPT_UNARY_BRANCH 0x0020
|
|
#define GENSEL_OPT_BINARY_BRANCH 0x0040
|
|
#define GENSEL_OPT_ONLY 0x0080
|
|
#define GENSEL_OPT_MANUAL 0x0100
|
|
#define GENSEL_OPT_UNARY_NOTE 0x0200
|
|
#define GENSEL_OPT_BINARY_NOTE 0x0400
|
|
#define GENSEL_OPT_MORE_SPACE 0x0800
|
|
|
|
/*
|
|
* Pattern values.
|
|
*/
|
|
#define GENSEL_PATT_END 0
|
|
#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
|
|
|
|
/*
|
|
* Information about clauses.
|
|
*/
|
|
typedef struct gensel_clause *gensel_clause_t;
|
|
struct gensel_clause
|
|
{
|
|
int pattern[8];
|
|
char *filename;
|
|
long linenum;
|
|
char *code;
|
|
gensel_clause_t 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;
|
|
free(clauses->code);
|
|
free(clauses);
|
|
clauses = next;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Declare the register variables that are needed for a set of clauses.
|
|
*/
|
|
static void gensel_declare_regs(gensel_clause_t clauses, int options)
|
|
{
|
|
int have_reg1 = 0;
|
|
int have_reg2 = 0;
|
|
int have_reg3 = 0;
|
|
int have_imm = 0;
|
|
int have_local = 0;
|
|
int index;
|
|
while(clauses != 0)
|
|
{
|
|
for(index = 0; clauses->pattern[index] != GENSEL_PATT_END; ++index)
|
|
{
|
|
switch(clauses->pattern[index])
|
|
{
|
|
case GENSEL_PATT_REG:
|
|
case GENSEL_PATT_LREG:
|
|
case GENSEL_PATT_FREG:
|
|
{
|
|
if(index == 0)
|
|
have_reg1 = 1;
|
|
else if(index == 1)
|
|
have_reg2 = 1;
|
|
else
|
|
have_reg3 = 1;
|
|
}
|
|
break;
|
|
|
|
case GENSEL_PATT_IMMZERO: break;
|
|
|
|
case GENSEL_PATT_IMM:
|
|
case GENSEL_PATT_IMMS8:
|
|
case GENSEL_PATT_IMMU8:
|
|
case GENSEL_PATT_IMMS16:
|
|
case GENSEL_PATT_IMMU16:
|
|
{
|
|
have_imm = 1;
|
|
}
|
|
break;
|
|
|
|
case GENSEL_PATT_LOCAL:
|
|
{
|
|
have_local = 1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
clauses = clauses->next;
|
|
}
|
|
if(have_reg1)
|
|
{
|
|
printf("\tint reg;\n");
|
|
}
|
|
if(have_reg2 && (options & GENSEL_OPT_STACK) == 0)
|
|
{
|
|
printf("\tint reg2;\n");
|
|
}
|
|
if(have_reg3 && (options & GENSEL_OPT_STACK) == 0)
|
|
{
|
|
printf("\tint reg3;\n");
|
|
}
|
|
if(have_imm)
|
|
{
|
|
printf("\tjit_nint imm_value;\n");
|
|
}
|
|
if(have_local)
|
|
{
|
|
printf("\tjit_nint local_offset;\n");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Output the code within a clause.
|
|
*/
|
|
static void gensel_output_clause_code(gensel_clause_t clause)
|
|
{
|
|
char *code;
|
|
int index;
|
|
|
|
/* Output the line number information from the original file */
|
|
printf("#line %ld \"%s\"\n", clause->linenum, clause->filename);
|
|
|
|
/* Output the clause code */
|
|
printf("\t\t");
|
|
code = clause->code;
|
|
while(*code != '\0')
|
|
{
|
|
if(*code == '$' && code[1] >= '1' && code[1] <= '9')
|
|
{
|
|
index = code[1] - '1';
|
|
switch(clause->pattern[index])
|
|
{
|
|
case GENSEL_PATT_REG:
|
|
case GENSEL_PATT_LREG:
|
|
case GENSEL_PATT_FREG:
|
|
{
|
|
if(index == 0)
|
|
printf("_jit_reg_info[reg].cpu_reg");
|
|
else if(index == 1)
|
|
printf("_jit_reg_info[reg2].cpu_reg");
|
|
else
|
|
printf("_jit_reg_info[reg3].cpu_reg");
|
|
}
|
|
break;
|
|
|
|
case GENSEL_PATT_IMM:
|
|
case GENSEL_PATT_IMMZERO:
|
|
case GENSEL_PATT_IMMS8:
|
|
case GENSEL_PATT_IMMU8:
|
|
case GENSEL_PATT_IMMS16:
|
|
case GENSEL_PATT_IMMU16:
|
|
{
|
|
printf("imm_value");
|
|
}
|
|
break;
|
|
|
|
case GENSEL_PATT_LOCAL:
|
|
{
|
|
printf("local_offset");
|
|
}
|
|
break;
|
|
}
|
|
code += 2;
|
|
}
|
|
else if(*code == '%' && code[1] >= '1' && code[1] <= '9')
|
|
{
|
|
index = code[1] - '1';
|
|
switch(clause->pattern[index])
|
|
{
|
|
case GENSEL_PATT_REG:
|
|
case GENSEL_PATT_LREG:
|
|
case GENSEL_PATT_FREG:
|
|
{
|
|
if(index == 0)
|
|
printf("_jit_reg_info[_jit_reg_info[reg].other_reg].cpu_reg");
|
|
else if(index == 1)
|
|
printf("_jit_reg_info[_jit_reg_info[reg2].other_reg].cpu_reg");
|
|
else
|
|
printf("_jit_reg_info[_jit_reg_info[reg3].other_reg].cpu_reg");
|
|
}
|
|
break;
|
|
}
|
|
code += 2;
|
|
}
|
|
else if(*code == '\n')
|
|
{
|
|
putc(*code, stdout);
|
|
putc('\t', stdout);
|
|
++code;
|
|
}
|
|
else
|
|
{
|
|
putc(*code, stdout);
|
|
++code;
|
|
}
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
/*
|
|
* Output a single clause for a rule.
|
|
*/
|
|
static void gensel_output_clause(gensel_clause_t clause, int options)
|
|
{
|
|
/* Cache the instruction pointer into "inst" */
|
|
if(gensel_new_inst_type)
|
|
{
|
|
printf("\t\tjit_gen_load_inst_ptr(gen, inst);\n");
|
|
}
|
|
else
|
|
{
|
|
printf("\t\tinst = (%s)(gen->posn.ptr);\n", gensel_inst_type);
|
|
printf("\t\tif(!jit_cache_check_for_n(&(gen->posn), %d))\n",
|
|
(((options & GENSEL_OPT_MORE_SPACE) == 0)
|
|
? gensel_reserve_space : gensel_reserve_more_space));
|
|
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, int options)
|
|
{
|
|
const char *arg1;
|
|
const char *arg2;
|
|
const char *arg3;
|
|
const char *arg;
|
|
const char *reg;
|
|
const char *flag1;
|
|
const char *flag2;
|
|
const char *flag3;
|
|
const char *flag;
|
|
int destroy1;
|
|
int destroy2;
|
|
int destroy3;
|
|
int destroy;
|
|
gensel_clause_t clause;
|
|
int first, index;
|
|
int check_index;
|
|
|
|
/* If the clause is manual, then output it as-is */
|
|
if((options & GENSEL_OPT_MANUAL) != 0)
|
|
{
|
|
gensel_output_clause_code(clauses);
|
|
return;
|
|
}
|
|
|
|
/* Determine the location of this instruction's arguments */
|
|
if((options & GENSEL_OPT_TERNARY) != 0)
|
|
{
|
|
arg1 = "insn->dest";
|
|
arg2 = "insn->value1";
|
|
arg3 = "insn->value2";
|
|
flag1 = "DEST";
|
|
flag2 = "VALUE1";
|
|
flag3 = "VALUE2";
|
|
destroy1 = 0;
|
|
destroy2 = 0;
|
|
destroy3 = 0;
|
|
}
|
|
else
|
|
{
|
|
arg1 = "insn->value1";
|
|
arg2 = "insn->value2";
|
|
arg3 = "??";
|
|
flag1 = "VALUE1";
|
|
flag2 = "VALUE2";
|
|
flag3 = "??";
|
|
if((options & (GENSEL_OPT_BINARY_BRANCH |
|
|
GENSEL_OPT_UNARY_BRANCH |
|
|
GENSEL_OPT_BINARY_NOTE |
|
|
GENSEL_OPT_UNARY_NOTE)) != 0)
|
|
{
|
|
destroy1 = 0;
|
|
}
|
|
else
|
|
{
|
|
destroy1 = 1;
|
|
}
|
|
destroy2 = 0;
|
|
destroy3 = 0;
|
|
}
|
|
|
|
/* If all of the clauses start with a register, then load the first
|
|
value into a register before we start checking cases */
|
|
check_index = 0;
|
|
if((options & (GENSEL_OPT_BINARY | GENSEL_OPT_UNARY |
|
|
GENSEL_OPT_BINARY_BRANCH | GENSEL_OPT_UNARY_BRANCH |
|
|
GENSEL_OPT_BINARY_NOTE | GENSEL_OPT_UNARY_NOTE)) != 0 &&
|
|
(options & GENSEL_OPT_STACK) == 0)
|
|
{
|
|
clause = clauses;
|
|
while(clause != 0)
|
|
{
|
|
if(clause->pattern[0] != GENSEL_PATT_REG &&
|
|
clause->pattern[0] != GENSEL_PATT_LREG &&
|
|
clause->pattern[0] != GENSEL_PATT_FREG)
|
|
{
|
|
break;
|
|
}
|
|
clause = clause->next;
|
|
}
|
|
if(!clause)
|
|
{
|
|
printf("\treg = _jit_regs_load_value(gen, %s, %d, ",
|
|
arg1, destroy1);
|
|
printf("(insn->flags & (JIT_INSN_%s_NEXT_USE | "
|
|
"JIT_INSN_%s_LIVE)));\n", flag1, flag1);
|
|
check_index = 1;
|
|
}
|
|
}
|
|
|
|
/* 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(");
|
|
for(index = check_index; clause->pattern[index]; ++index)
|
|
{
|
|
if(index == 0)
|
|
arg = arg1;
|
|
else if(index == 1)
|
|
arg = arg2;
|
|
else
|
|
arg = arg3;
|
|
switch(clause->pattern[index])
|
|
{
|
|
case GENSEL_PATT_REG:
|
|
case GENSEL_PATT_LREG:
|
|
case GENSEL_PATT_FREG:
|
|
{
|
|
printf("%s->in_register", arg);
|
|
}
|
|
break;
|
|
|
|
case GENSEL_PATT_IMM:
|
|
{
|
|
printf("%s->is_constant", arg);
|
|
}
|
|
break;
|
|
|
|
case GENSEL_PATT_IMMZERO:
|
|
{
|
|
printf("%s->is_nint_constant && ", arg);
|
|
printf("%s->address == 0", arg);
|
|
}
|
|
break;
|
|
|
|
case GENSEL_PATT_IMMS8:
|
|
{
|
|
printf("%s->is_nint_constant && ", arg);
|
|
printf("%s->address >= -128 && ", arg);
|
|
printf("%s->address <= 127", arg);
|
|
}
|
|
break;
|
|
|
|
case GENSEL_PATT_IMMU8:
|
|
{
|
|
printf("%s->is_nint_constant && ", arg);
|
|
printf("%s->address >= 0 && ", arg);
|
|
printf("%s->address <= 255", arg);
|
|
}
|
|
break;
|
|
|
|
case GENSEL_PATT_IMMS16:
|
|
{
|
|
printf("%s->is_nint_constant && ", arg);
|
|
printf("%s->address >= -32768 && ", arg);
|
|
printf("%s->address <= 32767", arg);
|
|
}
|
|
break;
|
|
|
|
case GENSEL_PATT_IMMU16:
|
|
{
|
|
printf("%s->is_nint_constant && ", arg);
|
|
printf("%s->address >= 0 && ", arg);
|
|
printf("%s->address <= 65535", arg);
|
|
}
|
|
break;
|
|
|
|
case GENSEL_PATT_LOCAL:
|
|
{
|
|
printf("%s->in_frame && !(%s->in_register)", arg, arg);
|
|
}
|
|
break;
|
|
}
|
|
if(clause->pattern[index + 1])
|
|
{
|
|
printf(" && ");
|
|
}
|
|
}
|
|
printf(")\n\t{\n");
|
|
}
|
|
else if(first)
|
|
{
|
|
printf("\t{\n");
|
|
}
|
|
else
|
|
{
|
|
printf("\telse\n\t{\n");
|
|
}
|
|
if((options & GENSEL_OPT_STACK) == 0 || clause->next)
|
|
{
|
|
for(index = check_index; clause->pattern[index]; ++index)
|
|
{
|
|
if(index == 0)
|
|
{
|
|
arg = arg1;
|
|
reg = "reg";
|
|
flag = flag1;
|
|
destroy = destroy1;
|
|
}
|
|
else if(index == 1)
|
|
{
|
|
arg = arg2;
|
|
reg = "reg2";
|
|
flag = flag2;
|
|
destroy = destroy2;
|
|
}
|
|
else
|
|
{
|
|
arg = arg3;
|
|
reg = "reg3";
|
|
flag = flag3;
|
|
destroy = destroy3;
|
|
}
|
|
switch(clause->pattern[index])
|
|
{
|
|
case GENSEL_PATT_REG:
|
|
case GENSEL_PATT_LREG:
|
|
case GENSEL_PATT_FREG:
|
|
{
|
|
printf("\t\t%s = _jit_regs_load_value(gen, %s, %d, ",
|
|
reg, arg, destroy);
|
|
printf("(insn->flags & (JIT_INSN_%s_NEXT_USE | "
|
|
"JIT_INSN_%s_LIVE)));\n",
|
|
flag, flag);
|
|
}
|
|
break;
|
|
|
|
case GENSEL_PATT_IMMZERO: break;
|
|
|
|
case GENSEL_PATT_IMM:
|
|
case GENSEL_PATT_IMMS8:
|
|
case GENSEL_PATT_IMMU8:
|
|
case GENSEL_PATT_IMMS16:
|
|
case GENSEL_PATT_IMMU16:
|
|
{
|
|
printf("\t\timm_value = %s->address;\n", arg);
|
|
}
|
|
break;
|
|
|
|
case GENSEL_PATT_LOCAL:
|
|
{
|
|
printf("\t\tlocal_offset = %s->frame_offset;\n", arg);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if((options & GENSEL_OPT_ONLY) != 0)
|
|
{
|
|
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");
|
|
}
|
|
if((options & GENSEL_OPT_TERNARY) != 0)
|
|
{
|
|
printf("\t\treg = _jit_regs_load_to_top_three\n");
|
|
printf("\t\t\t(gen, insn->dest, insn->value1, insn->value2,\n");
|
|
printf("\t\t\t\t(insn->flags & (JIT_INSN_DEST_NEXT_USE | "
|
|
"JIT_INSN_DEST_LIVE)),\n");
|
|
printf("\t\t\t\t(insn->flags & (JIT_INSN_VALUE1_NEXT_USE | "
|
|
"JIT_INSN_VALUE1_LIVE)),\n");
|
|
printf("\t\t\t\t(insn->flags & (JIT_INSN_VALUE2_NEXT_USE | "
|
|
"JIT_INSN_VALUE2_LIVE)), "
|
|
"%d);\n",
|
|
gensel_first_stack_reg);
|
|
}
|
|
else if((options & (GENSEL_OPT_BINARY |
|
|
GENSEL_OPT_BINARY_BRANCH)) != 0)
|
|
{
|
|
printf("\t\treg = _jit_regs_load_to_top_two\n");
|
|
printf("\t\t\t(gen, insn->value1, insn->value2,\n");
|
|
printf("\t\t\t\t(insn->flags & (JIT_INSN_VALUE1_NEXT_USE | "
|
|
"JIT_INSN_VALUE1_LIVE)),\n");
|
|
printf("\t\t\t\t(insn->flags & (JIT_INSN_VALUE2_NEXT_USE | "
|
|
"JIT_INSN_VALUE2_LIVE)), "
|
|
"%d);\n",
|
|
gensel_first_stack_reg);
|
|
}
|
|
else if((options & (GENSEL_OPT_UNARY |
|
|
GENSEL_OPT_UNARY_BRANCH |
|
|
GENSEL_OPT_UNARY_NOTE)) != 0)
|
|
{
|
|
printf("\t\treg = _jit_regs_load_to_top\n");
|
|
printf("\t\t\t(gen, insn->value1,\n");
|
|
printf("\t\t\t\t(insn->flags & (JIT_INSN_VALUE1_NEXT_USE | "
|
|
"JIT_INSN_VALUE1_LIVE)), "
|
|
"%d);\n",
|
|
gensel_first_stack_reg);
|
|
}
|
|
}
|
|
if((options & (GENSEL_OPT_BINARY_BRANCH |
|
|
GENSEL_OPT_UNARY_BRANCH)) != 0)
|
|
{
|
|
/* 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}\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 {
|
|
char *name;
|
|
struct
|
|
{
|
|
char *filename;
|
|
long linenum;
|
|
char *block;
|
|
} code;
|
|
int options;
|
|
struct
|
|
{
|
|
int elem[8];
|
|
int size;
|
|
|
|
} pattern;
|
|
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 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_SPILL_BEFORE "`spill_before'"
|
|
%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_MORE_SPACE "`more_space'"
|
|
%token K_MANUAL "`manual'"
|
|
%token K_INST_TYPE "`%inst_type'"
|
|
|
|
/*
|
|
* Define the yylval types of the various non-terminals.
|
|
*/
|
|
%type <name> IDENTIFIER IfClause IdentifierList
|
|
%type <code> CODE_BLOCK
|
|
%type <options> Options OptionList Option PatternElement
|
|
%type <clauses> Clauses Clause
|
|
%type <pattern> Pattern Pattern2
|
|
|
|
%expect 0
|
|
|
|
%start Start
|
|
%%
|
|
|
|
Start
|
|
: /* empty */
|
|
| Rules
|
|
;
|
|
|
|
Rules
|
|
: Rule
|
|
| Rules Rule
|
|
;
|
|
|
|
Rule
|
|
: IdentifierList IfClause ':' Options Clauses {
|
|
if($2)
|
|
{
|
|
if(($2)[0] == '!')
|
|
{
|
|
printf("#ifndef %s\n\n", $2 + 1);
|
|
}
|
|
else
|
|
{
|
|
printf("#ifdef %s\n\n", $2);
|
|
}
|
|
}
|
|
printf("case %s:\n{\n", $1);
|
|
if(($4 & GENSEL_OPT_MANUAL) == 0)
|
|
{
|
|
printf("\t%s inst;\n", gensel_inst_type);
|
|
}
|
|
gensel_declare_regs($5.head, $4);
|
|
if(($4 & GENSEL_OPT_SPILL_BEFORE) != 0)
|
|
{
|
|
printf("\t_jit_regs_spill_all(gen);\n");
|
|
}
|
|
gensel_output_clauses($5.head, $4);
|
|
if(($4 & (GENSEL_OPT_BINARY | GENSEL_OPT_UNARY)) != 0)
|
|
{
|
|
printf("\tif((insn->flags & JIT_INSN_DEST_NEXT_USE) != 0)\n");
|
|
printf("\t{\n");
|
|
printf("\t\t_jit_regs_set_value(gen, reg, insn->dest, 0);\n");
|
|
printf("\t}\n");
|
|
printf("\telse\n");
|
|
printf("\t{\n");
|
|
printf("\t\t_jit_gen_spill_reg(gen, reg, -1, insn->dest);\n");
|
|
printf("\t\tif(insn->dest->has_global_register)\n");
|
|
printf("\t\t\tinsn->dest->in_global_register = 1;\n");
|
|
printf("\t\telse\n");
|
|
printf("\t\t\tinsn->dest->in_frame = 1;\n");
|
|
printf("\t\t_jit_regs_free_reg(gen, reg, 1);\n");
|
|
printf("\t}\n");
|
|
}
|
|
printf("}\nbreak;\n\n");
|
|
if($2)
|
|
{
|
|
printf("#endif /* %s */\n\n", $2);
|
|
}
|
|
gensel_free_clauses($5.head);
|
|
gensel_add_supported($1, $2);
|
|
}
|
|
| K_INST_TYPE IDENTIFIER {
|
|
gensel_inst_type = $2;
|
|
gensel_new_inst_type = 1;
|
|
}
|
|
;
|
|
|
|
IdentifierList
|
|
: IDENTIFIER { $$ = $1; }
|
|
| IdentifierList ',' IDENTIFIER {
|
|
char *result = (char *)malloc(strlen($1) + strlen($3) + 16);
|
|
if(!result)
|
|
{
|
|
exit(1);
|
|
}
|
|
strcpy(result, $1);
|
|
strcat(result, ":\ncase ");
|
|
strcat(result, $3);
|
|
free($1);
|
|
free($3);
|
|
$$ = result;
|
|
}
|
|
;
|
|
|
|
IfClause
|
|
: /* empty */ { $$ = 0; }
|
|
| '(' IDENTIFIER ')' { $$ = $2; }
|
|
;
|
|
|
|
Options
|
|
: /* empty */ { $$ = 0; }
|
|
| OptionList { $$ = $1; }
|
|
;
|
|
|
|
OptionList
|
|
: Option { $$ = $1; }
|
|
| OptionList ',' Option { $$ = $1 | $3; }
|
|
;
|
|
|
|
Option
|
|
: K_SPILL_BEFORE { $$ = GENSEL_OPT_SPILL_BEFORE; }
|
|
| K_BINARY { $$ = GENSEL_OPT_BINARY; }
|
|
| K_UNARY { $$ = GENSEL_OPT_UNARY; }
|
|
| K_UNARY_BRANCH { $$ = GENSEL_OPT_UNARY_BRANCH; }
|
|
| K_BINARY_BRANCH { $$ = GENSEL_OPT_BINARY_BRANCH; }
|
|
| K_UNARY_NOTE { $$ = GENSEL_OPT_UNARY_NOTE; }
|
|
| K_BINARY_NOTE { $$ = GENSEL_OPT_BINARY_NOTE; }
|
|
| K_TERNARY { $$ = GENSEL_OPT_TERNARY; }
|
|
| K_STACK { $$ = GENSEL_OPT_STACK; }
|
|
| K_ONLY { $$ = GENSEL_OPT_ONLY; }
|
|
| K_MORE_SPACE { $$ = GENSEL_OPT_MORE_SPACE; }
|
|
| K_MANUAL { $$ = GENSEL_OPT_MANUAL; }
|
|
;
|
|
|
|
Clauses
|
|
: Clause { $$ = $1; }
|
|
| Clauses Clause {
|
|
$1.tail->next = $2.head;
|
|
$$.head = $1.head;
|
|
$$.tail = $2.tail;
|
|
}
|
|
;
|
|
|
|
Clause
|
|
: '[' Pattern ']' K_PTR CODE_BLOCK {
|
|
gensel_clause_t clause;
|
|
int index;
|
|
clause = (gensel_clause_t)malloc(sizeof(struct gensel_clause));
|
|
if(!clause)
|
|
{
|
|
exit(1);
|
|
}
|
|
for(index = 0; index < 8; ++index)
|
|
{
|
|
clause->pattern[index] = $2.elem[index];
|
|
}
|
|
clause->filename = $5.filename;
|
|
clause->linenum = $5.linenum;
|
|
clause->code = $5.block;
|
|
clause->next = 0;
|
|
$$.head = clause;
|
|
$$.tail = clause;
|
|
}
|
|
;
|
|
|
|
Pattern
|
|
: /* empty */ {
|
|
$$.elem[0] = GENSEL_PATT_END;
|
|
$$.size = 0;
|
|
}
|
|
| Pattern2 { $$ = $1; }
|
|
;
|
|
|
|
Pattern2
|
|
: PatternElement {
|
|
$$.elem[0] = $1;
|
|
$$.elem[1] = GENSEL_PATT_END;
|
|
$$.size = 1;
|
|
}
|
|
| Pattern2 ',' PatternElement {
|
|
$$.elem[$1.size] = $3;
|
|
$$.elem[$1.size + 1] = GENSEL_PATT_END;
|
|
$$.size = $1.size + 1;
|
|
}
|
|
;
|
|
|
|
PatternElement
|
|
: K_REG { $$ = GENSEL_PATT_REG; }
|
|
| K_LREG { $$ = GENSEL_PATT_LREG; }
|
|
| K_FREG { $$ = GENSEL_PATT_FREG; }
|
|
| K_IMM { $$ = GENSEL_PATT_IMM; }
|
|
| K_IMMZERO { $$ = GENSEL_PATT_IMMZERO; }
|
|
| K_IMMS8 { $$ = GENSEL_PATT_IMMS8; }
|
|
| K_IMMU8 { $$ = GENSEL_PATT_IMMU8; }
|
|
| K_IMMS16 { $$ = GENSEL_PATT_IMMS16; }
|
|
| K_IMMU16 { $$ = GENSEL_PATT_IMMU16; }
|
|
| K_LOCAL { $$ = GENSEL_PATT_LOCAL; }
|
|
;
|
|
|
|
%%
|
|
|
|
#define COPYRIGHT_MSG \
|
|
" * Copyright (C) 2004 Southern Storm Software, Pty Ltd.\n" \
|
|
" *\n" \
|
|
" * This program is free software; you can redistribute it and/or modify\n" \
|
|
" * it under the terms of the GNU General Public License as published by\n" \
|
|
" * the Free Software Foundation; either version 2 of the License, or\n" \
|
|
" * (at your option) any later version.\n" \
|
|
" *\n" \
|
|
" * This program is distributed in the hope that it will be useful,\n" \
|
|
" * but WITHOUT ANY WARRANTY; without even the implied warranty of\n" \
|
|
" * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" \
|
|
" * GNU General Public License for more details.\n" \
|
|
" *\n" \
|
|
" * You should have received a copy of the GNU General Public License\n" \
|
|
" * along with this program; if not, write to the Free Software\n" \
|
|
" * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
FILE *file;
|
|
if(argc != 2)
|
|
{
|
|
fprintf(stderr, "Usage: %s input.sel >output.slc\n", argv[0]);
|
|
return 1;
|
|
}
|
|
file = fopen(argv[1], "r");
|
|
if(!file)
|
|
{
|
|
perror(argv[1]);
|
|
return 1;
|
|
}
|
|
printf("/%c Automatically generated from %s - DO NOT EDIT %c/\n",
|
|
'*', argv[1], '*');
|
|
printf("/%c\n%s%c/\n\n", '*', COPYRIGHT_MSG, '*');
|
|
printf("#if defined(JIT_INCLUDE_RULES)\n\n");
|
|
gensel_filename = argv[1];
|
|
gensel_linenum = 1;
|
|
yyrestart(file);
|
|
if(yyparse())
|
|
{
|
|
fclose(file);
|
|
return 1;
|
|
}
|
|
fclose(file);
|
|
printf("#elif defined(JIT_INCLUDE_SUPPORTED)\n\n");
|
|
gensel_output_supported();
|
|
printf("#endif\n");
|
|
return 0;
|
|
}
|
|
|