%{ /* * gen-ops-parser.y - Bison grammar for the "gen-ops" program. * * Copyright (C) 2010 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 /* * The task to execute */ #define TASK_GEN_NONE 0 #define TASK_GEN_HEADER 1 #define TASK_GEN_TABLE 2 #define TASK_GEN_CF_TABLE 3 /* * Value Flags */ #define VALUE_FLAG_EMPTY 0 #define VALUE_FLAG_INT 1 #define VALUE_FLAG_LONG 2 #define VALUE_FLAG_FLOAT32 3 #define VALUE_FLAG_FLOAT64 4 #define VALUE_FLAG_NFLOAT 5 #define VALUE_FLAG_ANY 6 #define VALUE_FLAG_PTR 7 /* * Opcode type flags */ #define OP_TYPE_BRANCH 0x0001 #define OP_TYPE_CALL 0x0002 #define OP_TYPE_CALL_EXTERNAL 0x0004 #define OP_TYPE_ADDRESS_OF_LABEL 0x0008 #define OP_TYPE_JUMP_TABLE 0x0010 #define OP_TYPE_REG 0x0020 /* * Operations */ #define OP_NONE 0x00 #define OP_ADD 0x01 #define OP_SUB 0x02 #define OP_MUL 0x03 #define OP_DIV 0x04 #define OP_REM 0x05 #define OP_NEG 0x06 #define OP_AND 0x07 #define OP_OR 0x08 #define OP_XOR 0x09 #define OP_NOT 0x0A #define OP_EQ 0x0B #define OP_NE 0x0C #define OP_LT 0x0D #define OP_LE 0x0E #define OP_GT 0x0F #define OP_GE 0x10 #define OP_SHL 0x11 #define OP_SHR 0x12 #define OP_SHR_UN 0x13 #define OP_COPY 0x14 #define OP_ADDRESS_OF 0x15 /* * Intrinisc signatures */ #define SIG_NONE 0 #define SIG_i_i 1 #define SIG_i_ii 2 #define SIG_i_piii 3 #define SIG_i_iI 4 #define SIG_i_II 5 #define SIG_I_I 6 #define SIG_I_II 7 #define SIG_i_pIII 8 #define SIG_l_l 9 #define SIG_l_ll 10 #define SIG_i_plll 11 #define SIG_i_l 12 #define SIG_i_ll 13 #define SIG_l_lI 14 #define SIG_L_L 15 #define SIG_L_LL 16 #define SIG_i_pLLL 17 #define SIG_i_LL 18 #define SIG_L_LI 19 #define SIG_f_f 20 #define SIG_f_ff 21 #define SIG_i_f 22 #define SIG_i_ff 23 #define SIG_d_d 24 #define SIG_d_dd 25 #define SIG_i_d 26 #define SIG_i_dd 27 #define SIG_D_D 28 #define SIG_D_DD 29 #define SIG_i_D 30 #define SIG_i_DD 31 #define SIG_conv 32 #define SIG_conv_ovf 33 /* * Current file and line number. */ extern char *genops_filename; extern long genops_linenum; struct intrinsic_info { const char *flags; int signature; const char *intrinsic; }; struct genops_opcode { struct genops_opcode *next; const char *name; int type; int oper; int dest_flags; int input1_flags; int input2_flags; const char *expression; struct intrinsic_info intrinsic_info; }; /* * Opcode declaration list header */ struct genops_opcode_list { const char *declaration; const char *define_start; const char *counter_prefix_expr; struct genops_opcode *first_opcode; struct genops_opcode *last_opcode; }; /* * The task to execute. */ static int genops_task = TASK_GEN_NONE; /* * The file to execute */ static FILE *genops_file = 0; static int genops_file_needs_close = 0; /* * options */ static int genops_gen_intrinsic_table = 0; static const char *genops_intrinsic_decl = 0; /* * Blocks coppied to the resulting file. */ static const char *start_code_block = 0; static const char *start_header_block = 0; static const char *end_code_block = 0; static const char *end_header_block = 0; /* * Current opcode declaration header */ static struct genops_opcode_list *opcode_header = 0; /* * Report error message. */ static void genops_error_message(char *filename, long linenum, char *msg) { fprintf(stderr, "%s(%ld): %s\n", filename, linenum, msg); } /* * Report error messages from the parser. */ static void yyerror(char *msg) { genops_error_message(genops_filename, genops_linenum, msg); } /* * Create an opcode declaration header. */ static void genops_create_opcode_header(const char *define_start, const char *declaration, const char *counter_prefix_expr) { struct genops_opcode_list *header; header = (struct genops_opcode_list *)malloc(sizeof(struct genops_opcode_list)); if(!header) { exit(1); } if(counter_prefix_expr && (strlen(counter_prefix_expr) == 0)) { counter_prefix_expr = 0; } header->declaration = declaration; header->define_start = define_start; header->counter_prefix_expr = counter_prefix_expr; header->first_opcode = 0; header->last_opcode = 0; opcode_header = header; } /* * Create an opcode entry */ static struct genops_opcode * genops_add_opcode(const char *name, int type, int oper, int dest_flags, int input1_flags, int input2_flags, const char *expression, const char *intrinsic_flags, int signature, const char *intrinsic) { struct genops_opcode *opcode; opcode = (struct genops_opcode *) malloc(sizeof(struct genops_opcode)); if(!opcode) { exit(1); } if(opcode_header->first_opcode == 0) { opcode_header->first_opcode = opcode; } if(opcode_header->last_opcode != 0) { opcode_header->last_opcode->next = opcode; } opcode_header->last_opcode = opcode; opcode->next = 0; opcode->name = name; opcode->type = type; opcode->oper = oper; opcode->dest_flags = dest_flags; opcode->input1_flags= input1_flags; opcode->input2_flags= input2_flags; opcode->expression = expression; opcode->intrinsic_info.flags = intrinsic_flags; opcode->intrinsic_info.signature = signature; opcode->intrinsic_info.intrinsic = intrinsic; return opcode; } static int genops_output_flag(const char *flag, int needs_or) { if(needs_or) printf(" | "); printf(flag); return 1; } static int genops_output_prefix_flag(const char *prefix, const char *flag, int needs_or) { if(needs_or) printf(" | "); printf("%s%s", prefix, flag); return 1; } static int genops_output_type(int type, int needs_or) { if(type & OP_TYPE_BRANCH) { needs_or = genops_output_flag("JIT_OPCODE_IS_BRANCH", needs_or); } if(type & OP_TYPE_CALL) { needs_or = genops_output_flag("JIT_OPCODE_IS_CALL", needs_or); } if(type & OP_TYPE_CALL_EXTERNAL) { needs_or = genops_output_flag("JIT_OPCODE_IS_CALL_EXTERNAL", needs_or); } if(type & OP_TYPE_ADDRESS_OF_LABEL) { needs_or = genops_output_flag("JIT_OPCODE_IS_ADDROF_LABEL", needs_or); } if(type & OP_TYPE_JUMP_TABLE) { needs_or = genops_output_flag("JIT_OPCODE_IS_JUMP_TABLE", needs_or); } if(type & OP_TYPE_REG) { needs_or = genops_output_flag("JIT_OPCODE_IS_REG", needs_or); } return needs_or; } static int genops_output_expression(const char *expression, int needs_or) { if(expression && (strlen(expression) > 0)) { needs_or = genops_output_flag(expression, needs_or); } return needs_or; } static int genops_output_oper(int oper, int needs_or) { switch(oper) { case OP_ADD: { return genops_output_flag ("JIT_OPCODE_OPER_ADD", needs_or); } break; case OP_SUB: { return genops_output_flag ("JIT_OPCODE_OPER_SUB", needs_or); } break; case OP_MUL: { return genops_output_flag ("JIT_OPCODE_OPER_MUL", needs_or); } break; case OP_DIV: { return genops_output_flag ("JIT_OPCODE_OPER_DIV", needs_or); } break; case OP_REM: { return genops_output_flag ("JIT_OPCODE_OPER_REM", needs_or); } break; case OP_NEG: { return genops_output_flag ("JIT_OPCODE_OPER_NEG", needs_or); } break; case OP_AND: { return genops_output_flag ("JIT_OPCODE_OPER_AND", needs_or); } break; case OP_OR: { return genops_output_flag ("JIT_OPCODE_OPER_OR", needs_or); } break; case OP_XOR: { return genops_output_flag ("JIT_OPCODE_OPER_XOR", needs_or); } break; case OP_NOT: { return genops_output_flag ("JIT_OPCODE_OPER_NOT", needs_or); } break; case OP_EQ: { return genops_output_flag ("JIT_OPCODE_OPER_EQ", needs_or); } break; case OP_NE: { return genops_output_flag ("JIT_OPCODE_OPER_NE", needs_or); } break; case OP_LT: { return genops_output_flag ("JIT_OPCODE_OPER_LT", needs_or); } break; case OP_LE: { return genops_output_flag ("JIT_OPCODE_OPER_LE", needs_or); } break; case OP_GT: { return genops_output_flag ("JIT_OPCODE_OPER_GT", needs_or); } break; case OP_GE: { return genops_output_flag ("JIT_OPCODE_OPER_GE", needs_or); } break; case OP_SHL: { return genops_output_flag ("JIT_OPCODE_OPER_SHL", needs_or); } break; case OP_SHR: { return genops_output_flag ("JIT_OPCODE_OPER_SHR", needs_or); } break; case OP_SHR_UN: { return genops_output_flag ("JIT_OPCODE_OPER_SHR_UN", needs_or); } break; case OP_COPY: { return genops_output_flag ("JIT_OPCODE_OPER_COPY", needs_or); } break; case OP_ADDRESS_OF: { return genops_output_flag ("JIT_OPCODE_OPER_ADDRESS_OF", needs_or); } break; } return needs_or; } static int genops_output_value_flags(const char *prefix, int flags, int needs_or) { switch(flags) { case VALUE_FLAG_EMPTY: { /* Nothing to do here */ } break; case VALUE_FLAG_INT: { return genops_output_prefix_flag (prefix, "_INT", needs_or); } break; case VALUE_FLAG_LONG: { return genops_output_prefix_flag (prefix, "_LONG", needs_or); } break; case VALUE_FLAG_FLOAT32: { return genops_output_prefix_flag (prefix, "_FLOAT32", needs_or); } break; case VALUE_FLAG_FLOAT64: { return genops_output_prefix_flag (prefix, "_FLOAT64", needs_or); } break; case VALUE_FLAG_NFLOAT: { return genops_output_prefix_flag (prefix, "_NFLOAT", needs_or); } break; case VALUE_FLAG_ANY: { return genops_output_prefix_flag (prefix, "_ANY", needs_or); } break; case VALUE_FLAG_PTR: { return genops_output_prefix_flag (prefix, "_PTR", needs_or); } break; } return needs_or; } /* * */ static void genops_output_signature(int signature) { switch(signature) { case SIG_NONE: { printf("JIT_SIG_NONE"); } break; case SIG_i_i: { printf("JIT_SIG_i_i"); } break; case SIG_i_ii: { printf("JIT_SIG_i_ii"); } break; case SIG_i_piii: { printf("JIT_SIG_i_piii"); } break; case SIG_i_iI: { printf("JIT_SIG_i_iI"); } break; case SIG_i_II: { printf("JIT_SIG_i_II"); } break; case SIG_I_I: { printf("JIT_SIG_I_I"); } break; case SIG_I_II: { printf("JIT_SIG_I_II"); } break; case SIG_i_pIII: { printf("JIT_SIG_i_pIII"); } break; case SIG_l_l: { printf("JIT_SIG_l_l"); } break; case SIG_l_ll: { printf("JIT_SIG_l_ll"); } break; case SIG_i_plll: { printf("JIT_SIG_i_plll"); } break; case SIG_i_l: { printf("JIT_SIG_i_l"); } break; case SIG_i_ll: { printf("JIT_SIG_i_ll"); } break; case SIG_l_lI: { printf("JIT_SIG_l_lI"); } break; case SIG_L_L: { printf("JIT_SIG_L_L"); } break; case SIG_L_LL: { printf("JIT_SIG_L_LL"); } break; case SIG_i_pLLL: { printf("JIT_SIG_i_pLLL"); } break; case SIG_i_LL: { printf("JIT_SIG_i_LL"); } break; case SIG_L_LI: { printf("JIT_SIG_L_LI"); } break; case SIG_f_f: { printf("JIT_SIG_f_f"); } break; case SIG_f_ff: { printf("JIT_SIG_f_ff"); } break; case SIG_i_f: { printf("JIT_SIG_i_f"); } break; case SIG_i_ff: { printf("JIT_SIG_i_ff"); } break; case SIG_d_d: { printf("JIT_SIG_d_d"); } break; case SIG_d_dd: { printf("JIT_SIG_d_dd"); } break; case SIG_i_d: { printf("JIT_SIG_i_d"); } break; case SIG_i_dd: { printf("JIT_SIG_i_dd"); } break; case SIG_D_D: { printf("JIT_SIG_D_D"); } break; case SIG_D_DD: { printf("JIT_SIG_D_DD"); } break; case SIG_i_D: { printf("JIT_SIG_i_D"); } break; case SIG_i_DD: { printf("JIT_SIG_i_DD"); } break; case SIG_conv: { printf("JIT_SIG_conv"); } break; case SIG_conv_ovf: { printf("JIT_SIG_conv_ovf"); } break; } } /* * Create an upper-case copy of a string. */ static char * genops_string_upper(const char *string) { if(string) { char *cp; char *new_string; new_string = strdup(string); for(cp = new_string; *cp; cp++) { *cp = toupper(*cp); } return new_string; } return 0; } static int genops_set_option(const char *option, const char *value) { if(!strcmp(option, "gen_intrinsic_table")) { if(!strcmp(value, "yes")) { genops_gen_intrinsic_table = 1; } else if(!strcmp(value, "no")) { genops_gen_intrinsic_table = 0; } else { yyerror("Invalid boolean value for the option. Allowed values: yes | no"); return 0; } } else if(!strcmp(option, "intrinsic_table_decl")) { genops_intrinsic_decl = value; } else { yyerror("Invalid option"); return 0; } return 1; } %} /* * Define the structure of yylval. */ %union { int value; char *name; struct { const char *header; const char *code; } blocks; struct { const char *declaration; const char *define_start; const char *counter_prefix_expr; } opcode_list_header; struct { const char *name; int oper; } opcode_header; struct { int dest_flags; int input1_flags; int input2_flags; } opcode_values; struct { int type; int dest_flags; int input1_flags; int input2_flags; const char *expression; const char *intrinsic_flags; int signature; const char *intrinsic; } opcode_properties; struct { const char *intrinsic_flags; int signature; const char *intrinsic; } intrinsic_info; struct { const char *name; int type; int oper; int dest_flags; int input1_flags; int input2_flags; const char *expression; const char *intrinsic_flags; int signature; const char *intrinsic; } opcode; } /* * Primitive lexical tokens and keywords. */ %token IDENTIFIER "an identifier" %token CODE_BLOCK "a block copied to the code" %token HEADER_BLOCK "a block copied to the header" %token LITERAL "literal string" %token K_EMPTY "empty" %token K_ANY "any" %token K_INT "int" %token K_LONG "long" %token K_PTR "ptr" %token K_FLOAT32 "float32" %token K_FLOAT64 "float64" %token K_NFLOAT "nfloat" %token K_NEG "neg" %token K_EQ "==" %token K_NE "!=" %token K_LT "lt" %token K_LE "<=" %token K_GT "gt" %token K_GE ">=" %token K_SHL "<<" %token K_SHR ">>" %token K_SHR_UN "shr_un" %token K_ADDRESS_OF "address_of" %token K_ADDRESS_OF_LABEL "address_of_label" %token K_BRANCH "branch" %token K_CALL "call" %token K_CALL_EXTERNAL "call_external" %token K_JUMP_TABLE "jump_table" %token K_OP_DEF "op_def" %token K_OP_INTRINSIC "op_intrinsic" %token K_OP_TYPE "op_type" %token K_OP_VALUES "op_values" %token K_OPCODES "opcodes" %token K_REG "reg" %token K_POPTION "%option" %token K_i_i "i_i" %token K_i_ii "i_ii" %token K_i_piii "i_piii" %token K_i_iI "i_iI" %token K_i_II "i_II" %token K_I_I "I_I" %token K_I_II "I_II" %token K_i_pIII "i_pIII" %token K_l_l "l_l" %token K_l_ll "l_ll" %token K_i_plll "i_plll" %token K_i_l "i_l" %token K_i_ll "i_ll" %token K_l_lI "l_lI" %token K_L_L "L_L" %token K_L_LL "L_LL" %token K_i_pLLL "i_pLLL" %token K_i_LL "i_LL" %token K_L_LI "L_LI" %token K_f_f "f_f" %token K_f_ff "f_ff" %token K_i_f "i_f" %token K_i_ff "i_ff" %token K_d_d "d_d" %token K_d_dd "d_dd" %token K_i_d "i_d" %token K_i_dd "i_dd" %token K_D_D "D_D" %token K_D_DD "D_DD" %token K_i_D "i_D" %token K_i_DD "i_DD" %token K_CONV "conv" %token K_CONV_OVF "conv_ovf" /* * Define the yylval types of the various non-terminals. */ %type CODE_BLOCK HEADER_BLOCK %type IDENTIFIER LITERAL Literal %type Blocks %type OpcodeListHeader %type ValueFlag Op %type OpcodeType OpcodeTypeFlag %type Signature %type OpcodeExpression %type Opcode %type OpcodeHeader %type OpcodeProperties %type OpcodeValues %type OpcodeIntrinsicInfo %expect 0 %error-verbose %start Start %% Start : Blocks OptOptions OpcodeDeclarations Blocks { start_code_block = ($1).code; start_header_block = ($1).header; end_code_block = ($4).code;; end_header_block = ($4).header; } ; Blocks : /* empty */ { ($$).header = 0; ($$).code = 0; } | CODE_BLOCK { ($$).header = 0; ($$).code = $1; } | HEADER_BLOCK { ($$).header = $1; ($$).code = 0; } | CODE_BLOCK HEADER_BLOCK { ($$).code = $1; ($$).header = $2; } | HEADER_BLOCK CODE_BLOCK { ($$).code = $2; ($$).header = $1; } ; OpcodeDeclarations : OpcodeListHeader { genops_create_opcode_header(($1).declaration, ($1).define_start, ($1).counter_prefix_expr); } '{' Opcodes '}' ; OpcodeListHeader : K_OPCODES '(' IDENTIFIER ',' Literal ')' { ($$).declaration = $3; ($$).define_start = $5; ($$).counter_prefix_expr = 0; } | K_OPCODES '(' IDENTIFIER ',' Literal ',' Literal ')' { ($$).declaration = $3; ($$).define_start = $5; ($$).counter_prefix_expr = $7; } ; Opcodes : Opcode { genops_add_opcode(($1).name, ($1).type, ($1).oper, ($1).dest_flags, ($1).input1_flags, ($1).input2_flags, ($1).expression, ($1).intrinsic_flags, ($1).signature, ($1).intrinsic); } | Opcodes Opcode { genops_add_opcode(($2).name, ($2).type, ($2).oper, ($2).dest_flags, ($2).input1_flags, ($2).input2_flags, ($2).expression, ($2).intrinsic_flags, ($2).signature, ($2).intrinsic); } ; Opcode : OpcodeHeader '{' '}' { ($$).name = ($1).name; ($$).type = 0; ($$).oper = ($1).oper; ($$).dest_flags = VALUE_FLAG_EMPTY; ($$).input1_flags = VALUE_FLAG_EMPTY; ($$).input2_flags = VALUE_FLAG_EMPTY; ($$).expression = 0; ($$).intrinsic_flags = 0; ($$).signature = SIG_NONE; ($$).intrinsic = 0;; } | OpcodeHeader '{' OpcodeProperties '}' { ($$).name = ($1).name; ($$).type = ($3).type; ($$).oper = ($1).oper; ($$).dest_flags = ($3).dest_flags; ($$).input1_flags = ($3).input1_flags; ($$).input2_flags = ($3).input2_flags; ($$).expression = ($3).expression; ($$).intrinsic_flags = ($3).intrinsic_flags; ($$).signature = ($3).signature; ($$).intrinsic = ($3).intrinsic;; } ; OpcodeHeader : K_OP_DEF '(' LITERAL ')' { ($$).name = $3; ($$).oper = OP_NONE; } | K_OP_DEF '(' LITERAL ',' Op ')' { ($$).name = $3; ($$).oper = $5; } ; OpcodeProperties : OpcodeType { ($$).type = $1; ($$).dest_flags = VALUE_FLAG_EMPTY; ($$).input1_flags = VALUE_FLAG_EMPTY; ($$).input2_flags = VALUE_FLAG_EMPTY; ($$).expression = 0; ($$).intrinsic_flags = 0; ($$).signature = SIG_NONE; ($$).intrinsic = 0;; } | OpcodeValues { ($$).type = 0; ($$).dest_flags = ($1).dest_flags; ($$).input1_flags = ($1).input1_flags; ($$).input2_flags = ($1).input2_flags; ($$).expression = 0; ($$).intrinsic_flags = 0; ($$).signature = SIG_NONE; ($$).intrinsic = 0;; } | OpcodeExpression { ($$).type = 0; ($$).dest_flags = VALUE_FLAG_EMPTY; ($$).input1_flags = VALUE_FLAG_EMPTY; ($$).input2_flags = VALUE_FLAG_EMPTY; ($$).expression = $1; ($$).intrinsic_flags = 0; ($$).signature = SIG_NONE; ($$).intrinsic = 0;; } | OpcodeIntrinsicInfo { ($$).type = 0; ($$).dest_flags = VALUE_FLAG_EMPTY; ($$).input1_flags = VALUE_FLAG_EMPTY; ($$).input2_flags = VALUE_FLAG_EMPTY; ($$).expression = 0; ($$).intrinsic_flags = ($1).intrinsic_flags; ($$).signature = ($1).signature; ($$).intrinsic = ($1).intrinsic;; } | OpcodeProperties ',' OpcodeType { ($$).type = $3; ($$).dest_flags = ($1).dest_flags; ($$).input1_flags = ($1).input1_flags; ($$).input2_flags = ($1).input2_flags; ($$).expression = ($1).expression; ($$).intrinsic_flags = ($1).intrinsic_flags; ($$).signature = ($1).signature; ($$).intrinsic = ($1).intrinsic;; } | OpcodeProperties ',' OpcodeValues { ($$).type = ($1).type; ($$).dest_flags = ($3).dest_flags; ($$).input1_flags = ($3).input1_flags; ($$).input2_flags = ($3).input2_flags; ($$).expression = ($1).expression; ($$).intrinsic_flags = ($1).intrinsic_flags; ($$).signature = ($1).signature; ($$).intrinsic = ($1).intrinsic;; } | OpcodeProperties ',' OpcodeExpression { ($$).type = ($1).type; ($$).dest_flags = ($1).dest_flags; ($$).input1_flags = ($1).input1_flags; ($$).input2_flags = ($1).input2_flags; ($$).expression = $3; ($$).intrinsic_flags = ($1).intrinsic_flags; ($$).signature = ($1).signature; ($$).intrinsic = ($1).intrinsic;; } | OpcodeProperties ',' OpcodeIntrinsicInfo { ($$).type = ($1).type; ($$).dest_flags = ($1).dest_flags; ($$).input1_flags = ($1).input1_flags; ($$).input2_flags = ($1).input2_flags; ($$).expression = ($1).expression; ($$).intrinsic_flags = ($3).intrinsic_flags; ($$).signature = ($3).signature; ($$).intrinsic = ($3).intrinsic;; } ; OpcodeType : K_OP_TYPE '(' OpcodeTypeFlag ')' { $$ = $3; } ; OpcodeTypeFlag : K_ADDRESS_OF_LABEL { $$ = OP_TYPE_ADDRESS_OF_LABEL; } | K_BRANCH { $$ = OP_TYPE_BRANCH; } | K_CALL { $$ = OP_TYPE_CALL; } | K_CALL_EXTERNAL { $$ = OP_TYPE_CALL_EXTERNAL; } | K_JUMP_TABLE { $$ = OP_TYPE_JUMP_TABLE; } | K_REG { $$ = OP_TYPE_REG; } ; OpcodeValues : K_OP_VALUES '(' ValueFlag ')' { ($$).dest_flags = $3; ($$).input1_flags = VALUE_FLAG_EMPTY; ($$).input2_flags = VALUE_FLAG_EMPTY; } | K_OP_VALUES '(' ValueFlag ',' ValueFlag ')' { ($$).dest_flags = $3; ($$).input1_flags = $5; ($$).input2_flags = VALUE_FLAG_EMPTY; } | K_OP_VALUES '(' ValueFlag ',' ValueFlag ',' ValueFlag ')' { ($$).dest_flags = $3; ($$).input1_flags = $5; ($$).input2_flags = $7; } ; OpcodeExpression : Literal { $$ = $1; } ; Op : /* empty */ { $$ = OP_NONE; } | '+' { $$ = OP_ADD; } | '-' { $$ = OP_SUB; } | '*' { $$ = OP_MUL; } | '/' { $$ = OP_DIV; } | '%' { $$ = OP_REM; } | K_NEG { $$ = OP_NEG; } | '&' { $$ = OP_AND; } | '|' { $$ = OP_OR; } | '^' { $$ = OP_XOR; } | '~' { $$ = OP_NOT; } | K_SHL { $$ = OP_SHL; } | K_SHR { $$ = OP_SHR; } | K_SHR_UN { $$ = OP_SHR_UN; } | K_EQ { $$ = OP_EQ; } | K_NE { $$ = OP_NE; } | K_LE { $$ = OP_LE; } | '<' { $$ = OP_LT; } | K_GE { $$ = OP_GE; } | '>' { $$ = OP_GT; } | '=' { $$ = OP_COPY; } | K_ADDRESS_OF { $$ = OP_ADDRESS_OF; } ; ValueFlag : K_EMPTY { $$ = VALUE_FLAG_EMPTY; } | K_INT { $$ = VALUE_FLAG_INT; } | K_LONG { $$ = VALUE_FLAG_LONG; } | K_PTR { $$ = VALUE_FLAG_PTR; } | K_FLOAT32 { $$ = VALUE_FLAG_FLOAT32; } | K_FLOAT64 { $$ = VALUE_FLAG_FLOAT64; } | K_NFLOAT { $$ = VALUE_FLAG_NFLOAT; } | K_ANY { $$ = VALUE_FLAG_ANY; } ; OpcodeIntrinsicInfo : K_OP_INTRINSIC '(' Literal ')' { ($$).intrinsic_flags = $3; ($$).signature = SIG_NONE; ($$).intrinsic = 0;; } | K_OP_INTRINSIC '(' Signature ')' { ($$).intrinsic_flags = 0; ($$).signature = $3; ($$).intrinsic = 0; } | K_OP_INTRINSIC '(' IDENTIFIER ',' Signature ')' { ($$).intrinsic_flags = 0; ($$).signature = $5; ($$).intrinsic = $3; } ; Signature : K_i_i { $$ = SIG_i_i; } | K_i_ii { $$ = SIG_i_ii; } | K_i_piii { $$ = SIG_i_piii; } | K_i_iI { $$ = SIG_i_iI; } | K_i_II { $$ = SIG_i_II; } | K_I_I { $$ = SIG_I_I; } | K_I_II { $$ = SIG_I_II; } | K_i_pIII { $$ = SIG_i_pIII; } | K_l_l { $$ = SIG_l_l; } | K_l_ll { $$ = SIG_l_ll; } | K_i_plll { $$ = SIG_i_plll; } | K_i_l { $$ = SIG_i_l; } | K_i_ll { $$ = SIG_i_ll; } | K_l_lI { $$ = SIG_l_lI; } | K_L_L { $$ = SIG_L_L; } | K_L_LL { $$ = SIG_L_LL; } | K_i_pLLL { $$ = SIG_i_pLLL; } | K_i_LL { $$ = SIG_i_LL; } | K_L_LI { $$ = SIG_L_LI; } | K_f_f { $$ = SIG_f_f; } | K_f_ff { $$ = SIG_f_ff; } | K_i_f { $$ = SIG_i_f; } | K_i_ff { $$ = SIG_i_ff; } | K_d_d { $$ = SIG_d_d; } | K_d_dd { $$ = SIG_d_dd; } | K_i_d { $$ = SIG_i_d; } | K_i_dd { $$ = SIG_i_dd; } | K_D_D { $$ = SIG_D_D; } | K_D_DD { $$ = SIG_D_DD; } | K_i_D { $$ = SIG_i_D; } | K_i_DD { $$ = SIG_i_DD; } | K_CONV { $$ = SIG_conv; } | K_CONV_OVF { $$ = SIG_conv_ovf; } ; Literal : LITERAL { $$ = $1; } | Literal LITERAL { char *cp = malloc(strlen($1) + strlen($2) + 1); if(!cp) { exit(1); } strcpy(cp, $1); strcat(cp, $2); free($1); free($2); $$ = cp; } ; OptOptions : /* None */ { } | Options ; Options : Option | Options Option ; Option : K_POPTION IDENTIFIER '=' IDENTIFIER { genops_set_option($2, $4); } | K_POPTION IDENTIFIER '=' Literal { genops_set_option($2, $4); } ; %% /* * Parse the commandline arguments */ static int genops_parseargs(int argc, char *argv[]) { int current; current = 1; while(current < argc - 1) { if(!strcmp(argv[current], "-H") || !strcmp(argv[current], "--header")) { genops_task = TASK_GEN_HEADER; } else if(!strcmp(argv[current], "-T") || !strcmp(argv[current], "--table")) { genops_task = TASK_GEN_TABLE; } else if(!strcmp(argv[current], "--help")) { return 1; } else { fprintf(stderr, "Invalid commandline option %s\n", argv[current]); return 1; } ++current; } if(genops_task == TASK_GEN_NONE) { return 1; } if(argc > 1) { if(strcmp(argv[argc - 1], "-")) { genops_file = fopen(argv[argc - 1], "r"); if(!genops_file) { perror(argv[argc - 1]); return 1; } genops_file_needs_close = 1; } else { genops_file = stdin; } } else { return 1; } return 0; } /* * Output the opcode declaration header */ static void genops_output_defines(const char *define_start, const char *counter_prefix_expr) { struct genops_opcode *current; int start_len; int opcode_no; int name_len; int num_tabs; start_len = strlen(define_start); opcode_no = 0; current = opcode_header->first_opcode; while(current) { char *upper_name; upper_name = genops_string_upper(current->name); if(upper_name == 0) { /* Out of memory */ perror(genops_filename); exit(1); } printf("#define\t%s%s", define_start, upper_name); name_len = strlen(upper_name) + 8 + start_len; num_tabs = 8 - name_len / 8; while(num_tabs > 0) { printf("\t"); --num_tabs; } if(counter_prefix_expr) { printf("(%s + 0x%04X)\n", counter_prefix_expr, opcode_no); } else { printf("0x%04X\n", opcode_no); } free(upper_name); current = current->next; ++opcode_no; } /* * Print the definition for the number of opcodes */ printf("#define\t%s%s", define_start, "NUM_OPCODES"); name_len = 11 + 8 + start_len; num_tabs = 8 - name_len / 8; while(num_tabs > 0) { printf("\t"); --num_tabs; } printf("0x%04X\n", opcode_no); } static void genops_output_defs(const char *filename) { printf("/%c Automatically generated from %s - DO NOT EDIT %c/\n", '*', filename, '*'); if(start_header_block) { printf("%s", start_header_block); } genops_output_defines(opcode_header->define_start, opcode_header->counter_prefix_expr); if(end_header_block) { printf("%s", end_header_block); } } /* * Output the opcode description table. */ static void genops_output_ops(void) { struct genops_opcode *current; printf("%s = {\n", opcode_header->declaration); current = opcode_header->first_opcode; while(current) { int needs_or = 0; printf("\t{\"%s\"", current->name); if(current->type || current->oper || current->dest_flags || current->input1_flags || current->input2_flags|| current->expression) printf(", "); needs_or = genops_output_type(current->type, 0); needs_or = genops_output_oper(current->oper, needs_or); needs_or = genops_output_value_flags("JIT_OPCODE_DEST", current->dest_flags, needs_or); needs_or = genops_output_value_flags("JIT_OPCODE_SRC1", current->input1_flags, needs_or); needs_or = genops_output_value_flags("JIT_OPCODE_SRC2", current->input2_flags, needs_or); needs_or = genops_output_expression(current->expression, needs_or); if(!needs_or) { /* * None of the above flags needed to be printed so * we have to add the 0 value here. */ printf(", 0"); } printf("}"); current = current->next; if(current) { printf(",\n"); } else { printf("\n"); } } printf("};\n"); } static void genops_output_intrinsic_table(const char *define_start) { struct genops_opcode *current; printf("%s = {\n", genops_intrinsic_decl); current = opcode_header->first_opcode; while(current) { printf("\t{"); if(current->intrinsic_info.flags) { printf("%s", current->intrinsic_info.flags); } else { printf("%i", 0); } printf(", "); genops_output_signature(current->intrinsic_info.signature); printf(", "); if(current->intrinsic_info.intrinsic) { printf("%s", current->intrinsic_info.intrinsic); } else { printf("0"); } printf("}"); current = current->next; if(current) { printf(",\n"); } else { printf("\n"); } } printf("};\n"); } static void genops_output_opcode_table(const char *filename) { printf("/%c Automatically generated from %s - DO NOT EDIT %c/\n", '*', filename, '*'); if(start_code_block) { printf("%s", start_code_block); } genops_output_ops(); if(genops_gen_intrinsic_table) { printf("\n"); genops_output_intrinsic_table(opcode_header->define_start); } if(end_code_block) { printf("%s", end_code_block); } } #define USAGE \ "Usage: %s option file\n" \ "Generates an opcode header or table from opcode definitions\n" \ "and writes the result to standard output\n\n" \ "Options:\n" \ " -H, --header\tgenerate a header file\n" \ " -T, --table\tgenerate a file with the opcode table\n" \ " --help\tdisplay this information\n" \ "\nExactly one of header or table option must be supplied.\n" \ "If file is - standard input is used.\n" int main(int argc, char *argv[]) { if(genops_parseargs(argc, argv)) { fprintf(stderr, USAGE, argv[0]); return 1; } genops_filename = argv[argc - 1]; genops_linenum = 1; yyrestart(genops_file); if(yyparse()) { if(genops_file_needs_close) { fclose(genops_file); } return 1; } if(genops_file_needs_close) { fclose(genops_file); } switch(genops_task) { case TASK_GEN_HEADER: { genops_output_defs(genops_filename); } break; case TASK_GEN_TABLE: { genops_output_opcode_table(genops_filename); } break; } return 0; }