target/hexagon: import parser for idef-parser
Signed-off-by: Alessandro Di Federico <ale@rev.ng> Signed-off-by: Paolo Montesel <babush@rev.ng> Signed-off-by: Anton Johansson <anjo@rev.ng> Signed-off-by: Taylor Simpson <tsimpson@quicinc.com> Reviewed-by: Taylor Simpson <tsimpson@quicinc.com> Message-Id: <20220923173831.227551-10-anjo@rev.ng>
This commit is contained in:
parent
fd8171fe52
commit
c0a41ee631
|
@ -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;
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,376 @@
|
||||||
|
/*
|
||||||
|
* Copyright(c) 2019-2022 rev.ng Labs Srl. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PARSER_HELPERS_H
|
||||||
|
#define PARSER_HELPERS_H
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "tcg/tcg-cond.h"
|
||||||
|
|
||||||
|
#include "idef-parser.tab.h"
|
||||||
|
#include "idef-parser.yy.h"
|
||||||
|
#include "idef-parser.h"
|
||||||
|
|
||||||
|
/* Decomment this to disable yyasserts */
|
||||||
|
/* #define NDEBUG */
|
||||||
|
|
||||||
|
#define ERR_LINE_CONTEXT 40
|
||||||
|
|
||||||
|
#define START_COMMENT "/" "*"
|
||||||
|
#define END_COMMENT "*" "/"
|
||||||
|
|
||||||
|
void yyerror(YYLTYPE *locp,
|
||||||
|
yyscan_t scanner __attribute__((unused)),
|
||||||
|
Context *c,
|
||||||
|
const char *s);
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
#define yyassert(context, locp, condition, msg) \
|
||||||
|
if (!(condition)) { \
|
||||||
|
yyerror(locp, (context)->scanner, (context), (msg)); \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool is_direct_predicate(HexValue *value);
|
||||||
|
|
||||||
|
bool is_inside_ternary(Context *c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
void str_print(Context *c, YYLTYPE *locp, const char *string);
|
||||||
|
|
||||||
|
void uint8_print(Context *c, YYLTYPE *locp, uint8_t *num);
|
||||||
|
|
||||||
|
void uint64_print(Context *c, YYLTYPE *locp, uint64_t *num);
|
||||||
|
|
||||||
|
void int_print(Context *c, YYLTYPE *locp, int *num);
|
||||||
|
|
||||||
|
void uint_print(Context *c, YYLTYPE *locp, unsigned *num);
|
||||||
|
|
||||||
|
void tmp_print(Context *c, YYLTYPE *locp, HexTmp *tmp);
|
||||||
|
|
||||||
|
void pred_print(Context *c, YYLTYPE *locp, HexPred *pred, bool is_dotnew);
|
||||||
|
|
||||||
|
void reg_compose(Context *c, YYLTYPE *locp, HexReg *reg, char reg_id[5]);
|
||||||
|
|
||||||
|
void reg_print(Context *c, YYLTYPE *locp, HexReg *reg);
|
||||||
|
|
||||||
|
void imm_print(Context *c, YYLTYPE *locp, HexImm *imm);
|
||||||
|
|
||||||
|
void var_print(Context *c, YYLTYPE *locp, HexVar *var);
|
||||||
|
|
||||||
|
void rvalue_print(Context *c, YYLTYPE *locp, void *pointer);
|
||||||
|
|
||||||
|
void out_assert(Context *c, YYLTYPE *locp, void *dummy);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies output code buffer into stdout
|
||||||
|
*/
|
||||||
|
void commit(Context *c);
|
||||||
|
|
||||||
|
#define OUT_IMPL(c, locp, x) \
|
||||||
|
_Generic(*(x), \
|
||||||
|
char: str_print, \
|
||||||
|
uint8_t: uint8_print, \
|
||||||
|
uint64_t: uint64_print, \
|
||||||
|
int: int_print, \
|
||||||
|
unsigned: uint_print, \
|
||||||
|
HexValue: rvalue_print, \
|
||||||
|
default: out_assert \
|
||||||
|
)(c, locp, x);
|
||||||
|
|
||||||
|
/* FOREACH macro */
|
||||||
|
#define FE_1(c, locp, WHAT, X) WHAT(c, locp, X)
|
||||||
|
#define FE_2(c, locp, WHAT, X, ...) \
|
||||||
|
WHAT(c, locp, X)FE_1(c, locp, WHAT, __VA_ARGS__)
|
||||||
|
#define FE_3(c, locp, WHAT, X, ...) \
|
||||||
|
WHAT(c, locp, X)FE_2(c, locp, WHAT, __VA_ARGS__)
|
||||||
|
#define FE_4(c, locp, WHAT, X, ...) \
|
||||||
|
WHAT(c, locp, X)FE_3(c, locp, WHAT, __VA_ARGS__)
|
||||||
|
#define FE_5(c, locp, WHAT, X, ...) \
|
||||||
|
WHAT(c, locp, X)FE_4(c, locp, WHAT, __VA_ARGS__)
|
||||||
|
#define FE_6(c, locp, WHAT, X, ...) \
|
||||||
|
WHAT(c, locp, X)FE_5(c, locp, WHAT, __VA_ARGS__)
|
||||||
|
#define FE_7(c, locp, WHAT, X, ...) \
|
||||||
|
WHAT(c, locp, X)FE_6(c, locp, WHAT, __VA_ARGS__)
|
||||||
|
#define FE_8(c, locp, WHAT, X, ...) \
|
||||||
|
WHAT(c, locp, X)FE_7(c, locp, WHAT, __VA_ARGS__)
|
||||||
|
#define FE_9(c, locp, WHAT, X, ...) \
|
||||||
|
WHAT(c, locp, X)FE_8(c, locp, WHAT, __VA_ARGS__)
|
||||||
|
/* repeat as needed */
|
||||||
|
|
||||||
|
#define GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, NAME, ...) NAME
|
||||||
|
|
||||||
|
#define FOR_EACH(c, locp, action, ...) \
|
||||||
|
do { \
|
||||||
|
GET_MACRO(__VA_ARGS__, \
|
||||||
|
FE_9, \
|
||||||
|
FE_8, \
|
||||||
|
FE_7, \
|
||||||
|
FE_6, \
|
||||||
|
FE_5, \
|
||||||
|
FE_4, \
|
||||||
|
FE_3, \
|
||||||
|
FE_2, \
|
||||||
|
FE_1)(c, locp, action, \
|
||||||
|
__VA_ARGS__) \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define OUT(c, locp, ...) FOR_EACH((c), (locp), OUT_IMPL, __VA_ARGS__)
|
||||||
|
|
||||||
|
const char *cmp_swap(Context *c, YYLTYPE *locp, const char *type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Temporary values creation
|
||||||
|
*/
|
||||||
|
|
||||||
|
HexValue gen_tmp(Context *c,
|
||||||
|
YYLTYPE *locp,
|
||||||
|
unsigned bit_width,
|
||||||
|
HexSignedness signedness);
|
||||||
|
|
||||||
|
HexValue gen_tmp_value(Context *c,
|
||||||
|
YYLTYPE *locp,
|
||||||
|
const char *value,
|
||||||
|
unsigned bit_width,
|
||||||
|
HexSignedness signedness);
|
||||||
|
|
||||||
|
HexValue gen_imm_value(Context *c __attribute__((unused)),
|
||||||
|
YYLTYPE *locp,
|
||||||
|
int value,
|
||||||
|
unsigned bit_width,
|
||||||
|
HexSignedness signedness);
|
||||||
|
|
||||||
|
HexValue gen_imm_qemu_tmp(Context *c, YYLTYPE *locp, unsigned bit_width,
|
||||||
|
HexSignedness signedness);
|
||||||
|
|
||||||
|
void gen_rvalue_free(Context *c, YYLTYPE *locp, HexValue *rvalue);
|
||||||
|
|
||||||
|
HexValue rvalue_materialize(Context *c, YYLTYPE *locp, HexValue *rvalue);
|
||||||
|
|
||||||
|
HexValue gen_rvalue_extend(Context *c, YYLTYPE *locp, HexValue *rvalue);
|
||||||
|
|
||||||
|
HexValue gen_rvalue_truncate(Context *c, YYLTYPE *locp, HexValue *rvalue);
|
||||||
|
|
||||||
|
void gen_varid_allocate(Context *c,
|
||||||
|
YYLTYPE *locp,
|
||||||
|
HexValue *varid,
|
||||||
|
unsigned bit_width,
|
||||||
|
HexSignedness signedness);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Code generation functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
HexValue gen_bin_cmp(Context *c,
|
||||||
|
YYLTYPE *locp,
|
||||||
|
TCGCond type,
|
||||||
|
HexValue *op1,
|
||||||
|
HexValue *op2);
|
||||||
|
|
||||||
|
HexValue gen_bin_op(Context *c,
|
||||||
|
YYLTYPE *locp,
|
||||||
|
OpType type,
|
||||||
|
HexValue *op1,
|
||||||
|
HexValue *op2);
|
||||||
|
|
||||||
|
HexValue gen_cast_op(Context *c,
|
||||||
|
YYLTYPE *locp,
|
||||||
|
HexValue *src,
|
||||||
|
unsigned target_width,
|
||||||
|
HexSignedness signedness);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gen_extend_op extends a region of src_width_ptr bits stored in a
|
||||||
|
* value_ptr to the size of dst_width. Note: src_width_ptr is a
|
||||||
|
* HexValue * to handle the special case where it is unknown at
|
||||||
|
* translation time.
|
||||||
|
*/
|
||||||
|
HexValue gen_extend_op(Context *c,
|
||||||
|
YYLTYPE *locp,
|
||||||
|
HexValue *src_width,
|
||||||
|
unsigned dst_width,
|
||||||
|
HexValue *value,
|
||||||
|
HexSignedness signedness);
|
||||||
|
|
||||||
|
void gen_rdeposit_op(Context *c,
|
||||||
|
YYLTYPE *locp,
|
||||||
|
HexValue *dst,
|
||||||
|
HexValue *value,
|
||||||
|
HexValue *begin,
|
||||||
|
HexValue *width);
|
||||||
|
|
||||||
|
void gen_deposit_op(Context *c,
|
||||||
|
YYLTYPE *locp,
|
||||||
|
HexValue *dst,
|
||||||
|
HexValue *value,
|
||||||
|
HexValue *index,
|
||||||
|
HexCast *cast);
|
||||||
|
|
||||||
|
HexValue gen_rextract_op(Context *c,
|
||||||
|
YYLTYPE *locp,
|
||||||
|
HexValue *src,
|
||||||
|
unsigned begin,
|
||||||
|
unsigned width);
|
||||||
|
|
||||||
|
HexValue gen_extract_op(Context *c,
|
||||||
|
YYLTYPE *locp,
|
||||||
|
HexValue *src,
|
||||||
|
HexValue *index,
|
||||||
|
HexExtract *extract);
|
||||||
|
|
||||||
|
HexValue gen_read_reg(Context *c, YYLTYPE *locp, HexValue *reg);
|
||||||
|
|
||||||
|
void gen_write_reg(Context *c, YYLTYPE *locp, HexValue *reg, HexValue *value);
|
||||||
|
|
||||||
|
void gen_assign(Context *c,
|
||||||
|
YYLTYPE *locp,
|
||||||
|
HexValue *dst,
|
||||||
|
HexValue *value);
|
||||||
|
|
||||||
|
HexValue gen_convround(Context *c,
|
||||||
|
YYLTYPE *locp,
|
||||||
|
HexValue *src);
|
||||||
|
|
||||||
|
HexValue gen_round(Context *c,
|
||||||
|
YYLTYPE *locp,
|
||||||
|
HexValue *src,
|
||||||
|
HexValue *position);
|
||||||
|
|
||||||
|
HexValue gen_convround_n(Context *c,
|
||||||
|
YYLTYPE *locp,
|
||||||
|
HexValue *src,
|
||||||
|
HexValue *pos);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Circular addressing mode with auto-increment
|
||||||
|
*/
|
||||||
|
void gen_circ_op(Context *c,
|
||||||
|
YYLTYPE *locp,
|
||||||
|
HexValue *addr,
|
||||||
|
HexValue *increment,
|
||||||
|
HexValue *modifier);
|
||||||
|
|
||||||
|
HexValue gen_locnt_op(Context *c, YYLTYPE *locp, HexValue *src);
|
||||||
|
|
||||||
|
HexValue gen_ctpop_op(Context *c, YYLTYPE *locp, HexValue *src);
|
||||||
|
|
||||||
|
HexValue gen_rotl(Context *c, YYLTYPE *locp, HexValue *src, HexValue *n);
|
||||||
|
|
||||||
|
HexValue gen_deinterleave(Context *c, YYLTYPE *locp, HexValue *mixed);
|
||||||
|
|
||||||
|
HexValue gen_interleave(Context *c,
|
||||||
|
YYLTYPE *locp,
|
||||||
|
HexValue *odd,
|
||||||
|
HexValue *even);
|
||||||
|
|
||||||
|
HexValue gen_carry_from_add(Context *c,
|
||||||
|
YYLTYPE *locp,
|
||||||
|
HexValue *op1,
|
||||||
|
HexValue *op2,
|
||||||
|
HexValue *op3);
|
||||||
|
|
||||||
|
void gen_addsat64(Context *c,
|
||||||
|
YYLTYPE *locp,
|
||||||
|
HexValue *dst,
|
||||||
|
HexValue *op1,
|
||||||
|
HexValue *op2);
|
||||||
|
|
||||||
|
void gen_inst(Context *c, GString *iname);
|
||||||
|
|
||||||
|
void gen_inst_init_args(Context *c, YYLTYPE *locp);
|
||||||
|
|
||||||
|
void gen_inst_code(Context *c, YYLTYPE *locp);
|
||||||
|
|
||||||
|
void gen_pred_assign(Context *c, YYLTYPE *locp, HexValue *left_pred,
|
||||||
|
HexValue *right_pred);
|
||||||
|
|
||||||
|
void gen_cancel(Context *c, YYLTYPE *locp);
|
||||||
|
|
||||||
|
void gen_load_cancel(Context *c, YYLTYPE *locp);
|
||||||
|
|
||||||
|
void gen_load(Context *c, YYLTYPE *locp, HexValue *size,
|
||||||
|
HexSignedness signedness, HexValue *ea, HexValue *dst);
|
||||||
|
|
||||||
|
void gen_store(Context *c, YYLTYPE *locp, HexValue *size, HexValue *ea,
|
||||||
|
HexValue *src);
|
||||||
|
|
||||||
|
void gen_sethalf(Context *c, YYLTYPE *locp, HexCast *sh, HexValue *n,
|
||||||
|
HexValue *dst, HexValue *value);
|
||||||
|
|
||||||
|
void gen_setbits(Context *c, YYLTYPE *locp, HexValue *hi, HexValue *lo,
|
||||||
|
HexValue *dst, HexValue *value);
|
||||||
|
|
||||||
|
unsigned gen_if_cond(Context *c, YYLTYPE *locp, HexValue *cond);
|
||||||
|
|
||||||
|
unsigned gen_if_else(Context *c, YYLTYPE *locp, unsigned index);
|
||||||
|
|
||||||
|
HexValue gen_rvalue_pred(Context *c, YYLTYPE *locp, HexValue *pred);
|
||||||
|
|
||||||
|
HexValue gen_rvalue_var(Context *c, YYLTYPE *locp, HexValue *var);
|
||||||
|
|
||||||
|
HexValue gen_rvalue_mpy(Context *c, YYLTYPE *locp, HexMpy *mpy, HexValue *op1,
|
||||||
|
HexValue *op2);
|
||||||
|
|
||||||
|
HexValue gen_rvalue_not(Context *c, YYLTYPE *locp, HexValue *value);
|
||||||
|
|
||||||
|
HexValue gen_rvalue_notl(Context *c, YYLTYPE *locp, HexValue *value);
|
||||||
|
|
||||||
|
HexValue gen_rvalue_sat(Context *c, YYLTYPE *locp, HexSat *sat, HexValue *n,
|
||||||
|
HexValue *value);
|
||||||
|
|
||||||
|
HexValue gen_rvalue_fscr(Context *c, YYLTYPE *locp, HexValue *value);
|
||||||
|
|
||||||
|
HexValue gen_rvalue_abs(Context *c, YYLTYPE *locp, HexValue *value);
|
||||||
|
|
||||||
|
HexValue gen_rvalue_neg(Context *c, YYLTYPE *locp, HexValue *value);
|
||||||
|
|
||||||
|
HexValue gen_rvalue_brev(Context *c, YYLTYPE *locp, HexValue *value);
|
||||||
|
|
||||||
|
HexValue gen_rvalue_ternary(Context *c, YYLTYPE *locp, HexValue *cond,
|
||||||
|
HexValue *true_branch, HexValue *false_branch);
|
||||||
|
|
||||||
|
const char *cond_to_str(TCGCond cond);
|
||||||
|
|
||||||
|
void emit_header(Context *c);
|
||||||
|
|
||||||
|
void emit_arg(Context *c, YYLTYPE *locp, HexValue *arg);
|
||||||
|
|
||||||
|
void emit_footer(Context *c);
|
||||||
|
|
||||||
|
void track_string(Context *c, GString *s);
|
||||||
|
|
||||||
|
void free_variables(Context *c, YYLTYPE *locp);
|
||||||
|
|
||||||
|
void free_instruction(Context *c);
|
||||||
|
|
||||||
|
void assert_signedness(Context *c,
|
||||||
|
YYLTYPE *locp,
|
||||||
|
HexSignedness signedness);
|
||||||
|
|
||||||
|
#endif /* PARSER_HELPERS_h */
|
|
@ -203,6 +203,35 @@ if idef_parser_enabled and 'hexagon-linux-user' in target_dirs
|
||||||
output: ['@BASENAME@.yy.c', '@BASENAME@.yy.h'],
|
output: ['@BASENAME@.yy.c', '@BASENAME@.yy.h'],
|
||||||
arguments: ['-o', '@OUTPUT0@', '--header-file=@OUTPUT1@', '@INPUT@']
|
arguments: ['-o', '@OUTPUT0@', '--header-file=@OUTPUT1@', '@INPUT@']
|
||||||
)
|
)
|
||||||
|
|
||||||
|
bison = generator(
|
||||||
|
find_program('bison'),
|
||||||
|
output: ['@BASENAME@.tab.c', '@BASENAME@.tab.h'],
|
||||||
|
arguments: ['@INPUT@', '--defines=@OUTPUT1@', '--output=@OUTPUT0@']
|
||||||
|
)
|
||||||
|
|
||||||
|
glib_dep = dependency('glib-2.0', native: true)
|
||||||
|
|
||||||
|
idef_parser = executable(
|
||||||
|
'idef-parser',
|
||||||
|
[flex.process(idef_parser_dir / 'idef-parser.lex'),
|
||||||
|
bison.process(idef_parser_dir / 'idef-parser.y'),
|
||||||
|
idef_parser_dir / 'parser-helpers.c'],
|
||||||
|
include_directories: ['idef-parser', '../../include/'],
|
||||||
|
dependencies: [glib_dep],
|
||||||
|
c_args: ['-Wextra'],
|
||||||
|
native: true
|
||||||
|
)
|
||||||
|
|
||||||
|
idef_generated_tcg = custom_target(
|
||||||
|
'idef-generated-tcg',
|
||||||
|
output: ['idef-generated-emitter.c',
|
||||||
|
'idef-generated-emitter.h.inc',
|
||||||
|
'idef-generated-enabled-instructions'],
|
||||||
|
input: preprocessed_idef_parser_input_generated,
|
||||||
|
depend_files: [hex_common_py],
|
||||||
|
command: [idef_parser, '@INPUT@', '@OUTPUT0@', '@OUTPUT1@', '@OUTPUT2@']
|
||||||
|
)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
target_arch += {'hexagon': hexagon_ss}
|
target_arch += {'hexagon': hexagon_ss}
|
||||||
|
|
Loading…
Reference in New Issue