aboutsummaryrefslogtreecommitdiff
path: root/target/hexagon/idef-parser/idef-parser.y
diff options
context:
space:
mode:
Diffstat (limited to 'target/hexagon/idef-parser/idef-parser.y')
-rw-r--r--target/hexagon/idef-parser/idef-parser.y965
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;
+}