diff options
Diffstat (limited to 'target/hexagon/idef-parser/idef-parser.y')
-rw-r--r-- | target/hexagon/idef-parser/idef-parser.y | 965 |
1 files changed, 965 insertions, 0 deletions
diff --git a/target/hexagon/idef-parser/idef-parser.y b/target/hexagon/idef-parser/idef-parser.y new file mode 100644 index 0000000..8be44a0 --- /dev/null +++ b/target/hexagon/idef-parser/idef-parser.y @@ -0,0 +1,965 @@ +%{ +/* + * Copyright(c) 2019-2022 rev.ng Labs Srl. All Rights Reserved. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include "idef-parser.h" +#include "parser-helpers.h" +#include "idef-parser.tab.h" +#include "idef-parser.yy.h" + +/* Uncomment this to disable yyasserts */ +/* #define NDEBUG */ + +#define ERR_LINE_CONTEXT 40 + +%} + +%lex-param {void *scanner} +%parse-param {void *scanner} +%parse-param {Context *c} + +%define parse.error verbose +%define parse.lac full +%define api.pure full + +%locations + +%union { + GString *string; + HexValue rvalue; + HexSat sat; + HexCast cast; + HexExtract extract; + HexMpy mpy; + HexSignedness signedness; + int index; +} + +/* Tokens */ +%start input + +%expect 1 + +%token IN INAME VAR +%token ABS CROUND ROUND CIRCADD COUNTONES INC DEC ANDA ORA XORA PLUSPLUS ASL +%token ASR LSR EQ NEQ LTE GTE MIN MAX ANDL FOR ICIRC IF MUN FSCR FCHK SXT +%token ZXT CONSTEXT LOCNT BREV SIGN LOAD STORE PC NPC LPCFG +%token LOAD_CANCEL CANCEL IDENTITY PART1 ROTL INSBITS SETBITS EXTRANGE +%token CAST4_8U FAIL CARRY_FROM_ADD ADDSAT64 LSBNEW +%token TYPE_SIZE_T TYPE_INT TYPE_SIGNED TYPE_UNSIGNED TYPE_LONG + +%token <rvalue> REG IMM PRED +%token <index> ELSE +%token <mpy> MPY +%token <sat> SAT +%token <cast> CAST DEPOSIT SETHALF +%token <extract> EXTRACT +%type <string> INAME +%type <rvalue> rvalue lvalue VAR assign_statement var var_decl var_type +%type <rvalue> FAIL +%type <rvalue> TYPE_SIGNED TYPE_UNSIGNED TYPE_INT TYPE_LONG TYPE_SIZE_T +%type <index> if_stmt IF +%type <signedness> SIGN + +/* Operator Precedences */ +%left MIN MAX +%left '(' +%left ',' +%left '=' +%right CIRCADD +%right INC DEC ANDA ORA XORA +%left '?' ':' +%left ANDL +%left '|' +%left '^' ANDOR +%left '&' +%left EQ NEQ +%left '<' '>' LTE GTE +%left ASL ASR LSR +%right ABS +%left '-' '+' +%left '*' '/' '%' MPY +%right '~' '!' +%left '[' +%right CAST +%right LOCNT BREV + +/* Bison Grammar */ +%% + +/* Input file containing the description of each hexagon instruction */ +input : instructions + { + YYACCEPT; + } + ; + +instructions : instruction instructions + | %empty + ; + +instruction : INAME + { + gen_inst(c, $1); + } + arguments + { + EMIT_SIG(c, ")"); + EMIT_HEAD(c, "{\n"); + } + code + { + gen_inst_code(c, &@1); + } + | error /* Recover gracefully after instruction compilation error */ + { + free_instruction(c); + } + ; + +arguments : '(' ')' + | '(' argument_list ')'; + +argument_list : argument_decl ',' argument_list + | argument_decl + ; + +var : VAR + { + track_string(c, $1.var.name); + $$ = $1; + } + ; + +/* + * Here the integer types are defined from valid combinations of + * `signed`, `unsigned`, `int`, and `long` tokens. The `signed` + * and `unsigned` tokens are here assumed to always be placed + * first in the type declaration, which is not the case in + * normal C. Similarly, `int` is assumed to always be placed + * last in the type. + */ +type_int : TYPE_INT + | TYPE_SIGNED + | TYPE_SIGNED TYPE_INT; +type_uint : TYPE_UNSIGNED + | TYPE_UNSIGNED TYPE_INT; +type_ulonglong : TYPE_UNSIGNED TYPE_LONG TYPE_LONG + | TYPE_UNSIGNED TYPE_LONG TYPE_LONG TYPE_INT; + +/* + * Here the various valid int types defined above specify + * their `signedness` and `bit_width`. The LP64 convention + * is assumed where longs are 64-bit, long longs are then + * assumed to also be 64-bit. + */ +var_type : TYPE_SIZE_T + { + yyassert(c, &@1, $1.bit_width <= 64, + "Variables with size > 64-bit are not supported!"); + $$ = $1; + } + | type_int + { + $$.signedness = SIGNED; + $$.bit_width = 32; + } + | type_uint + { + $$.signedness = UNSIGNED; + $$.bit_width = 32; + } + | type_ulonglong + { + $$.signedness = UNSIGNED; + $$.bit_width = 64; + } + ; + +/* Rule to capture declarations of VARs */ +var_decl : var_type IMM + { + /* + * Rule to capture "int i;" declarations since "i" is special + * and assumed to be always be IMM. Moreover, "i" is only + * assumed to be used in for-loops. + * + * Therefore we want to NOP these declarations. + */ + yyassert(c, &@2, $2.imm.type == I, + "Variable declaration with immedaties only allowed" + " for the loop induction variable \"i\""); + $$ = $2; + } + | var_type var + { + /* + * Allocate new variable, this checks that it hasn't already + * been declared. + */ + gen_varid_allocate(c, &@1, &$2, $1.bit_width, $1.signedness); + /* Copy var for variable name */ + $$ = $2; + /* Copy type info from var_type */ + $$.signedness = $1.signedness; + $$.bit_width = $1.bit_width; + } + ; + +/* Return the modified registers list */ +code : '{' statements '}' + { + c->inst.code_begin = c->input_buffer + @2.first_column - 1; + c->inst.code_end = c->input_buffer + @2.last_column - 1; + } + | '{' + { + /* Nop */ + } + '}' + ; + +argument_decl : REG + { + emit_arg(c, &@1, &$1); + /* Enqueue register into initialization list */ + g_array_append_val(c->inst.init_list, $1); + } + | PRED + { + emit_arg(c, &@1, &$1); + /* Enqueue predicate into initialization list */ + g_array_append_val(c->inst.init_list, $1); + } + | IN REG + { + emit_arg(c, &@2, &$2); + } + | IN PRED + { + emit_arg(c, &@2, &$2); + } + | IMM + { + EMIT_SIG(c, ", int %ciV", $1.imm.id); + } + ; + +code_block : '{' statements '}' + | '{' '}' + ; + +/* A list of one or more statements */ +statements : statements statement + | statement + ; + +/* Statements can be assignment (rvalue ';'), control or memory statements */ +statement : control_statement + | var_decl ';' + | rvalue ';' + { + gen_rvalue_free(c, &@1, &$1); + } + | code_block + | ';' + ; + +assign_statement : lvalue '=' rvalue + { + @1.last_column = @3.last_column; + gen_assign(c, &@1, &$1, &$3); + $$ = $1; + } + | var_decl '=' rvalue + { + @1.last_column = @3.last_column; + gen_assign(c, &@1, &$1, &$3); + $$ = $1; + } + | lvalue INC rvalue + { + @1.last_column = @3.last_column; + HexValue tmp = gen_bin_op(c, &@1, ADD_OP, &$1, &$3); + gen_assign(c, &@1, &$1, &tmp); + $$ = $1; + } + | lvalue DEC rvalue + { + @1.last_column = @3.last_column; + HexValue tmp = gen_bin_op(c, &@1, SUB_OP, &$1, &$3); + gen_assign(c, &@1, &$1, &tmp); + $$ = $1; + } + | lvalue ANDA rvalue + { + @1.last_column = @3.last_column; + HexValue tmp = gen_bin_op(c, &@1, ANDB_OP, &$1, &$3); + gen_assign(c, &@1, &$1, &tmp); + $$ = $1; + } + | lvalue ORA rvalue + { + @1.last_column = @3.last_column; + HexValue tmp = gen_bin_op(c, &@1, ORB_OP, &$1, &$3); + gen_assign(c, &@1, &$1, &tmp); + $$ = $1; + } + | lvalue XORA rvalue + { + @1.last_column = @3.last_column; + HexValue tmp = gen_bin_op(c, &@1, XORB_OP, &$1, &$3); + gen_assign(c, &@1, &$1, &tmp); + $$ = $1; + } + | PRED '=' rvalue + { + @1.last_column = @3.last_column; + gen_pred_assign(c, &@1, &$1, &$3); + } + | IMM '=' rvalue + { + @1.last_column = @3.last_column; + yyassert(c, &@1, $3.type == IMMEDIATE, + "Cannot assign non-immediate to immediate!"); + yyassert(c, &@1, $1.imm.type == VARIABLE, + "Cannot assign to non-variable!"); + /* Assign to the function argument */ + OUT(c, &@1, &$1, " = ", &$3, ";\n"); + $$ = $1; + } + | PC '=' rvalue + { + @1.last_column = @3.last_column; + yyassert(c, &@1, !is_inside_ternary(c), + "Assignment side-effect not modeled!"); + $3 = gen_rvalue_truncate(c, &@1, &$3); + $3 = rvalue_materialize(c, &@1, &$3); + OUT(c, &@1, "gen_write_new_pc(", &$3, ");\n"); + gen_rvalue_free(c, &@1, &$3); /* Free temporary value */ + } + | LOAD '(' IMM ',' IMM ',' SIGN ',' var ',' lvalue ')' + { + @1.last_column = @12.last_column; + yyassert(c, &@1, !is_inside_ternary(c), + "Assignment side-effect not modeled!"); + yyassert(c, &@1, $3.imm.value == 1, + "LOAD of arrays not supported!"); + gen_load(c, &@1, &$5, $7, &$9, &$11); + } + | STORE '(' IMM ',' IMM ',' var ',' rvalue ')' + /* Store primitive */ + { + @1.last_column = @10.last_column; + yyassert(c, &@1, !is_inside_ternary(c), + "Assignment side-effect not modeled!"); + yyassert(c, &@1, $3.imm.value == 1, + "STORE of arrays not supported!"); + gen_store(c, &@1, &$5, &$7, &$9); + } + | LPCFG '=' rvalue + { + @1.last_column = @3.last_column; + yyassert(c, &@1, !is_inside_ternary(c), + "Assignment side-effect not modeled!"); + $3 = gen_rvalue_truncate(c, &@1, &$3); + $3 = rvalue_materialize(c, &@1, &$3); + OUT(c, &@1, "SET_USR_FIELD(USR_LPCFG, ", &$3, ");\n"); + gen_rvalue_free(c, &@1, &$3); + } + | DEPOSIT '(' rvalue ',' rvalue ',' rvalue ')' + { + @1.last_column = @8.last_column; + yyassert(c, &@1, !is_inside_ternary(c), + "Assignment side-effect not modeled!"); + gen_deposit_op(c, &@1, &$5, &$7, &$3, &$1); + } + | SETHALF '(' rvalue ',' lvalue ',' rvalue ')' + { + @1.last_column = @8.last_column; + yyassert(c, &@1, !is_inside_ternary(c), + "Assignment side-effect not modeled!"); + gen_sethalf(c, &@1, &$1, &$3, &$5, &$7); + } + | SETBITS '(' rvalue ',' rvalue ',' rvalue ',' rvalue ')' + { + @1.last_column = @10.last_column; + yyassert(c, &@1, !is_inside_ternary(c), + "Assignment side-effect not modeled!"); + gen_setbits(c, &@1, &$3, &$5, &$7, &$9); + } + | INSBITS '(' lvalue ',' rvalue ',' rvalue ',' rvalue ')' + { + @1.last_column = @10.last_column; + yyassert(c, &@1, !is_inside_ternary(c), + "Assignment side-effect not modeled!"); + gen_rdeposit_op(c, &@1, &$3, &$9, &$7, &$5); + } + | IDENTITY '(' rvalue ')' + { + @1.last_column = @4.last_column; + $$ = $3; + } + ; + +control_statement : frame_check + | cancel_statement + | if_statement + | for_statement + | fpart1_statement + ; + +frame_check : FCHK '(' rvalue ',' rvalue ')' ';' + { + gen_rvalue_free(c, &@1, &$3); + gen_rvalue_free(c, &@1, &$5); + } + ; + +cancel_statement : LOAD_CANCEL + { + gen_load_cancel(c, &@1); + } + | CANCEL + { + gen_cancel(c, &@1); + } + ; + +if_statement : if_stmt + { + /* Fix else label */ + OUT(c, &@1, "gen_set_label(if_label_", &$1, ");\n"); + } + | if_stmt ELSE + { + @1.last_column = @2.last_column; + $2 = gen_if_else(c, &@1, $1); + } + statement + { + OUT(c, &@1, "gen_set_label(if_label_", &$2, ");\n"); + } + ; + +for_statement : FOR '(' IMM '=' IMM ';' IMM '<' IMM ';' IMM PLUSPLUS ')' + { + yyassert(c, &@3, + $3.imm.type == I && + $7.imm.type == I && + $11.imm.type == I, + "Loop induction variable must be \"i\""); + @1.last_column = @13.last_column; + OUT(c, &@1, "for (int ", &$3, " = ", &$5, "; ", + &$7, " < ", &$9); + OUT(c, &@1, "; ", &$11, "++) {\n"); + } + code_block + { + OUT(c, &@1, "}\n"); + } + ; + +fpart1_statement : PART1 + { + OUT(c, &@1, "if (insn->part1) {\n"); + } + '(' statements ')' + { + @1.last_column = @3.last_column; + OUT(c, &@1, "return; }\n"); + } + ; + +if_stmt : IF '(' rvalue ')' + { + @1.last_column = @3.last_column; + $1 = gen_if_cond(c, &@1, &$3); + } + statement + { + $$ = $1; + } + ; + +rvalue : FAIL + { + yyassert(c, &@1, false, "Encountered a FAIL token as rvalue.\n"); + } + | assign_statement + | REG + { + $$ = $1; + } + | IMM + { + $$ = $1; + } + | PRED + { + $$ = gen_rvalue_pred(c, &@1, &$1); + } + | PC + { + /* Read PC from the CR */ + HexValue rvalue; + memset(&rvalue, 0, sizeof(HexValue)); + rvalue.type = IMMEDIATE; + rvalue.imm.type = IMM_PC; + rvalue.bit_width = 32; + rvalue.signedness = UNSIGNED; + $$ = rvalue; + } + | NPC + { + /* + * NPC is only read from CALLs, so we can hardcode it + * at translation time + */ + HexValue rvalue; + memset(&rvalue, 0, sizeof(HexValue)); + rvalue.type = IMMEDIATE; + rvalue.imm.type = IMM_NPC; + rvalue.bit_width = 32; + rvalue.signedness = UNSIGNED; + $$ = rvalue; + } + | CONSTEXT + { + HexValue rvalue; + memset(&rvalue, 0, sizeof(HexValue)); + rvalue.type = IMMEDIATE; + rvalue.imm.type = IMM_CONSTEXT; + rvalue.signedness = UNSIGNED; + rvalue.is_dotnew = false; + rvalue.is_manual = false; + $$ = rvalue; + } + | var + { + $$ = gen_rvalue_var(c, &@1, &$1); + } + | MPY '(' rvalue ',' rvalue ')' + { + @1.last_column = @6.last_column; + $$ = gen_rvalue_mpy(c, &@1, &$1, &$3, &$5); + } + | rvalue '+' rvalue + { + @1.last_column = @3.last_column; + $$ = gen_bin_op(c, &@1, ADD_OP, &$1, &$3); + } + | rvalue '-' rvalue + { + @1.last_column = @3.last_column; + $$ = gen_bin_op(c, &@1, SUB_OP, &$1, &$3); + } + | rvalue '*' rvalue + { + @1.last_column = @3.last_column; + $$ = gen_bin_op(c, &@1, MUL_OP, &$1, &$3); + } + | rvalue ASL rvalue + { + @1.last_column = @3.last_column; + $$ = gen_bin_op(c, &@1, ASL_OP, &$1, &$3); + } + | rvalue ASR rvalue + { + @1.last_column = @3.last_column; + assert_signedness(c, &@1, $1.signedness); + if ($1.signedness == UNSIGNED) { + $$ = gen_bin_op(c, &@1, LSR_OP, &$1, &$3); + } else if ($1.signedness == SIGNED) { + $$ = gen_bin_op(c, &@1, ASR_OP, &$1, &$3); + } + } + | rvalue LSR rvalue + { + @1.last_column = @3.last_column; + $$ = gen_bin_op(c, &@1, LSR_OP, &$1, &$3); + } + | rvalue '&' rvalue + { + @1.last_column = @3.last_column; + $$ = gen_bin_op(c, &@1, ANDB_OP, &$1, &$3); + } + | rvalue '|' rvalue + { + @1.last_column = @3.last_column; + $$ = gen_bin_op(c, &@1, ORB_OP, &$1, &$3); + } + | rvalue '^' rvalue + { + @1.last_column = @3.last_column; + $$ = gen_bin_op(c, &@1, XORB_OP, &$1, &$3); + } + | rvalue ANDL rvalue + { + @1.last_column = @3.last_column; + $$ = gen_bin_op(c, &@1, ANDL_OP, &$1, &$3); + } + | MIN '(' rvalue ',' rvalue ')' + { + @1.last_column = @3.last_column; + $$ = gen_bin_op(c, &@1, MINI_OP, &$3, &$5); + } + | MAX '(' rvalue ',' rvalue ')' + { + @1.last_column = @3.last_column; + $$ = gen_bin_op(c, &@1, MAXI_OP, &$3, &$5); + } + | '~' rvalue + { + @1.last_column = @2.last_column; + $$ = gen_rvalue_not(c, &@1, &$2); + } + | '!' rvalue + { + @1.last_column = @2.last_column; + $$ = gen_rvalue_notl(c, &@1, &$2); + } + | SAT '(' IMM ',' rvalue ')' + { + @1.last_column = @6.last_column; + $$ = gen_rvalue_sat(c, &@1, &$1, &$3, &$5); + } + | CAST rvalue + { + @1.last_column = @2.last_column; + /* Assign target signedness */ + $2.signedness = $1.signedness; + $$ = gen_cast_op(c, &@1, &$2, $1.bit_width, $1.signedness); + } + | rvalue EQ rvalue + { + @1.last_column = @3.last_column; + $$ = gen_bin_cmp(c, &@1, TCG_COND_EQ, &$1, &$3); + } + | rvalue NEQ rvalue + { + @1.last_column = @3.last_column; + $$ = gen_bin_cmp(c, &@1, TCG_COND_NE, &$1, &$3); + } + | rvalue '<' rvalue + { + @1.last_column = @3.last_column; + + assert_signedness(c, &@1, $1.signedness); + assert_signedness(c, &@1, $3.signedness); + if ($1.signedness == UNSIGNED || $3.signedness == UNSIGNED) { + $$ = gen_bin_cmp(c, &@1, TCG_COND_LTU, &$1, &$3); + } else { + $$ = gen_bin_cmp(c, &@1, TCG_COND_LT, &$1, &$3); + } + } + | rvalue '>' rvalue + { + @1.last_column = @3.last_column; + + assert_signedness(c, &@1, $1.signedness); + assert_signedness(c, &@1, $3.signedness); + if ($1.signedness == UNSIGNED || $3.signedness == UNSIGNED) { + $$ = gen_bin_cmp(c, &@1, TCG_COND_GTU, &$1, &$3); + } else { + $$ = gen_bin_cmp(c, &@1, TCG_COND_GT, &$1, &$3); + } + } + | rvalue LTE rvalue + { + @1.last_column = @3.last_column; + + assert_signedness(c, &@1, $1.signedness); + assert_signedness(c, &@1, $3.signedness); + if ($1.signedness == UNSIGNED || $3.signedness == UNSIGNED) { + $$ = gen_bin_cmp(c, &@1, TCG_COND_LEU, &$1, &$3); + } else { + $$ = gen_bin_cmp(c, &@1, TCG_COND_LE, &$1, &$3); + } + } + | rvalue GTE rvalue + { + @1.last_column = @3.last_column; + + assert_signedness(c, &@1, $1.signedness); + assert_signedness(c, &@1, $3.signedness); + if ($1.signedness == UNSIGNED || $3.signedness == UNSIGNED) { + $$ = gen_bin_cmp(c, &@1, TCG_COND_GEU, &$1, &$3); + } else { + $$ = gen_bin_cmp(c, &@1, TCG_COND_GE, &$1, &$3); + } + } + | rvalue '?' + { + $1.is_manual = true; + Ternary t = { 0 }; + t.state = IN_LEFT; + t.cond = $1; + g_array_append_val(c->ternary, t); + } + rvalue ':' + { + Ternary *t = &g_array_index(c->ternary, Ternary, + c->ternary->len - 1); + t->state = IN_RIGHT; + } + rvalue + { + @1.last_column = @5.last_column; + $$ = gen_rvalue_ternary(c, &@1, &$1, &$4, &$7); + } + | FSCR '(' rvalue ')' + { + @1.last_column = @4.last_column; + $$ = gen_rvalue_fscr(c, &@1, &$3); + } + | SXT '(' rvalue ',' IMM ',' rvalue ')' + { + @1.last_column = @8.last_column; + yyassert(c, &@1, $5.type == IMMEDIATE && + $5.imm.type == VALUE, + "SXT expects immediate values\n"); + $$ = gen_extend_op(c, &@1, &$3, $5.imm.value, &$7, SIGNED); + } + | ZXT '(' rvalue ',' IMM ',' rvalue ')' + { + @1.last_column = @8.last_column; + yyassert(c, &@1, $5.type == IMMEDIATE && + $5.imm.type == VALUE, + "ZXT expects immediate values\n"); + $$ = gen_extend_op(c, &@1, &$3, $5.imm.value, &$7, UNSIGNED); + } + | '(' rvalue ')' + { + $$ = $2; + } + | ABS rvalue + { + @1.last_column = @2.last_column; + $$ = gen_rvalue_abs(c, &@1, &$2); + } + | CROUND '(' rvalue ',' rvalue ')' + { + @1.last_column = @6.last_column; + $$ = gen_convround_n(c, &@1, &$3, &$5); + } + | CROUND '(' rvalue ')' + { + @1.last_column = @4.last_column; + $$ = gen_convround(c, &@1, &$3); + } + | ROUND '(' rvalue ',' rvalue ')' + { + @1.last_column = @6.last_column; + $$ = gen_round(c, &@1, &$3, &$5); + } + | '-' rvalue + { + @1.last_column = @2.last_column; + $$ = gen_rvalue_neg(c, &@1, &$2); + } + | ICIRC '(' rvalue ')' ASL IMM + { + @1.last_column = @6.last_column; + $$ = gen_tmp(c, &@1, 32, UNSIGNED); + OUT(c, &@1, "gen_read_ireg(", &$$, ", ", &$3, ", ", &$6, ");\n"); + gen_rvalue_free(c, &@1, &$3); + } + | CIRCADD '(' rvalue ',' rvalue ',' rvalue ')' + { + @1.last_column = @8.last_column; + gen_circ_op(c, &@1, &$3, &$5, &$7); + } + | LOCNT '(' rvalue ')' + { + @1.last_column = @4.last_column; + /* Leading ones count */ + $$ = gen_locnt_op(c, &@1, &$3); + } + | COUNTONES '(' rvalue ')' + { + @1.last_column = @4.last_column; + /* Ones count */ + $$ = gen_ctpop_op(c, &@1, &$3); + } + | LPCFG + { + $$ = gen_tmp_value(c, &@1, "0", 32, UNSIGNED); + OUT(c, &@1, "GET_USR_FIELD(USR_LPCFG, ", &$$, ");\n"); + } + | EXTRACT '(' rvalue ',' rvalue ')' + { + @1.last_column = @6.last_column; + $$ = gen_extract_op(c, &@1, &$5, &$3, &$1); + } + | EXTRANGE '(' rvalue ',' rvalue ',' rvalue ')' + { + @1.last_column = @8.last_column; + yyassert(c, &@1, $5.type == IMMEDIATE && + $5.imm.type == VALUE && + $7.type == IMMEDIATE && + $7.imm.type == VALUE, + "Range extract needs immediate values!\n"); + $$ = gen_rextract_op(c, + &@1, + &$3, + $7.imm.value, + $5.imm.value - $7.imm.value + 1); + } + | CAST4_8U '(' rvalue ')' + { + @1.last_column = @4.last_column; + $$ = gen_rvalue_truncate(c, &@1, &$3); + $$.signedness = UNSIGNED; + $$ = rvalue_materialize(c, &@1, &$$); + $$ = gen_rvalue_extend(c, &@1, &$$); + } + | BREV '(' rvalue ')' + { + @1.last_column = @4.last_column; + $$ = gen_rvalue_brev(c, &@1, &$3); + } + | ROTL '(' rvalue ',' rvalue ')' + { + @1.last_column = @6.last_column; + $$ = gen_rotl(c, &@1, &$3, &$5); + } + | ADDSAT64 '(' rvalue ',' rvalue ',' rvalue ')' + { + @1.last_column = @8.last_column; + gen_addsat64(c, &@1, &$3, &$5, &$7); + } + | CARRY_FROM_ADD '(' rvalue ',' rvalue ',' rvalue ')' + { + @1.last_column = @8.last_column; + $$ = gen_carry_from_add(c, &@1, &$3, &$5, &$7); + } + | LSBNEW '(' rvalue ')' + { + @1.last_column = @4.last_column; + HexValue one = gen_imm_value(c, &@1, 1, 32, UNSIGNED); + $$ = gen_bin_op(c, &@1, ANDB_OP, &$3, &one); + } + ; + +lvalue : FAIL + { + @1.last_column = @1.last_column; + yyassert(c, &@1, false, "Encountered a FAIL token as lvalue.\n"); + } + | REG + { + $$ = $1; + } + | var + { + $$ = $1; + } + ; + +%% + +int main(int argc, char **argv) +{ + if (argc != 5) { + fprintf(stderr, + "Semantics: Hexagon ISA to tinycode generator compiler\n\n"); + fprintf(stderr, + "Usage: ./semantics IDEFS EMITTER_C EMITTER_H " + "ENABLED_INSTRUCTIONS_LIST\n"); + return 1; + } + + enum { + ARG_INDEX_ARGV0 = 0, + ARG_INDEX_IDEFS, + ARG_INDEX_EMITTER_C, + ARG_INDEX_EMITTER_H, + ARG_INDEX_ENABLED_INSTRUCTIONS_LIST + }; + + FILE *enabled_file = fopen(argv[ARG_INDEX_ENABLED_INSTRUCTIONS_LIST], "w"); + + FILE *output_file = fopen(argv[ARG_INDEX_EMITTER_C], "w"); + fputs("#include \"qemu/osdep.h\"\n", output_file); + fputs("#include \"qemu/log.h\"\n", output_file); + fputs("#include \"cpu.h\"\n", output_file); + fputs("#include \"internal.h\"\n", output_file); + fputs("#include \"tcg/tcg-op.h\"\n", output_file); + fputs("#include \"insn.h\"\n", output_file); + fputs("#include \"opcodes.h\"\n", output_file); + fputs("#include \"translate.h\"\n", output_file); + fputs("#define QEMU_GENERATE\n", output_file); + fputs("#include \"genptr.h\"\n", output_file); + fputs("#include \"tcg/tcg.h\"\n", output_file); + fputs("#include \"macros.h\"\n", output_file); + fprintf(output_file, "#include \"%s\"\n", argv[ARG_INDEX_EMITTER_H]); + + FILE *defines_file = fopen(argv[ARG_INDEX_EMITTER_H], "w"); + assert(defines_file != NULL); + fputs("#ifndef HEX_EMITTER_H\n", defines_file); + fputs("#define HEX_EMITTER_H\n", defines_file); + fputs("\n", defines_file); + fputs("#include \"insn.h\"\n\n", defines_file); + + /* Parser input file */ + Context context = { 0 }; + context.defines_file = defines_file; + context.output_file = output_file; + context.enabled_file = enabled_file; + /* Initialize buffers */ + context.out_str = g_string_new(NULL); + context.signature_str = g_string_new(NULL); + context.header_str = g_string_new(NULL); + context.ternary = g_array_new(FALSE, TRUE, sizeof(Ternary)); + /* Read input file */ + FILE *input_file = fopen(argv[ARG_INDEX_IDEFS], "r"); + fseek(input_file, 0L, SEEK_END); + long input_size = ftell(input_file); + context.input_buffer = (char *) calloc(input_size + 1, sizeof(char)); + fseek(input_file, 0L, SEEK_SET); + size_t read_chars = fread(context.input_buffer, + sizeof(char), + input_size, + input_file); + if (read_chars != (size_t) input_size) { + fprintf(stderr, "Error: an error occurred while reading input file!\n"); + return -1; + } + yylex_init(&context.scanner); + YY_BUFFER_STATE buffer; + buffer = yy_scan_string(context.input_buffer, context.scanner); + /* Start the parsing procedure */ + yyparse(context.scanner, &context); + if (context.implemented_insn != context.total_insn) { + fprintf(stderr, + "Warning: %d/%d meta instructions have been implemented!\n", + context.implemented_insn, + context.total_insn); + } + fputs("#endif " START_COMMENT " HEX_EMITTER_h " END_COMMENT "\n", + defines_file); + /* Cleanup */ + yy_delete_buffer(buffer, context.scanner); + yylex_destroy(context.scanner); + free(context.input_buffer); + g_string_free(context.out_str, TRUE); + g_string_free(context.signature_str, TRUE); + g_string_free(context.header_str, TRUE); + g_array_free(context.ternary, TRUE); + fclose(output_file); + fclose(input_file); + fclose(defines_file); + fclose(enabled_file); + + return 0; +} |