diff mbox series

[v2,08/10] target/hexagon: import parser for idef-parser

Message ID 20210225151856.3284701-9-ale.qemu@rev.ng (mailing list archive)
State New, archived
Headers show
Series target/hexagon: introduce idef-parser | expand

Commit Message

Alessandro Di Federico Feb. 25, 2021, 3:18 p.m. UTC
From: Paolo Montesel <babush@rev.ng>

Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Paolo Montesel <babush@rev.ng>
---
 target/hexagon/idef-parser/idef-parser.y      | 1250 +++++++++++
 target/hexagon/idef-parser/parser-helpers.c   | 1925 +++++++++++++++++
 target/hexagon/idef-parser/parser-helpers.h   |  293 +++
 target/hexagon/meson.build                    |   23 +-
 tests/docker/dockerfiles/alpine.docker        |    1 +
 tests/docker/dockerfiles/centos7.docker       |    1 +
 tests/docker/dockerfiles/centos8.docker       |    1 +
 tests/docker/dockerfiles/debian10.docker      |    1 +
 .../dockerfiles/fedora-i386-cross.docker      |    1 +
 .../dockerfiles/fedora-win32-cross.docker     |    1 +
 .../dockerfiles/fedora-win64-cross.docker     |    1 +
 tests/docker/dockerfiles/fedora.docker        |    1 +
 tests/docker/dockerfiles/opensuse-leap.docker |    1 +
 tests/docker/dockerfiles/ubuntu.docker        |    1 +
 tests/docker/dockerfiles/ubuntu1804.docker    |    1 +
 tests/docker/dockerfiles/ubuntu2004.docker    |    3 +-
 16 files changed, 3503 insertions(+), 2 deletions(-)
 create mode 100644 target/hexagon/idef-parser/idef-parser.y
 create mode 100644 target/hexagon/idef-parser/parser-helpers.c
 create mode 100644 target/hexagon/idef-parser/parser-helpers.h

Comments

Richard Henderson Feb. 26, 2021, 3:30 a.m. UTC | #1
On 2/25/21 7:18 AM, Alessandro Di Federico wrote:
> +instructions : instruction instructions
> +| %empty
> +;

I have never seen bison written flush-left like this, and I find it really hard
to read, especially with some of the larger non-terminals.

I'm also not a fan of large blocks of code within non-terminals.  IMO they
should pretty much be limited to calling a function, the result of which is
assigned to $$ as needed.

> +instruction : INAME
> +{
> +    /* Early-free if the parser failed on the previous instruction */
> +    free_instruction(c);

Surely this belongs in the error alternative.

> +    for (int i = 0; i < c->inst.init_count; i++) {
> +        bool is64 = c->inst.init_list[i].bit_width == 64;
> +        const char *type = is64 ? "i64" : "i32";

Why would you not use "i%d" in the printf format.

> +        if (c->inst.init_list[i].type == REGISTER) {
> +            OUT(c, &@1, "tcg_gen_movi_", type,
> +                "(", &(c->inst.init_list[i]), ", 0);\n");
> +        } else if (c->inst.init_list[i].type == PREDICATE) {
> +            OUT(c, &@1, "tcg_gen_movi_", type,
> +                "(", &(c->inst.init_list[i]), ", 0);\n");
> +        }

These are identical.

> +    }
> +}
> +code
> +{
> +    if (c->inst.error_count != 0) {
> +        fprintf(stderr,
> +                "Parsing of instruction %s generated %d errors!\n",
> +                c->inst.name,
> +                c->inst.error_count);
> +        EMIT(c, "assert(false && \"This instruction is not implemented!\");");

What's the point of assert(false) above abort()?

Is there any point in emitting anything at all, since I assume the idef-parser
program itself will exit with error, stopping the build process?

> +arguments : LPAR RPAR

Is there any reason you're not spelling these '(' and ')'?
The same goes for every other single-character token.

> +decl : REG
> +{
> +    emit_arg(c, &@1, &$1);
> +    /* Enqueue register into initialization list */
> +    yyassert(c, &@1, c->inst.init_count < INIT_LIST_LEN,
> +             "init_count overflow");

Use a data structure that grows.  There are plenty to choose from.

> +| pre ASSIGN rvalue
> +{
> +    @1.last_column = @3.last_column;

Do you really find any value in this column manipulation, given that the input
is not the original file, but the output of cpp?

IMO this is another reason to *not* preprocess with macros.inc, nor sed the
output as a workaround for your parsing troubles.

> +| SETBITS LPAR rvalue COMMA rvalue COMMA rvalue COMMA rvalue RPAR
> +{
> +    @1.last_column = @10.last_column;
> +    yyassert(c, &@1, $3.type == IMMEDIATE &&
> +             $3.imm.type == VALUE &&
> +             $5.type == IMMEDIATE &&
> +             $5.imm.type == VALUE,
> +             "Range deposit needs immediate values!\n");
> +    int i;
> +    $9 = rvalue_truncate(c, &@1, &$9);
> +    for (i = $5.imm.value; i <= $3.imm.value; ++i) {
> +        OUT(c, &@1, "gen_set_bit(", &i, ", ", &$7, ", ", &$9, ");\n");

A loop, really?  Surely this is just

  deposit($7, $7, -$9, $5, $3 - $5 + 1)

> +control_statement : frame_check          { /* does nothing */ }
> +| cancel_statement     { /* does nothing */ }
> +| if_statement         { /* does nothing */ }
> +| for_statement        { /* does nothing */ }
> +| fpart1_statement     { /* does nothing */ }
> +;

You can drop all the empty code blocks.

> +frame_check : FCHK LPAR rvalue COMMA rvalue RPAR SEMI  {

Do not start code blocks on the previous line like this.
What goes for our C coding style does not apply to yacc grammar.  ;-)

> +for_statement : FOR LPAR IMM ASSIGN IMM SEMI IMM LT IMM SEMI IMM PLUSPLUS RPAR
> +{
> +    @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");
> +}
> +;
> +
> +for_statement : FOR LPAR IMM ASSIGN IMM SEMI IMM LT IMM SEMI IMM INC IMM RPAR

Why separate these productions, and not use |?

> +if_stmt : IF
> +{
> +    /* Generate an end label, if false branch to that label */
> +    OUT(c, &@1, "TCGLabel *if_label_", &c->inst.if_count,
> +        " = gen_new_label();\n");
> +}

Do you actually use the label before...

> +LPAR rvalue RPAR
> +{
> +    @1.last_column = @3.last_column;
> +    $4 = rvalue_materialize(c, &@1, &$4);
> +    const char *bit_suffix = ($4.bit_width == 64) ? "i64" : "i32";
> +    OUT(c, &@1, "tcg_gen_brcondi_", bit_suffix, "(TCG_COND_EQ, ", &$4,
> +        ", 0, if_label_", &c->inst.if_count, ");\n");

... here?  I don't see why you need to create it early.


> +rvalue : FAIL
> +{
> +    @1.last_column = @1.last_column;

Useless assignment.

> +| PC
> +{
> +    /* Read PC from the CR */
> +    $$ = gen_tmp(c, &@1, 32);
> +    OUT(c, &@1, "tcg_gen_mov_i32(", &$$, ", hex_gpr[HEX_REG_PC]);\n");
> +}
> +| NPC
> +{
> +    /* NPC is only read from CALLs, so we can hardcode it at translation time */
> +    $$ = gen_tmp(c, &@1, 32);
> +    OUT(c, &@1, "tcg_gen_movi_i32(", &$$, ", ctx->npc);\n");
> +}

If you can hardcode NPC, you can also hardcode PC.
Which makes total sense the way tcg translation works.

> +| MAX LPAR rvalue COMMA rvalue RPAR
> +{
> +    @1.last_column = @3.last_column;
> +    $$ = gen_bin_op(c, &@1, MAXI_OP, &$3, &$5);
> +}
> +| NOT rvalue
> +{
> +    @1.last_column = @2.last_column;

Why no gen_unary_op()?

> +| rvalue LSQ rvalue RSQ
> +{
> +    @1.last_column = @4.last_column;
> +    HexValue one = gen_imm_value(c, &@1, 1, $3.bit_width);
> +    HexValue tmp = gen_bin_op(c, &@1, ASR_OP, &$1, &$3);
> +    $$ = gen_bin_op(c, &@1, ANDB_OP, &tmp, &one);

Should be an extract operation, at least when $3 is immediate.

> +| rvalue QMARK rvalue COLON rvalue
> +{
> +    @1.last_column = @5.last_column;
> +    bool is_64bit = ($3.bit_width == 64) || ($5.bit_width == 64);
> +    int bit_width = (is_64bit) ? 64 : 32;
> +    if (is_64bit) {
> +        $1 = rvalue_extend(c, &@1, &$1);
> +        $3 = rvalue_extend(c, &@1, &$3);
> +        $5 = rvalue_extend(c, &@1, &$5);
> +    } else {
> +        $1 = rvalue_truncate(c, &@1, &$1);
> +    }
> +    $1 = rvalue_materialize(c, &@1, &$1);
> +    $3 = rvalue_materialize(c, &@1, &$3);
> +    $5 = rvalue_materialize(c, &@1, &$5);
> +    HexValue res = gen_local_tmp(c, &@1, bit_width);
> +    HexValue zero = gen_tmp_value(c, &@1, "0", bit_width);
> +    OUT(c, &@1, "tcg_gen_movcond_i", &bit_width);
> +    OUT(c, &@1, "(TCG_COND_NE, ", &res, ", ", &$1, ", ", &zero);

It would be better if you parsed conditions differently.
Retain the two arguments and the condition, so that you can fold that into the
movcond directly.

E.g. instead of

    tcg_gen_setcond_i32(cond, t, x, y)
    tcg_gen_movcond_i32(TCG_COND_NE, dest, t, zero, src1, src2);

you'd be able to do

    tcg_gen_movcond_i32(cond, dest, x, y, src1, src2);

This would be trivial with a non-terminal "cond", used here and with IF.  You'd
include cond as an alternative of rvalue, which would perform the reduction to
boolean with setcond.

> +| ABS rvalue
> +{
> +    @1.last_column = @2.last_column;
> +    const char *bit_suffix = ($2.bit_width == 64) ? "i64" : "i32";
> +    int bit_width = ($2.bit_width == 64) ? 64 : 32;
> +    HexValue res;
> +    res.is_unsigned = $2.is_unsigned;
> +    res.is_dotnew = false;
> +    res.is_manual = false;
> +    if ($2.type == IMMEDIATE) {
> +        res.type = IMMEDIATE;
> +        res.imm.type = QEMU_TMP;
> +        res.imm.index = c->inst.qemu_tmp_count;
> +        OUT(c, &@1, "int", &bit_width, "_t ", &res, " = abs(", &$2, ");\n");
> +        c->inst.qemu_tmp_count++;
> +        $$ = res;
> +    } else {
> +        res = gen_tmp(c, &@1, bit_width);
> +        HexValue zero = gen_tmp_value(c, &@1, "0", bit_width);
> +        OUT(c, &@1, "tcg_gen_neg_", bit_suffix, "(", &res, ", ",
> +            &$2, ");\n");
> +        OUT(c, &@1, "tcg_gen_movcond_i", &bit_width);
> +        OUT(c, &@1, "(TCG_COND_GT, ", &res, ", ", &$2, ", ", &zero);

tcg_gen_abs, surely via gen_unary_op.

> +pre : PRE
> +{
> +    $$ = $1;
> +}
> +| pre NEW

Surely PRE NEW.  You don't want PRE NEW NEW NEW to be a valid parse.

Also, I don't see NEW being generated from the lexer?  I do see
"P"{lower_pre}"N", so I suppose this production is entirely left-over, and pre
can be dropped in favor of PRE globally.

> +void tmp_print(Context *c, YYLTYPE *locp, HexTmp *tmp)
> +{
> +    EMIT(c, "tmp_");
> +    EMIT(c, "%d", tmp->index);

Merge to a single printf.

> +    case VALUE:
> +        EMIT(c, "((int64_t)%" PRIu64 "ULL)", (int64_t)imm->value);

Why are you using ull then casting to signed?  Just use ll.

> +const char *cmp_swap(Context *c, YYLTYPE *locp, const char *type)
> +{
> +    if (type == COND_EQ) {
> +        return COND_EQ;
> +    } else if (type == COND_NE) {
> +        return COND_NE;
> +    } else if (type == COND_GT) {
> +        return COND_LT;
> +    } else if (type == COND_LT) {
> +        return COND_GT;
> +    } else if (type == COND_GE) {
> +        return COND_LE;
> +    } else if (type == COND_LE) {
> +        return COND_GE;
> +    } else if (type == COND_GTU) {
> +        return COND_LTU;
> +    } else if (type == COND_LTU) {
> +        return COND_GTU;
> +    } else if (type == COND_GEU) {
> +        return COND_LEU;
> +    } else if (type == COND_LEU) {
> +        return COND_GEU;
> +    } else {
> +        yyassert(c, locp, false, "Unhandled comparison swap!");
> +        return NULL;
> +    }

Eww.  It looks like it might be worthwhile pulling out TCGCond from tcg/tcg.h
into its own file, so that you can use tcg_swap_cond(), is_unsigned_cond(), etc.

> +/* Temporary values creation */
> +static inline HexValue gen_tmp_impl(Context *c,

Drop all inline markup and let the compiler decide.

> +    switch (op_types) {
> +    case IMM_IMM:
> +    {
> +        OUT(c, locp, "tcg_gen_movi_", bit_suffix,
> +            "(", &res, ", ", &op1, " == ", &op2, ");\n");
> +        break;
> +    }

Drop useless braces like this.

Do you really see any IMM_IMM operations?  There are some typos in this
section, so certainly all operators are not represented.  It might be worth
folding all of these inside the parser, and not deferring to the C compiler, so
that you can be certain of having a real value for any IMMEDIATE.  Which will
help when it comes to shift below.

I'm thinking that this code could really benefit from tcg_constant_{i32,i64}.
It produces a hashed temp that need not be freed, and it's what many of the
tcg_gen_fooi functions use in the backend.

Then you don't need any of the complication of

> +    case IMM_REG:
> +    {
> +        HexValue swp = op2;
> +        op2 = op1;
> +        op1 = swp;
> +        /* Swap comparison direction */
> +        type = cmp_swap(c, locp, type);
> +    }
> +    /* fallthrough */
> +    case REG_IMM:
> +    {
> +        OUT(c, locp, "tcg_gen_setcondi_", bit_suffix, "(");
> +        OUT(c, locp, type, ", ", &res, ", ", &op1, ", ", &op2, ");\n");
> +        break;
> +    }

this, you'd only have

> +    case REG_REG:
> +    {
> +        OUT(c, locp, "tcg_gen_setcond_", bit_suffix, "(");
> +        OUT(c, locp, type, ", ", &res, ", ", &op1, ", ", &op2, ");\n");
> +        break;
> +    }

this.

> +static void gen_add_op(Context *c, YYLTYPE *locp, unsigned bit_width,
> +                       const char *bit_suffix, HexValue *res,
> +                       enum OpTypes op_types, HexValue *op1, HexValue *op2)

You really need a helper to avoid replication of code...

> +static void gen_sub_op(Context *c, YYLTYPE *locp, unsigned bit_width,
> +                       const char *bit_suffix, HexValue *res,
> +                       enum OpTypes op_types, HexValue *op1, HexValue *op2)
...
> +static void gen_mul_op(Context *c, YYLTYPE *locp,
> +                       const char *bit_suffix, HexValue *res,
> +                       enum OpTypes op_types, HexValue *op1, HexValue *op2)

here, and so forth.

> +static void gen_div_op(Context *c, YYLTYPE *locp, HexValue *res,
> +                       enum OpTypes op_types, HexValue *op1, HexValue *op2)
> +{
> +    switch (op_types) {
> +    case IMM_IMM:
> +        OUT(c, locp, "int64_t ", res, " = ", op1, " / ", op2, ";\n");
> +        break;
> +    case IMM_REG:
> +    case REG_IMM:
> +    case REG_REG:
> +        OUT(c, locp, res, " = gen_helper_divu("
> +            "cpu_env, ", op1, ", ", op2, ");\n");

Are we trusting that div-by-zero has already been tested for?

> +    switch (op_types) {
> +    case IMM_IMM:
> +        OUT(c, locp, "int", &bit_width, "_t ", res,
> +            " = ", &op1, " << ", &op2, ";\n");
> +        break;
> +    case REG_IMM:
> +        {
> +            /* Need to work around assert(op2 < 64) in tcg_gen_shli */
> +            if (op_is64bit) {
> +                op2 = rvalue_extend(c, locp, &op2);
> +            }
> +            op2 = rvalue_materialize(c, locp, &op2);
> +            const char *mask = op_is64bit ? "0xffffffffffffffc0"
> +                                          : "0xffffffc0";
> +            HexValue zero = gen_tmp_value(c, locp, "0", bit_width);
> +            HexValue tmp = gen_tmp(c, locp, bit_width);
> +            OUT(c, locp, "tcg_gen_andi_", bit_suffix,
> +                "(", &tmp, ", ", &op2, ", ", mask, ");\n");
> +            OUT(c, locp, "tcg_gen_movcond_i", &bit_width);
> +            OUT(c, locp, "(TCG_COND_EQ, ", &tmp, ", ", &tmp, ", ", &zero);
> +            OUT(c, locp, ", ", &op2, ", ", &zero, ");\n");
> +            OUT(c, locp, "tcg_gen_shl_", bit_suffix,
> +                "(", res, ", ", &op1, ", ", &tmp, ");\n");

Er... this is

    tmp = op2 & -64;
    tmp = tmp == 0 ? op2 : 0;
    res = op1 << tmp;

This is quite surprising semantics for an out-of-range shift.
It's also broken for 32-bit operations, where you're still checking for 64,
when 32 is more relevance.

What semantics are you actually after?

You should also recall that you have the immediate and there's little point in
generating all of this code when a simple comparison now would be sufficient.

> +    if (op_types != IMM_IMM) {
> +        /* Handle left shift by 64 which hexagon-sim expects to clear out */
> +        /* register */

Oh, I see.  Really only 64, or any out-of-range shift?  Bearing in mind that 32
is also an out-of-range shift for !op_is64bit.

> +        if (op_types == REG_REG || op_types == IMM_REG) {
> +            OUT(c, locp, "(TCG_COND_EQ, ", res, ", ", &op2, ", ", &edge);
> +        } else {
> +            OUT(c, locp, "(TCG_COND_EQ, ", res, ", ", &op2, ", ", &edge);

These are identical, and in fact the else isn't reachable.

I strongly suggest TCG_COND_GEU.

> +static void gen_asr_op(Context *c, YYLTYPE *locp, unsigned bit_width,
> +                       const char *bit_suffix, HexValue *res,
> +                       enum OpTypes op_types, HexValue *op1, HexValue *op2)
> +{
> +    switch (op_types) {
> +    case IMM_IMM:
> +        OUT(c, locp, "int", &bit_width, "_t ", res,
> +            " = ", op1, " >> ", op2, ";\n");
> +        break;
> +    case REG_IMM:
> +        OUT(c, locp, "tcg_gen_sari_", bit_suffix,
> +            "(", res, ", ", op1, ", ", op2, ");\n");
> +        break;
> +    case IMM_REG:
> +        rvalue_materialize(c, locp, op1);
> +        /* Fallthrough */
> +    case REG_REG:
> +        OUT(c, locp, "tcg_gen_sar_", bit_suffix,
> +            "(", res, ", ", op1, ", ", op2, ");\n");

No out-of-range shift problems for ASR and LSR?

> +static void gen_orb_op(Context *c, YYLTYPE *locp, unsigned bit_width,
> +                       const char *bit_suffix, HexValue *res,
> +                       enum OpTypes op_types, HexValue *op1, HexValue *op2)
> +{
> +    switch (op_types) {
> +    case IMM_IMM:
> +        OUT(c, locp, "int", &bit_width, "_t ",
> +            res, " = ", op1, " & ", op2, ";\n");

cut-and-paste error

> +static void gen_xorb_op(Context *c, YYLTYPE *locp, unsigned bit_width,
> +                        const char *bit_suffix, HexValue *res,
> +                        enum OpTypes op_types, HexValue *op1, HexValue *op2)
> +{
> +    switch (op_types) {
> +    case IMM_IMM:
> +        OUT(c, locp, "int", &bit_width, "_t ",
> +            res, " = ", op1, " & ", op2, ";\n");

and again.

> +static void gen_mini_op(Context *c, YYLTYPE *locp, unsigned bit_width,
> +                        HexValue *res, enum OpTypes op_types,
> +                        HexValue *op1_ptr, HexValue *op2_ptr)
> +{
> +    HexValue op1 = *op1_ptr;
> +    HexValue op2 = *op2_ptr;
> +    const char *comparison = res->is_unsigned
> +                             ? "TCG_COND_LEU"
> +                             : "TCG_COND_LE";

tcg_gen_smin
tcg_gen_umin

> +static void gen_maxi_op(Context *c, YYLTYPE *locp, unsigned bit_width,
> +                        HexValue *res, enum OpTypes op_types,
> +                        HexValue *op1_ptr, HexValue *op2_ptr)
> +{
> +    HexValue op1 = *op1_ptr;
> +    HexValue op2 = *op2_ptr;
> +    const char *comparison = res->is_unsigned
> +                             ? "TCG_COND_LEU"
> +                             : "TCG_COND_LE";

tcg_gen_smax
tcg_gen_umax

> +    /* Find bit width of the two operands, if at least one is 64 bit use a */
> +    /* 64bit operation, eventually extend 32bit operands. */
> +    bool op_is64bit = op1.bit_width == 64 || op2.bit_width == 64;
> +    /* Shift greater than 32 are 64 bits wide */
> +    if (type == ASL_OP && op2.type == IMMEDIATE &&
> +        op2.imm.type == VALUE && op2.imm.value >= 32)
> +        op_is64bit = true;

Ah that explains the focus on 64 above.  And reinforces that we need to have
completely evaluated op2.imm.value, and can leave none of it to the generated code.

> +HexValue gen_fbrev_4(Context *c, YYLTYPE *locp, HexValue *source)
> +{
> +    HexValue source_m = *source;
> +
> +    HexValue res = gen_tmp(c, locp, 32);
> +    HexValue tmp1 = gen_tmp(c, locp, 32);
> +    HexValue tmp2 = gen_tmp(c, locp, 32);
> +
> +    source_m = rvalue_materialize(c, locp, &source_m);
> +    source_m = rvalue_truncate(c, locp, &source_m);
> +
> +    OUT(c, locp, "tcg_gen_mov_tl(", &res, ", ", &source_m, ");\n");
> +    OUT(c, locp, "tcg_gen_andi_tl(", &tmp1, ", ", &res, ", 0xaaaaaaaa);\n");
> +    OUT(c, locp, "tcg_gen_shri_tl(", &tmp1, ", ", &tmp1, ", 1);\n");
> +    OUT(c, locp, "tcg_gen_andi_tl(", &tmp2, ", ", &res, ", 0x55555555);\n");
> +    OUT(c, locp, "tcg_gen_shli_tl(", &tmp2, ", ", &tmp2, ", 1);\n");
> +    OUT(c, locp, "tcg_gen_or_tl(", &res, ", ", &tmp1, ", ", &tmp2, ");\n");
> +    OUT(c, locp, "tcg_gen_andi_tl(", &tmp1, ", ", &res, ", 0xcccccccc);\n");
> +    OUT(c, locp, "tcg_gen_shri_tl(", &tmp1, ", ", &tmp1, ", 2);\n");
> +    OUT(c, locp, "tcg_gen_andi_tl(", &tmp2, ", ", &res, ", 0x33333333);\n");
> +    OUT(c, locp, "tcg_gen_shli_tl(", &tmp2, ", ", &tmp2, ", 2);\n");
> +    OUT(c, locp, "tcg_gen_or_tl(", &res, ", ", &tmp1, ", ", &tmp2, ");\n");
> +    OUT(c, locp, "tcg_gen_andi_tl(", &tmp1, ", ", &res, ", 0xf0f0f0f0);\n");
> +    OUT(c, locp, "tcg_gen_shri_tl(", &tmp1, ", ", &tmp1, ", 4);\n");
> +    OUT(c, locp, "tcg_gen_andi_tl(", &tmp2, ", ", &res, ", 0x0f0f0f0f);\n");
> +    OUT(c, locp, "tcg_gen_shli_tl(", &tmp2, ", ", &tmp2, ", 4);\n");
> +    OUT(c, locp, "tcg_gen_or_tl(", &res, ", ", &tmp1, ", ", &tmp2, ");\n");
> +    OUT(c, locp, "tcg_gen_andi_tl(", &tmp1, ", ", &res, ", 0xff00ff00);\n");

>From here is

> +    OUT(c, locp, "tcg_gen_shri_tl(", &tmp1, ", ", &tmp1, ", 8);\n");
> +    OUT(c, locp, "tcg_gen_andi_tl(", &tmp2, ", ", &res, ", 0x00ff00ff);\n");
> +    OUT(c, locp, "tcg_gen_shli_tl(", &tmp2, ", ", &tmp2, ", 8);\n");
> +    OUT(c, locp, "tcg_gen_or_tl(", &res, ", ", &tmp1, ", ", &tmp2, ");\n");
> +    OUT(c, locp, "tcg_gen_shri_tl(", &tmp1, ", ", &res, ", 16);\n");
> +    OUT(c, locp, "tcg_gen_shli_tl(", &tmp2, ", ", &res, ", 16);\n");
> +    OUT(c, locp, "tcg_gen_or_tl(", &res, ", ", &tmp1, ", ", &tmp2, ");\n");

tcg_gen_bswap32

But I think you should question whether you want to use a helper, especially for

> +HexValue gen_fbrev_8(Context *c, YYLTYPE *locp, HexValue *source)

this one.

> +HexValue gen_rotl(Context *c, YYLTYPE *locp, HexValue *source, HexValue *n)

tcg_gen_rotl

> +bool reg_equal(HexReg *r1, HexReg *r2)
> +{
> +    return !memcmp(r1, r2, sizeof(HexReg));
> +}

I don't see these structures being zeroed on creation, so you're relying on
there being no embedded padding.  Without the zeroing, I think you're better
off with an element-by-element compare.

> +bool rvalue_equal(HexValue *v1, HexValue *v2)
> +{
> +    if (v1->is_dotnew != v2->is_dotnew) {
> +        return false;
> +    } else if (v1->type == REGISTER && v2->type == REGISTER) {
> +        return reg_equal(&(v1->reg), &(v2->reg));
> +    } else if (v1->type == PREDICATE && v2->type == PREDICATE) {
> +        return pre_equal(&(v1->pre), &(v2->pre));
> +    } else {
> +        return false;

IMMEDIATEs are never equal?

> +void emit_header(Context *c)
> +{
> +    EMIT_SIG(c, START_COMMENT " %s " END_COMMENT "\n", c->inst.name);
> +    EMIT_SIG(c, "void emit_%s(DisasContext *ctx, Insn *insn, Packet *pkt",
> +             c->inst.name);

The comment seems redundant, given that it says nothing that the function name
does not.

> +#define OUT_IMPL(c, locp, x)                                            \
> +    do {                                                                \
> +        if (__builtin_types_compatible_p(typeof(*x), char)) {           \
> +            str_print((c), (locp), (char *) x);                         \
> +        } else if (__builtin_types_compatible_p(typeof(*x), uint64_t)) { \
> +            uint64_print((c), (locp), (uint64_t *) x);                  \
> +        } else if (__builtin_types_compatible_p(typeof(*x), int)) {     \
> +            int_print((c), (locp), (int *) x);                          \
> +        } else if (__builtin_types_compatible_p(typeof(*x), unsigned)) { \
> +            uint_print((c), (locp), (unsigned *) x);                    \
> +        } else if (__builtin_types_compatible_p(typeof(*x), HexValue)) { \
> +            rvalue_out((c), (locp), (HexValue *) x);                 \
> +        } else {                                                        \
> +            yyassert(c, locp, false, "Unhandled print type!");          \
> +        }                                                               \

FWIW, the supporting macros here are re-impleenting QEMU_GENERIC.


r~
Alessandro Di Federico March 1, 2021, 2:50 p.m. UTC | #2
On Thu, 25 Feb 2021 19:30:14 -0800
Richard Henderson <richard.henderson@linaro.org> wrote:

> > +    }
> > +}
> > +code
> > +{
> > +    if (c->inst.error_count != 0) {
> > +        fprintf(stderr,
> > +                "Parsing of instruction %s generated %d errors!\n",
> > +                c->inst.name,
> > +                c->inst.error_count);
> > +        EMIT(c, "assert(false && \"This instruction is not
> > implemented!\");");  
> 
> What's the point of assert(false) above abort()?
> 
> Is there any point in emitting anything at all, since I assume the
> idef-parser program itself will exit with error, stopping the build
> process?

This is a leftover, that string will never be written to disk (`commit`
is not invoked).

> > +| pre ASSIGN rvalue
> > +{
> > +    @1.last_column = @3.last_column;  
> 
> Do you really find any value in this column manipulation, given that
> the input is not the original file, but the output of cpp?

The output of `cpp` is quite readable. We use it a lot for debugging
and it's very helpful.

> IMO this is another reason to *not* preprocess with macros.inc, nor
> sed the output as a workaround for your parsing troubles.

Yes, `sed` is a workaround I really don't like too. But preprocessing
with `cpp` saves us from having to handle a larger, redundant language.
After all, the input language is designed to be expanded through the
preprocessor, although with a different set of macros. I'd keep that
part.
Paolo Montesel March 23, 2021, 4:52 p.m. UTC | #3
Thanks for the feedback, it helped us improve the implementation quite a bit.

> > +| rvalue QMARK rvalue COLON rvalue
> > +{
> > +    @1.last_column = @5.last_column;
> > +    bool is_64bit = ($3.bit_width == 64) || ($5.bit_width == 64);
> > +    int bit_width = (is_64bit) ? 64 : 32;
> > +    if (is_64bit) {
> > +        $1 = rvalue_extend(c, &@1, &$1);
> > +        $3 = rvalue_extend(c, &@1, &$3);
> > +        $5 = rvalue_extend(c, &@1, &$5);
> > +    } else {
> > +        $1 = rvalue_truncate(c, &@1, &$1);
> > +    }
> > +    $1 = rvalue_materialize(c, &@1, &$1);
> > +    $3 = rvalue_materialize(c, &@1, &$3);
> > +    $5 = rvalue_materialize(c, &@1, &$5);
> > +    HexValue res = gen_local_tmp(c, &@1, bit_width);
> > +    HexValue zero = gen_tmp_value(c, &@1, "0", bit_width);
> > +    OUT(c, &@1, "tcg_gen_movcond_i", &bit_width);
> > +    OUT(c, &@1, "(TCG_COND_NE, ", &res, ", ", &$1, ", ", &zero);
>
> It would be better if you parsed conditions differently.
> Retain the two arguments and the condition, so that you can fold that into the
> movcond directly.
>
> E.g. instead of
>
>     tcg_gen_setcond_i32(cond, t, x, y)
>     tcg_gen_movcond_i32(TCG_COND_NE, dest, t, zero, src1, src2);
>
> you'd be able to do
>
>     tcg_gen_movcond_i32(cond, dest, x, y, src1, src2);
>
> This would be trivial with a non-terminal "cond", used here and with IF.  You'd
> include cond as an alternative of rvalue, which would perform the reduction to
> boolean with setcond.

This would save us from emitting some tcg ops but would increase the
complexity of the parser, which doesn't seem worth it imho.

> > +    case VALUE:
> > +        EMIT(c, "((int64_t)%" PRIu64 "ULL)", (int64_t)imm->value);
>
> Why are you using ull then casting to signed?  Just use ll.

We have a case in which we would print `-9223372036854775808LL` (64
bit integer with sign bit set) and gcc would complain with `warning:
integer constant is so large that it is unsigned`.
That's the reason for using ULL and then casting.
I'm open to other solutions.

> > +    switch (op_types) {
> > +    case IMM_IMM:
> > +    {
> > +        OUT(c, locp, "tcg_gen_movi_", bit_suffix,
> > +            "(", &res, ", ", &op1, " == ", &op2, ");\n");
> > +        break;
> > +    }
>
> Drop useless braces like this.
>
> Do you really see any IMM_IMM operations?  There are some typos in this
> section, so certainly all operators are not represented.  It might be worth
> folding all of these inside the parser, and not deferring to the C compiler, so
> that you can be certain of having a real value for any IMMEDIATE.  Which will
> help when it comes to shift below.

Maybe not for all bin ops, but we do see IMM_IMM.
I think we can't always fold IMMEDIATES, because they include "normal"
C variables (e.g.: `int32_t uiV` in function arguments) that depend on
instruction bytes at runtime.
That's true also for the IMM_IMM case.

> I'm thinking that this code could really benefit from tcg_constant_{i32,i64}.
> It produces a hashed temp that need not be freed, and it's what many of the
> tcg_gen_fooi functions use in the backend.

We can technically convert all the IMMs to tcg_constant before using
them, but since we can't constant fold in the parser that would
probably decrease performance quite a bit.

> > +static void gen_div_op(Context *c, YYLTYPE *locp, HexValue *res,
> > +                       enum OpTypes op_types, HexValue *op1, HexValue *op2)
> > +{
> > +    switch (op_types) {
> > +    case IMM_IMM:
> > +        OUT(c, locp, "int64_t ", res, " = ", op1, " / ", op2, ";\n");
> > +        break;
> > +    case IMM_REG:
> > +    case REG_IMM:
> > +    case REG_REG:
> > +        OUT(c, locp, res, " = gen_helper_divu("
> > +            "cpu_env, ", op1, ", ", op2, ");\n");
>
> Are we trusting that div-by-zero has already been tested for?

Turns out div is not even used by the instructions we currently
support (: so we can just delete this

~Paolo
diff mbox series

Patch

diff --git a/target/hexagon/idef-parser/idef-parser.y b/target/hexagon/idef-parser/idef-parser.y
new file mode 100644
index 0000000000..d9dd81bd6f
--- /dev/null
+++ b/target/hexagon/idef-parser/idef-parser.y
@@ -0,0 +1,1250 @@ 
+%{
+/*
+ * Copyright(c) 2019-2020 rev.ng Srls. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; withOUT even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; 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}
+
+/* Uncomment this for better errors in recent bison versions */
+/* %define parse.error detailed */
+%define parse.error verbose
+%define parse.lac full
+%define api.pure full
+
+%locations
+
+%union {
+    char *string;
+    HexValue rvalue;
+    HexSat sat;
+    HexCast cast;
+    HexExtract extract;
+    HexMpy mpy;
+    bool is_unsigned;
+    int index;
+}
+
+/* Tokens */
+%start input
+
+%expect 1
+
+%token INAME DREG DIMM DPRE DEA RREG WREG FREG FIMM RPRE WPRE FPRE FWRAP FEA
+%token VAR LBR RBR LPAR RPAR LSQ RSQ SEMI COLON PLUS MINUS MUL POW DIV MOD ABS
+%token CROUND ROUND CIRCADD COUNTONES AND OR XOR NOT ASSIGN INC DEC ANDA ORA
+%token XORA PLUSPLUS LT GT ASL ASR LSR EQ NEQ LTE GTE MIN MAX ANDL ORL NOTL
+%token COMMA FOR ICIRC IF MUN FSCR FCHK SXT ZXT NEW CONSTEXT LOCNT BREV SIGN
+%token LOAD STORE CONSTLL CONSTULL PC NPC LPCFG CANC QMARK IDENTITY PART1
+%token BREV_4 BREV_8 ROTL INSBITS SETBITS EXTBITS EXTRANGE CAST4_8U SETOVF FAIL
+%token DEINTERLEAVE INTERLEAVE
+
+%token <rvalue> REG IMM PRE
+%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 pre
+%type <rvalue> DREG DIMM DPRE RREG RPRE FAIL
+%type <index> if_stmt IF
+%type <is_unsigned> SIGN
+
+/* Operator Precedences */
+%left MIN MAX
+%left LPAR
+%left COMMA
+%left ASSIGN
+%right CIRCADD
+%right INC DEC ANDA ORA XORA
+%left QMARK COLON
+%left ORL
+%left ANDL
+%left OR
+%left XOR ANDOR
+%left AND
+%left EQ NEQ
+%left LT GT LTE GTE
+%left ASL ASR LSR
+%right ABS
+%left MINUS PLUS
+%left POW
+%left MUL DIV MOD MPY
+%right NOT NOTL
+%left LSQ
+%left NEW
+%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
+{
+    /* Early-free if the parser failed on the previous instruction */
+    free_instruction(c);
+
+    c->total_insn++;
+    c->inst.name = $1;
+    emit_header(c);
+}
+arguments
+{
+    EMIT_SIG(c, ")");
+    EMIT_HEAD(c, "{\n");
+
+    /* Initialize declared but uninitialized registers, but only for */
+    /* non-conditional instructions */
+    for (int i = 0; i < c->inst.init_count; i++) {
+        bool is64 = c->inst.init_list[i].bit_width == 64;
+        const char *type = is64 ? "i64" : "i32";
+        if (c->inst.init_list[i].type == REGISTER) {
+            OUT(c, &@1, "tcg_gen_movi_", type,
+                "(", &(c->inst.init_list[i]), ", 0);\n");
+        } else if (c->inst.init_list[i].type == PREDICATE) {
+            OUT(c, &@1, "tcg_gen_movi_", type,
+                "(", &(c->inst.init_list[i]), ", 0);\n");
+        }
+    }
+}
+code
+{
+    if (c->inst.error_count != 0) {
+        fprintf(stderr,
+                "Parsing of instruction %s generated %d errors!\n",
+                c->inst.name,
+                c->inst.error_count);
+        EMIT(c, "assert(false && \"This instruction is not implemented!\");");
+    } else {
+        free_variables(c, &@1);
+        c->implemented_insn++;
+        fprintf(c->enabled_file, "%s\n", c->inst.name);
+        emit_footer(c);
+        commit(c);
+    }
+    free_instruction(c);
+}
+| error /* Recover gracefully after instruction compilation error */
+;
+
+arguments : LPAR RPAR
+|
+LPAR argument_list RPAR
+;
+
+argument_list : decl COMMA argument_list
+| decl
+;
+
+/* Return the modified registers list */
+code : LBR statements RBR
+{
+    c->inst.code_begin = c->input_buffer + @2.first_column;
+    c->inst.code_end = c->input_buffer + @2.last_column - 1;
+}
+|
+LBR
+{
+    /* Nop */
+}
+RBR
+;
+
+decl : REG
+{
+    emit_arg(c, &@1, &$1);
+    /* Enqueue register into initialization list */
+    yyassert(c, &@1, c->inst.init_count < INIT_LIST_LEN,
+             "init_count overflow");
+    c->inst.init_list[c->inst.init_count] = $1;
+    c->inst.init_count++;
+}
+| IMM
+{
+    EMIT_SIG(c, ", int %ciV", $1.imm.id);
+}
+| PRE
+{
+    emit_arg(c, &@1, &$1);
+    /* Enqueue predicate into initialization list */
+    c->inst.init_list[c->inst.init_count] = $1;
+    c->inst.init_count++;
+}
+| VAR
+{
+    yyassert(c, &@1, !strcmp($1.var.name, "EA"), "Unknown argument variable!");
+}
+| RREG
+{
+    emit_arg(c, &@1, &$1);
+}
+| WREG
+| FREG
+| FIMM
+| RPRE
+{
+    emit_arg(c, &@1, &$1);
+}
+| WPRE
+| FPRE
+| FEA
+;
+
+code_block : LBR statements RBR            { /* does nothing */ }
+| LBR RBR                       { /* does nothing */ }
+;
+
+/* A list of one or more statements */
+statements : statements statement         { /* does nothing */ }
+| statement                    { /* does nothing */ }
+;
+
+/* Statements can be assignment (rvalue SEMI), control or memory statements */
+statement : control_statement            { /* does nothing */ }
+| rvalue SEMI                  { rvalue_free(c, &@1, &$1); }
+| code_block                   { /* does nothing */ }
+| SEMI                         { /* does nothing */ }
+;
+
+assign_statement : lvalue ASSIGN 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;
+}
+| pre ASSIGN rvalue
+{
+    @1.last_column = @3.last_column;
+    bool is_direct = is_direct_predicate(&$1);
+    char pre_id[2] = " ";
+    pre_id[0] = $1.pre.id;
+    /* Extract predicate TCGv */
+    if (is_direct) {
+        $1 = gen_tmp_value(c, &@1, "0", 32);
+    }
+    $3 = rvalue_materialize(c, &@1, &$3);
+    $3 = rvalue_truncate(c, &@1, &$3);
+    /* Extract first 8 bits, and store new predicate value */
+    if ($3.type == IMMEDIATE) {
+        OUT(c, &@1, &$3, " = (", &$3, " & 0xff) << i;\n");
+        OUT(c, &@1, "tcg_gen_ori_i32(", &$1, ", ", &$1, ", ", &$3, ");\n");
+    } else {
+        OUT(c, &@1, "tcg_gen_mov_i32(", &$1, ", ", &$3, ");\n");
+        OUT(c, &@1, "tcg_gen_andi_i32(", &$1, ", ", &$1, ", 0xff);\n");
+    }
+    if (is_direct) {
+        OUT(c, &@1, "gen_log_pred_write(", pre_id, ", ", &$1, ");\n");
+        OUT(c, &@1, "ctx_log_pred_write(ctx, ", pre_id, ");\n");
+        rvalue_free(c, &@1, &$1);
+    }
+    rvalue_free(c, &@1, &$3);  /* Free temporary value */
+}
+| IMM ASSIGN 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 ASSIGN rvalue
+{
+    @1.last_column = @3.last_column;
+    $3 = rvalue_truncate(c, &@1, &$3);
+    $3 = rvalue_materialize(c, &@1, &$3);
+    OUT(c, &@1, "gen_write_new_pc(", &$3, ");\n");
+    rvalue_free(c, &@1, &$3); /* Free temporary value */
+}
+| LOAD LPAR IMM COMMA IMM COMMA SIGN COMMA VAR COMMA lvalue RPAR
+{
+    @1.last_column = @12.last_column;
+    /* Memop width is specified in the load macro */
+    int bit_width = ($5.imm.value > 4) ? 64 : 32;
+    const char *sign_suffix = ($5.imm.value > 4) ? "" : (($7) ? "u" : "s");
+    char size_suffix[4] = { 0 };
+    /* Create temporary variable (if not present) */
+    if ($11.type == VARID) {
+        /* TODO: this is a common pattern, the parser should be varid-aware. */
+        varid_allocate(c, &@1, &$11, bit_width, $7);
+    }
+    snprintf(size_suffix, 4, "%" PRIu64, $5.imm.value * 8);
+    if (bit_width == 32) {
+        $11 = rvalue_truncate(c, &@1, &$11);
+    } else {
+        $11 = rvalue_extend(c, &@1, &$11);
+    }
+    if ($9.type == VARID) {
+        int var_id = find_variable(c, &@1, &$9);
+        yyassert(c, &@1, var_id != -1, "Load variable must exist!\n");
+        /* We need to enforce the variable size */
+        $9.bit_width = c->inst.allocated[var_id].bit_width;
+    }
+    if ($9.bit_width != 32) {
+        $9 = rvalue_truncate(c, &@1, &$9);
+    }
+    OUT(c, &@1, "if (insn->slot == 0 && pkt->pkt_has_store_s1) {\n");
+    OUT(c, &@1, "process_store(ctx, pkt, 1);\n");
+    OUT(c, &@1, "}\n");
+    OUT(c, &@1, "tcg_gen_qemu_ld", size_suffix, sign_suffix);
+    OUT(c, &@1, "(", &$11, ", ", &$9, ", 0);\n");
+    /* If the var in $9 was truncated it is now a tmp HexValue, so free it. */
+    rvalue_free(c, &@1, &$9);
+}
+| STORE LPAR IMM COMMA IMM COMMA VAR COMMA rvalue RPAR /* Store primitive */
+{
+    @1.last_column = @10.last_column;
+    /* Memop width is specified in the store macro */
+    int mem_width = $5.imm.value;
+    /* Adjust operand bit width to memop bit width */
+    if (mem_width < 8) {
+        $9 = rvalue_truncate(c, &@1, &$9);
+    } else {
+        $9 = rvalue_extend(c, &@1, &$9);
+    }
+    if ($7.type == VARID) {
+        int var_id = find_variable(c, &@1, &$7);
+        yyassert(c, &@1, var_id != -1, "Load variable must exist!\n");
+        /* We need to enforce the variable size */
+        $7.bit_width = c->inst.allocated[var_id].bit_width;
+    }
+    if ($7.bit_width != 32) {
+        $7 = rvalue_truncate(c, &@1, &$7);
+    }
+    $9 = rvalue_materialize(c, &@1, &$9);
+    OUT(c, &@1, "gen_store", &mem_width, "(cpu_env, ", &$7, ", ", &$9);
+    OUT(c, &@1, ", ctx, insn->slot);\n");
+    rvalue_free(c, &@1, &$9);
+    /* If the var in $7 was truncated it is now a tmp HexValue, so free it. */
+    rvalue_free(c, &@1, &$7);
+}
+| LPCFG ASSIGN rvalue
+{
+    @1.last_column = @3.last_column;
+    $3 = rvalue_truncate(c, &@1, &$3);
+    $3 = rvalue_materialize(c, &@1, &$3);
+    OUT(c, &@1, "SET_USR_FIELD(USR_LPCFG, ", &$3, ");\n");
+    rvalue_free(c, &@1, &$3);
+}
+| DEPOSIT LPAR rvalue COMMA rvalue COMMA rvalue RPAR
+{
+    @1.last_column = @8.last_column;
+    gen_deposit_op(c, &@1, &$5, &$7, &$3, &$1);
+}
+| SETHALF LPAR rvalue COMMA lvalue COMMA rvalue RPAR
+{
+    @1.last_column = @8.last_column;
+    yyassert(c, &@1, $3.type == IMMEDIATE,
+             "Deposit index must be immediate!\n");
+    if ($5.type == VARID) {
+        int var_id = find_variable(c, &@1, &$5);
+        if (var_id == -1) {
+            HexValue zero = gen_imm_value(c, &@1, 0, 64);
+            zero.is_unsigned = true;
+            $5.bit_width = 64;
+            gen_assign(c, &@1, &$5, &zero);
+        } else {
+            /* We need to enforce the variable size (default is 32) */
+            $5.bit_width = c->inst.allocated[var_id].bit_width;
+        }
+    }
+    gen_deposit_op(c, &@1, &$5, &$7, &$3, &$1);
+}
+| SETBITS LPAR rvalue COMMA rvalue COMMA rvalue COMMA rvalue RPAR
+{
+    @1.last_column = @10.last_column;
+    yyassert(c, &@1, $3.type == IMMEDIATE &&
+             $3.imm.type == VALUE &&
+             $5.type == IMMEDIATE &&
+             $5.imm.type == VALUE,
+             "Range deposit needs immediate values!\n");
+    int i;
+    $9 = rvalue_truncate(c, &@1, &$9);
+    for (i = $5.imm.value; i <= $3.imm.value; ++i) {
+        OUT(c, &@1, "gen_set_bit(", &i, ", ", &$7, ", ", &$9, ");\n");
+    }
+    rvalue_free(c, &@1, &$3);
+    rvalue_free(c, &@1, &$5);
+    rvalue_free(c, &@1, &$7);
+    rvalue_free(c, &@1, &$9);
+}
+| INSBITS LPAR lvalue COMMA rvalue COMMA rvalue COMMA rvalue RPAR
+{
+    @1.last_column = @10.last_column;
+    gen_rdeposit_op(c, &@1, &$3, &$9, &$7, &$5);
+}
+| IDENTITY LPAR rvalue RPAR
+{
+    @1.last_column = @4.last_column;
+    $$ = $3;
+}
+;
+
+control_statement : frame_check          { /* does nothing */ }
+| cancel_statement     { /* does nothing */ }
+| if_statement         { /* does nothing */ }
+| for_statement        { /* does nothing */ }
+| fpart1_statement     { /* does nothing */ }
+;
+
+frame_check : FCHK LPAR rvalue COMMA rvalue RPAR SEMI  {
+    /* does nothing */
+    rvalue_free(c, &@1, &$3);
+    rvalue_free(c, &@1, &$5);
+}
+;
+
+cancel_statement : CANC
+{
+    OUT(c, &@1, "gen_cancel(insn->slot);\n");
+}
+;
+
+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;
+    /* Generate label to jump if else is not verified */
+    OUT(c, &@1, "TCGLabel *if_label_", &c->inst.if_count,
+        " = gen_new_label();\n");
+    $2 = c->inst.if_count;
+    c->inst.if_count++;
+    /* Jump out of the else statement */
+    OUT(c, &@1, "tcg_gen_br(if_label_", &$2, ");\n");
+    /* Fix the else label */
+    OUT(c, &@1, "gen_set_label(if_label_", &$1, ");\n");
+}
+statement
+{
+    OUT(c, &@1, "gen_set_label(if_label_", &$2, ");\n");
+}
+;
+
+for_statement : FOR LPAR IMM ASSIGN IMM SEMI IMM LT IMM SEMI IMM PLUSPLUS RPAR
+{
+    @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");
+}
+;
+
+for_statement : FOR LPAR IMM ASSIGN IMM SEMI IMM LT IMM SEMI IMM INC IMM RPAR
+{
+    @1.last_column = @14.last_column;
+    OUT(c, &@1, "for (int ", &$3, " = ", &$5, "; ", &$7, " < ", &$9);
+    OUT(c, &@1, "; ", &$11, " += ", &$13, ") {\n");
+}
+code_block
+{
+    OUT(c, &@1, "}\n");
+}
+;
+
+fpart1_statement : PART1
+{
+    OUT(c, &@1, "if (insn->part1) {\n");
+}
+LPAR statements RPAR
+{
+    @1.last_column = @3.last_column;
+    OUT(c, &@1, "return; }\n");
+}
+;
+
+if_stmt : IF
+{
+    /* Generate an end label, if false branch to that label */
+    OUT(c, &@1, "TCGLabel *if_label_", &c->inst.if_count,
+        " = gen_new_label();\n");
+}
+LPAR rvalue RPAR
+{
+    @1.last_column = @3.last_column;
+    $4 = rvalue_materialize(c, &@1, &$4);
+    const char *bit_suffix = ($4.bit_width == 64) ? "i64" : "i32";
+    OUT(c, &@1, "tcg_gen_brcondi_", bit_suffix, "(TCG_COND_EQ, ", &$4,
+        ", 0, if_label_", &c->inst.if_count, ");\n");
+    rvalue_free(c, &@1, &$4);
+    $1 = c->inst.if_count;
+    c->inst.if_count++;
+}
+statement
+{
+    $$ = $1;
+}
+;
+
+rvalue : FAIL
+{
+    @1.last_column = @1.last_column;
+    yyassert(c, &@1, false, "Encountered a FAIL token as rvalue.\n");
+}
+|
+assign_statement            { /* does nothing */ }
+| REG
+{
+    if ($1.reg.type == CONTROL) {
+        $$ = gen_read_creg(c, &@1, &$1);
+    } else {
+        $$ = $1;
+    }
+}
+| IMM
+{
+    $$ = $1;
+}
+| CONSTLL LPAR IMM RPAR
+{
+    $3.is_unsigned = false;
+    $3.bit_width = 64;
+    $$ = $3;
+}
+| CONSTULL LPAR IMM RPAR
+{
+    $3.is_unsigned = true;
+    $3.bit_width = 64;
+    $$ = $3;
+}
+| pre
+{
+    if (is_direct_predicate(&$1)) {
+        bool is_dotnew = $1.is_dotnew;
+        char predicate_id[2] = {$1.pre.id, '\0'};
+        char *pre_str = (char *) &predicate_id;
+        $1 = gen_tmp_value(c, &@1, "0", 32);
+        if (is_dotnew) {
+            OUT(c, &@1, "tcg_gen_mov_i32(", &$1, ", hex_new_pred_value[");
+            OUT(c, &@1, pre_str, "]);\n");
+        } else {
+            OUT(c, &@1, "gen_read_preg(", &$1, ", ", pre_str, ");\n");
+        }
+    }
+    $$ = $1;
+}
+| PC
+{
+    /* Read PC from the CR */
+    $$ = gen_tmp(c, &@1, 32);
+    OUT(c, &@1, "tcg_gen_mov_i32(", &$$, ", hex_gpr[HEX_REG_PC]);\n");
+}
+| NPC
+{
+    /* NPC is only read from CALLs, so we can hardcode it at translation time */
+    $$ = gen_tmp(c, &@1, 32);
+    OUT(c, &@1, "tcg_gen_movi_i32(", &$$, ", ctx->npc);\n");
+}
+| CONSTEXT
+{
+    HexValue rvalue;
+    rvalue.type = IMMEDIATE;
+    rvalue.imm.type = IMM_CONSTEXT;
+    rvalue.is_unsigned = true;
+    rvalue.is_dotnew = false;
+    rvalue.is_manual = false;
+    $$ = rvalue;
+}
+| VAR
+{
+    /* Assign correct bit width and signedness */
+    bool found = false;
+    for (int i = 0; i < c->inst.allocated_count; i++) {
+        if (!strcmp($1.var.name, c->inst.allocated[i].name)) {
+            found = true;
+            free(c->inst.allocated[i].name);
+            c->inst.allocated[i].name = $1.var.name;
+            $1.bit_width = c->inst.allocated[i].bit_width;
+            $1.is_unsigned = c->inst.allocated[i].is_unsigned;
+            break;
+        }
+    }
+    yyassert(c, &@1, found, "Undefined symbol!\n");
+    $$ = $1;
+}
+| MPY LPAR rvalue COMMA rvalue RPAR
+{
+    @1.last_column = @6.last_column;
+    $3.is_unsigned = $1.first_unsigned;
+    $5.is_unsigned = $1.second_unsigned;
+    $3 = gen_cast_op(c, &@1, &$3, $1.first_bit_width * 2);
+    /* Handle fMPTY3216.. */
+    if ($1.first_bit_width == 32) {
+        $5 = gen_cast_op(c, &@1, &$5, 64);
+    } else {
+        $5 = gen_cast_op(c, &@1, &$5, $1.second_bit_width * 2);
+    }
+    $$ = gen_bin_op(c, &@1, MUL_OP, &$3, &$5);
+    /* Handle special cases required by the language */
+    if ($1.first_bit_width == 16 && $1.second_bit_width == 16) {
+        HexValue src_width = gen_imm_value(c, &@1, 32, 32);
+        HexValue dst_width = gen_imm_value(c, &@1, 64, 32);
+        $$ = gen_extend_op(c, &@1, &src_width, &dst_width, &$$,
+                           $1.first_unsigned && $1.second_unsigned);
+    }
+}
+| rvalue PLUS rvalue
+{
+    @1.last_column = @3.last_column;
+    $$ = gen_bin_op(c, &@1, ADD_OP, &$1, &$3);
+}
+| rvalue MINUS rvalue
+{
+    @1.last_column = @3.last_column;
+    $$ = gen_bin_op(c, &@1, SUB_OP, &$1, &$3);
+}
+| rvalue MUL rvalue
+{
+    @1.last_column = @3.last_column;
+    $$ = gen_bin_op(c, &@1, MUL_OP, &$1, &$3);
+}
+| rvalue POW rvalue
+{
+    @1.last_column = @3.last_column;
+    /* We assume that this is a shorthand for a shift */
+    yyassert(c, &@1, $1.type == IMMEDIATE && $1.imm.value == 2,
+             "Exponentiation is not a left shift!\n");
+    HexValue one = gen_imm_value(c, &@1, 1, 32);
+    HexValue shift = gen_bin_op(c, &@1, SUB_OP, &$3, &one);
+    $$ = gen_bin_op(c, &@1, ASL_OP, &$1, &shift);
+    rvalue_free(c, &@1, &one);
+    rvalue_free(c, &@1, &shift);
+}
+| rvalue DIV rvalue
+{
+    @1.last_column = @3.last_column;
+    $$ = gen_bin_op(c, &@1, DIV_OP, &$1, &$3);
+}
+| rvalue MOD rvalue
+{
+    @1.last_column = @3.last_column;
+    $$ = gen_bin_op(c, &@1, MOD_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;
+    if ($1.is_unsigned) {
+        $$ = gen_bin_op(c, &@1, LSR_OP, &$1, &$3);
+    } else {
+        $$ = 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 AND rvalue
+{
+    @1.last_column = @3.last_column;
+    $$ = gen_bin_op(c, &@1, ANDB_OP, &$1, &$3);
+}
+| rvalue OR rvalue
+{
+    @1.last_column = @3.last_column;
+    $$ = gen_bin_op(c, &@1, ORB_OP, &$1, &$3);
+}
+| rvalue XOR 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 LPAR rvalue COMMA rvalue RPAR
+{
+    @1.last_column = @3.last_column;
+    $$ = gen_bin_op(c, &@1, MINI_OP, &$3, &$5);
+}
+| MAX LPAR rvalue COMMA rvalue RPAR
+{
+    @1.last_column = @3.last_column;
+    $$ = gen_bin_op(c, &@1, MAXI_OP, &$3, &$5);
+}
+| NOT rvalue
+{
+    @1.last_column = @2.last_column;
+    const char *bit_suffix = ($2.bit_width == 64) ? "i64" : "i32";
+    int bit_width = ($2.bit_width == 64) ? 64 : 32;
+    HexValue res;
+    res.is_unsigned = $2.is_unsigned;
+    res.is_dotnew = false;
+    res.is_manual = false;
+    if ($2.type == IMMEDIATE) {
+        res.type = IMMEDIATE;
+        res.imm.type = QEMU_TMP;
+        res.imm.index = c->inst.qemu_tmp_count;
+        OUT(c, &@1, "int", &bit_width, "_t ", &res, " = ~", &$2, ";\n");
+        c->inst.qemu_tmp_count++;
+    } else {
+        res = gen_tmp(c, &@1, bit_width);
+        OUT(c, &@1, "tcg_gen_not_", bit_suffix, "(", &res,
+            ", ", &$2, ");\n");
+        rvalue_free(c, &@1, &$2);
+    }
+    $$ = res;
+}
+| NOTL rvalue
+{
+    @1.last_column = @2.last_column;
+    const char *bit_suffix = ($2.bit_width == 64) ? "i64" : "i32";
+    int bit_width = ($2.bit_width == 64) ? 64 : 32;
+    HexValue res;
+    res.is_unsigned = $2.is_unsigned;
+    res.is_dotnew = false;
+    res.is_manual = false;
+    if ($2.type == IMMEDIATE) {
+        res.type = IMMEDIATE;
+        res.imm.type = QEMU_TMP;
+        res.imm.index = c->inst.qemu_tmp_count;
+        OUT(c, &@1, "int", &bit_width, "_t ", &res, " = !", &$2, ";\n");
+        c->inst.qemu_tmp_count++;
+        $$ = res;
+    } else {
+        res = gen_tmp(c, &@1, bit_width);
+        HexValue zero = gen_tmp_value(c, &@1, "0", bit_width);
+        HexValue one = gen_tmp_value(c, &@1, "0xff", bit_width);
+        OUT(c, &@1, "tcg_gen_movcond_", bit_suffix);
+        OUT(c, &@1, "(TCG_COND_EQ, ", &res, ", ", &$2, ", ", &zero);
+        OUT(c, &@1, ", ", &one, ", ", &zero, ");\n");
+        rvalue_free(c, &@1, &$2);
+        rvalue_free(c, &@1, &zero);
+        rvalue_free(c, &@1, &one);
+        $$ = res;
+    }
+}
+| SAT LPAR IMM COMMA rvalue RPAR
+{
+    @1.last_column = @6.last_column;
+    if ($1.set_overflow) {
+        yyassert(c, &@1, $3.imm.value < $5.bit_width, "To compute overflow, "
+                 "source width must be greater than saturation width!");
+    }
+    HexValue res = gen_tmp(c, &@1, $5.bit_width);
+    const char *bit_suffix = ($5.bit_width == 64) ? "i64" : "i32";
+    const char *overflow_str = ($1.set_overflow) ? "true" : "false";
+    const char *unsigned_str = ($1.is_unsigned) ? "u" : "";
+    OUT(c, &@1, "gen_sat", unsigned_str, "_", bit_suffix, "(", &res, ", ");
+    OUT(c, &@1, &$5, ", ", &$3.imm.value, ", ", overflow_str, ");\n");
+    res.is_unsigned = $1.is_unsigned;
+    rvalue_free(c, &@1, &$5);
+    $$ = res;
+}
+| CAST rvalue
+{
+    @1.last_column = @2.last_column;
+    /* Assign target signedness */
+    $2.is_unsigned = $1.is_unsigned;
+    $$ = gen_cast_op(c, &@1, &$2, $1.bit_width);
+    $$.is_unsigned = $1.is_unsigned;
+}
+| rvalue LSQ rvalue RSQ
+{
+    @1.last_column = @4.last_column;
+    HexValue one = gen_imm_value(c, &@1, 1, $3.bit_width);
+    HexValue tmp = gen_bin_op(c, &@1, ASR_OP, &$1, &$3);
+    $$ = gen_bin_op(c, &@1, ANDB_OP, &tmp, &one);
+}
+| 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 LT rvalue
+{
+    @1.last_column = @3.last_column;
+    if ($1.is_unsigned || $3.is_unsigned) {
+        $$ = gen_bin_cmp(c, &@1, "TCG_COND_LTU", &$1, &$3);
+    } else {
+        $$ = gen_bin_cmp(c, &@1, "TCG_COND_LT", &$1, &$3);
+    }
+}
+| rvalue GT rvalue
+{
+    @1.last_column = @3.last_column;
+    if ($1.is_unsigned || $3.is_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;
+    if ($1.is_unsigned || $3.is_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;
+    if ($1.is_unsigned || $3.is_unsigned) {
+        $$ = gen_bin_cmp(c, &@1, "TCG_COND_GEU", &$1, &$3);
+    } else {
+        $$ = gen_bin_cmp(c, &@1, "TCG_COND_GE", &$1, &$3);
+    }
+}
+| rvalue QMARK rvalue COLON rvalue
+{
+    @1.last_column = @5.last_column;
+    bool is_64bit = ($3.bit_width == 64) || ($5.bit_width == 64);
+    int bit_width = (is_64bit) ? 64 : 32;
+    if (is_64bit) {
+        $1 = rvalue_extend(c, &@1, &$1);
+        $3 = rvalue_extend(c, &@1, &$3);
+        $5 = rvalue_extend(c, &@1, &$5);
+    } else {
+        $1 = rvalue_truncate(c, &@1, &$1);
+    }
+    $1 = rvalue_materialize(c, &@1, &$1);
+    $3 = rvalue_materialize(c, &@1, &$3);
+    $5 = rvalue_materialize(c, &@1, &$5);
+    HexValue res = gen_local_tmp(c, &@1, bit_width);
+    HexValue zero = gen_tmp_value(c, &@1, "0", bit_width);
+    OUT(c, &@1, "tcg_gen_movcond_i", &bit_width);
+    OUT(c, &@1, "(TCG_COND_NE, ", &res, ", ", &$1, ", ", &zero);
+    OUT(c, &@1, ", ", &$3, ", ", &$5, ");\n");
+    rvalue_free(c, &@1, &zero);
+    rvalue_free(c, &@1, &$1);
+    rvalue_free(c, &@1, &$3);
+    rvalue_free(c, &@1, &$5);
+    $$ = res;
+}
+| FSCR LPAR rvalue RPAR
+{
+    @1.last_column = @4.last_column;
+    HexValue key = gen_tmp(c, &@1, 64);
+    HexValue res = gen_tmp(c, &@1, 64);
+    $3 = rvalue_extend(c, &@1, &$3);
+    HexValue frame_key = gen_tmp(c, &@1, 32);
+    OUT(c, &@1, "READ_REG(", &frame_key, ", HEX_REG_FRAMEKEY);\n");
+    OUT(c, &@1, "tcg_gen_concat_i32_i64(",
+        &key, ", ", &frame_key, ", ", &frame_key, ");\n");
+    OUT(c, &@1, "tcg_gen_xor_i64(", &res, ", ", &$3, ", ", &key, ");\n");
+    rvalue_free(c, &@1, &key);
+    rvalue_free(c, &@1, &frame_key);
+    rvalue_free(c, &@1, &$3);
+    $$ = res;
+}
+| SXT LPAR rvalue COMMA IMM COMMA rvalue RPAR
+{
+    @1.last_column = @8.last_column;
+    yyassert(c, &@1, $5.type == IMMEDIATE &&
+             $5.imm.type == VALUE,
+             "SXT expects immediate values\n");
+    $5.imm.value = 64;
+    $$ = gen_extend_op(c, &@1, &$3, &$5, &$7, false);
+}
+| ZXT LPAR rvalue COMMA IMM COMMA rvalue RPAR
+{
+    @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, &$7, true);
+}
+| LPAR rvalue RPAR
+{
+    $$ = $2;
+}
+| ABS rvalue
+{
+    @1.last_column = @2.last_column;
+    const char *bit_suffix = ($2.bit_width == 64) ? "i64" : "i32";
+    int bit_width = ($2.bit_width == 64) ? 64 : 32;
+    HexValue res;
+    res.is_unsigned = $2.is_unsigned;
+    res.is_dotnew = false;
+    res.is_manual = false;
+    if ($2.type == IMMEDIATE) {
+        res.type = IMMEDIATE;
+        res.imm.type = QEMU_TMP;
+        res.imm.index = c->inst.qemu_tmp_count;
+        OUT(c, &@1, "int", &bit_width, "_t ", &res, " = abs(", &$2, ");\n");
+        c->inst.qemu_tmp_count++;
+        $$ = res;
+    } else {
+        res = gen_tmp(c, &@1, bit_width);
+        HexValue zero = gen_tmp_value(c, &@1, "0", bit_width);
+        OUT(c, &@1, "tcg_gen_neg_", bit_suffix, "(", &res, ", ",
+            &$2, ");\n");
+        OUT(c, &@1, "tcg_gen_movcond_i", &bit_width);
+        OUT(c, &@1, "(TCG_COND_GT, ", &res, ", ", &$2, ", ", &zero);
+        OUT(c, &@1, ", ", &$2, ", ", &res, ");\n");
+        rvalue_free(c, &@1, &zero);
+        rvalue_free(c, &@1, &$2);
+        $$ = res;
+    }
+}
+| CROUND LPAR rvalue COMMA rvalue RPAR
+{
+    @1.last_column = @6.last_column;
+    $$ = gen_convround_n(c, &@1, &$3, &$5);
+}
+| CROUND LPAR rvalue RPAR
+{
+    @1.last_column = @4.last_column;
+    $$ = gen_convround(c, &@1, &$3);
+}
+| ROUND LPAR rvalue COMMA rvalue RPAR
+{
+    @1.last_column = @6.last_column;
+    $$ = gen_round(c, &@1, &$3, &$5);
+}
+| MINUS rvalue
+{
+    @1.last_column = @2.last_column;
+    const char *bit_suffix = ($2.bit_width == 64) ? "i64" : "i32";
+    int bit_width = ($2.bit_width == 64) ? 64 : 32;
+    HexValue res;
+    res.is_unsigned = $2.is_unsigned;
+    res.is_dotnew = false;
+    res.is_manual = false;
+    if ($2.type == IMMEDIATE) {
+        res.type = IMMEDIATE;
+        res.imm.type = QEMU_TMP;
+        res.imm.index = c->inst.qemu_tmp_count;
+        OUT(c, &@1, "int", &bit_width, "_t ", &res, " = -", &$2, ";\n");
+        c->inst.qemu_tmp_count++;
+        $$ = res;
+    } else {
+        res = gen_tmp(c, &@1, bit_width);
+        OUT(c, &@1, "tcg_gen_neg_", bit_suffix, "(", &res, ", ",
+            &$2, ");\n");
+        rvalue_free(c, &@1, &$2);
+        $$ = res;
+    }
+}
+| ICIRC LPAR rvalue RPAR ASL IMM
+{
+    @1.last_column = @6.last_column;
+    $$ = gen_tmp(c, &@1, 32);
+    OUT(c, &@1, "gen_read_ireg(", &$$, ", ", &$3, ", ", &$6, ");\n");
+    rvalue_free(c, &@1, &$3);
+}
+| CIRCADD LPAR rvalue COMMA rvalue COMMA rvalue RPAR
+{
+    @1.last_column = @8.last_column;
+    $$ = gen_circ_op(c, &@1, &$3, &$5, &$7);
+}
+| LOCNT LPAR rvalue RPAR
+{
+    @1.last_column = @4.last_column;
+    /* Leading ones count */
+    $$ = gen_locnt_op(c, &@1, &$3);
+}
+| COUNTONES LPAR rvalue RPAR
+{
+    @1.last_column = @4.last_column;
+    /* Ones count */
+    $$ = gen_ctpop_op(c, &@1, &$3);
+}
+| LPCFG
+{
+    $$ = gen_tmp_value(c, &@1, "0", 32);
+    OUT(c, &@1, "tcg_gen_extract_tl(", &$$, ", hex_gpr[HEX_REG_USR], ");
+    OUT(c, &@1, "reg_field_info[USR_LPCFG].offset, ");
+    OUT(c, &@1, "reg_field_info[USR_LPCFG].width);\n");
+}
+| EXTRACT LPAR rvalue COMMA rvalue RPAR
+{
+    @1.last_column = @6.last_column;
+    $$ = gen_extract_op(c, &@1, &$5, &$3, &$1);
+}
+| EXTBITS LPAR rvalue COMMA rvalue COMMA rvalue RPAR
+{
+    @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);
+}
+| EXTRANGE LPAR rvalue COMMA rvalue COMMA rvalue RPAR
+{
+    @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 LPAR rvalue RPAR
+{
+    @1.last_column = @4.last_column;
+    $$ = rvalue_truncate(c, &@1, &$3);
+    $$.is_unsigned = true;
+    $$ = rvalue_materialize(c, &@1, &$$);
+    $$ = rvalue_extend(c, &@1, &$$);
+}
+| BREV LPAR rvalue RPAR
+{
+    @1.last_column = @4.last_column;
+    yyassert(c, &@1, $3.bit_width <= 32,
+             "fbrev not implemented for 64-bit integers!");
+    HexValue res = gen_tmp(c, &@1, $3.bit_width);
+    $3 = rvalue_materialize(c, &@1, &$3);
+    OUT(c, &@1, "gen_fbrev(", &res, ", ", &$3, ");\n");
+    rvalue_free(c, &@1, &$3);
+    $$ = res;
+}
+| BREV_4 LPAR rvalue RPAR
+{
+    @1.last_column = @4.last_column;
+    $$ = gen_fbrev_4(c, &@1, &$3);
+}
+| BREV_8 LPAR rvalue RPAR
+{
+    @1.last_column = @4.last_column;
+    $$ = gen_fbrev_8(c, &@1, &$3);
+}
+| ROTL LPAR rvalue COMMA rvalue RPAR
+{
+    @1.last_column = @6.last_column;
+    $$ = gen_rotl(c, &@1, &$3, &$5);
+}
+| SETOVF LPAR RPAR
+{
+    @1.last_column = @3.last_column;
+    OUT(c, &@1, "gen_set_usr_fieldi(USR_OVF, 1);\n");
+}
+| SETOVF LPAR rvalue RPAR
+{
+    /* Convenience fSET_OVERFLOW with pass-through */
+    @1.last_column = @3.last_column;
+    OUT(c, &@1, "gen_set_usr_fieldi(USR_OVF, 1);\n");
+    $$ = $3;
+}
+| DEINTERLEAVE LPAR rvalue RPAR
+{
+    @1.last_column = @4.last_column;
+    $$ = gen_deinterleave(c, &@1, &$3);
+}
+| INTERLEAVE LPAR rvalue COMMA rvalue RPAR
+{
+    @1.last_column = @6.last_column;
+    $$ = gen_interleave(c, &@1, &$3, &$5);
+}
+;
+
+pre : PRE
+{
+    $$ = $1;
+}
+| pre NEW
+{
+    $$ = $1;
+    $$.is_dotnew = true;
+}
+;
+
+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_buffer = (char *) calloc(OUT_BUF_LEN, sizeof(char));
+    context.signature_buffer = (char *) calloc(SIGNATURE_BUF_LEN, sizeof(char));
+    context.header_buffer = (char *) calloc(HEADER_BUF_LEN, sizeof(char));
+    /* 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 != 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, "%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);
+    fclose(output_file);
+    fclose(input_file);
+    fclose(defines_file);
+    fclose(enabled_file);
+    free(context.input_buffer);
+    free(context.out_buffer);
+    free(context.signature_buffer);
+
+    return 0;
+}
diff --git a/target/hexagon/idef-parser/parser-helpers.c b/target/hexagon/idef-parser/parser-helpers.c
new file mode 100644
index 0000000000..368c8b4928
--- /dev/null
+++ b/target/hexagon/idef-parser/parser-helpers.c
@@ -0,0 +1,1925 @@ 
+/*
+ * Copyright(c) 2019-2020 rev.ng Srls. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; withOUT even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#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 "idef-parser.h"
+#include "parser-helpers.h"
+#include "idef-parser.tab.h"
+#include "idef-parser.yy.h"
+
+const char *COND_EQ = "TCG_COND_EQ";
+const char *COND_NE = "TCG_COND_NE";
+const char *COND_GT = "TCG_COND_GT";
+const char *COND_LT = "TCG_COND_LT";
+const char *COND_GE = "TCG_COND_GE";
+const char *COND_LE = "TCG_COND_LE";
+const char *COND_GTU = "TCG_COND_GTU";
+const char *COND_LTU = "TCG_COND_LTU";
+const char *COND_GEU = "TCG_COND_GEU";
+const char *COND_LEU = "TCG_COND_LEU";
+
+const char *creg_str[] = {"HEX_REG_SP", "HEX_REG_FP", "HEX_REG_LR",
+                          "HEX_REG_GP", "HEX_REG_LC0", "HEX_REG_LC1",
+                          "HEX_REG_SA0", "HEX_REG_SA1"};
+
+void yyerror(YYLTYPE *locp,
+             yyscan_t scanner __attribute__((unused)),
+             Context *c,
+             const char *s)
+{
+    const char *code_ptr = c->input_buffer;
+
+    fprintf(stderr, "WARNING (%s): '%s'\n", c->inst.name, s);
+
+    fprintf(stderr, "Problematic range: ");
+    for (int i = locp->first_column; i < locp->last_column; i++) {
+        if (code_ptr[i] != '\n') {
+            fprintf(stderr, "%c", code_ptr[i]);
+        }
+    }
+    fprintf(stderr, "\n");
+
+    for (int i = 0;
+         i < 80 &&
+         code_ptr[locp->first_column - 10 + i] != '\0' &&
+         code_ptr[locp->first_column - 10 + i] != '\n';
+         i++) {
+        fprintf(stderr, "%c", code_ptr[locp->first_column - 10 + i]);
+    }
+    fprintf(stderr, "\n");
+    for (int i = 0; i < 9; i++) {
+        fprintf(stderr, " ");
+    }
+    fprintf(stderr, "^");
+    for (int i = 0; i < (locp->last_column - locp->first_column) - 1; i++) {
+        fprintf(stderr, "~");
+    }
+    fprintf(stderr, "\n");
+    c->inst.error_count++;
+}
+
+bool is_direct_predicate(HexValue *value)
+{
+    return value->pre.id >= '0' && value->pre.id <= '3';
+}
+
+/* Print functions */
+void str_print(Context *c, YYLTYPE *locp, char *string)
+{
+    EMIT(c, "%s", string);
+}
+
+
+void uint64_print(Context *c, YYLTYPE *locp, uint64_t *num)
+{
+    EMIT(c, "%" PRIu64, *num);
+}
+
+void int_print(Context *c, YYLTYPE *locp, int *num)
+{
+    EMIT(c, "%d", *num);
+}
+
+void uint_print(Context *c, YYLTYPE *locp, unsigned *num)
+{
+    EMIT(c, "%u", *num);
+}
+
+void tmp_print(Context *c, YYLTYPE *locp, HexTmp *tmp)
+{
+    EMIT(c, "tmp_");
+    EMIT(c, "%d", tmp->index);
+}
+
+void pre_print(Context *c, YYLTYPE *locp, HexPre *pre, bool is_dotnew)
+{
+    char suffix = is_dotnew ? 'N' : 'V';
+    EMIT(c, "P%c%c", pre->id, suffix);
+}
+
+void reg_compose(Context *c, YYLTYPE *locp, HexReg *reg, char reg_id[5])
+{
+    switch (reg->type) {
+    case GENERAL_PURPOSE:
+        reg_id[0] = 'R';
+        break;
+    case CONTROL:
+        reg_id[0] = 'C';
+        break;
+    case MODIFIER:
+        reg_id[0] = 'M';
+        break;
+    case DOTNEW:
+        /* The DOTNEW case is managed by the upper level function */
+        break;
+    }
+    switch (reg->bit_width) {
+    case 32:
+        reg_id[1] = reg->id;
+        reg_id[2] = 'V';
+        break;
+    case 64:
+        reg_id[1] = reg->id;
+        reg_id[2] = reg->id;
+        reg_id[3] = 'V';
+        break;
+    default:
+        yyassert(c, locp, false, "Unhandled register bit width!\n");
+    }
+}
+
+void reg_print(Context *c, YYLTYPE *locp, HexReg *reg)
+{
+  if (reg->type == DOTNEW) {
+    EMIT(c, "N%cN", reg->id);
+  } else {
+    char reg_id[5] = { 0 };
+    reg_compose(c, locp, reg, reg_id);
+    EMIT(c, "%s", reg_id);
+  }
+}
+
+void imm_print(Context *c, YYLTYPE *locp, HexImm *imm)
+{
+    switch (imm->type) {
+    case I:
+        EMIT(c, "i");
+        break;
+    case VARIABLE:
+        EMIT(c, "%ciV", imm->id);
+        break;
+    case VALUE:
+        EMIT(c, "((int64_t)%" PRIu64 "ULL)", (int64_t)imm->value);
+        break;
+    case QEMU_TMP:
+        EMIT(c, "qemu_tmp_%" PRIu64, imm->index);
+        break;
+    case IMM_PC:
+        EMIT(c, "dc->pc");
+        break;
+    case IMM_CONSTEXT:
+        EMIT(c, "insn->extension_valid");
+        break;
+    default:
+        yyassert(c, locp, false, "Cannot print this expression!");
+    }
+}
+
+void var_print(Context *c, YYLTYPE *locp, HexVar *var)
+{
+    EMIT(c, "%s", var->name);
+}
+
+void rvalue_out(Context *c, YYLTYPE *locp, void *pointer)
+{
+  HexValue *rvalue = (HexValue *) pointer;
+  switch (rvalue->type) {
+  case REGISTER:
+      reg_print(c, locp, &rvalue->reg);
+      break;
+  case TEMP:
+      tmp_print(c, locp, &rvalue->tmp);
+      break;
+  case IMMEDIATE:
+      imm_print(c, locp, &rvalue->imm);
+      break;
+  case VARID:
+      var_print(c, locp, &rvalue->var);
+      break;
+  case PREDICATE:
+      pre_print(c, locp, &rvalue->pre, rvalue->is_dotnew);
+      break;
+  default:
+      yyassert(c, locp, false, "Cannot print this expression!");
+  }
+}
+
+/* Copy output code buffer */
+void commit(Context *c)
+{
+    /* Emit instruction pseudocode */
+    EMIT_SIG(c, "\n" START_COMMENT " ");
+    for (char *x = c->inst.code_begin; x < c->inst.code_end; x++) {
+        EMIT_SIG(c, "%c", *x);
+    }
+    EMIT_SIG(c, " " END_COMMENT "\n");
+
+    /* Commit instruction code to output file */
+    fwrite(c->signature_buffer, sizeof(char), c->signature_c, c->output_file);
+    fwrite(c->header_buffer, sizeof(char), c->header_c, c->output_file);
+    fwrite(c->out_buffer, sizeof(char), c->out_c, c->output_file);
+
+    fwrite(c->signature_buffer, sizeof(char), c->signature_c, c->defines_file);
+    fprintf(c->defines_file, ";\n");
+}
+
+const char *cmp_swap(Context *c, YYLTYPE *locp, const char *type)
+{
+    if (type == COND_EQ) {
+        return COND_EQ;
+    } else if (type == COND_NE) {
+        return COND_NE;
+    } else if (type == COND_GT) {
+        return COND_LT;
+    } else if (type == COND_LT) {
+        return COND_GT;
+    } else if (type == COND_GE) {
+        return COND_LE;
+    } else if (type == COND_LE) {
+        return COND_GE;
+    } else if (type == COND_GTU) {
+        return COND_LTU;
+    } else if (type == COND_LTU) {
+        return COND_GTU;
+    } else if (type == COND_GEU) {
+        return COND_LEU;
+    } else if (type == COND_LEU) {
+        return COND_GEU;
+    } else {
+        yyassert(c, locp, false, "Unhandled comparison swap!");
+        return NULL;
+    }
+}
+
+/* Temporary values creation */
+static inline HexValue gen_tmp_impl(Context *c,
+                                    YYLTYPE *locp,
+                                    int bit_width,
+                                    bool is_local)
+{
+    HexValue rvalue;
+    rvalue.type = TEMP;
+    bit_width = (bit_width == 64) ? 64 : 32;
+    rvalue.bit_width = bit_width;
+    rvalue.is_unsigned = false;
+    rvalue.is_dotnew = false;
+    rvalue.is_manual = false;
+    rvalue.tmp.index = c->inst.tmp_count;
+    const char *suffix = is_local ? "local_" : "";
+    OUT(c, locp, "TCGv_i", &bit_width, " tmp_", &c->inst.tmp_count,
+        " = tcg_temp_", suffix, "new_i", &bit_width, "();\n");
+    c->inst.tmp_count++;
+    return rvalue;
+}
+
+HexValue gen_tmp(Context *c, YYLTYPE *locp, int bit_width)
+{
+    return gen_tmp_impl(c, locp, bit_width, false);
+}
+
+HexValue gen_local_tmp(Context *c, YYLTYPE *locp, int bit_width)
+{
+    return gen_tmp_impl(c, locp, bit_width, true);
+}
+
+HexValue gen_tmp_value(Context *c,
+                       YYLTYPE *locp,
+                       const char *value,
+                       int bit_width)
+{
+    HexValue rvalue;
+    rvalue.type = TEMP;
+    rvalue.bit_width = bit_width;
+    rvalue.is_unsigned = false;
+    rvalue.is_dotnew = false;
+    rvalue.is_manual = false;
+    rvalue.tmp.index = c->inst.tmp_count;
+    OUT(c, locp, "TCGv_i", &bit_width, " tmp_", &c->inst.tmp_count,
+        " = tcg_const_i", &bit_width, "(", value, ");\n");
+    c->inst.tmp_count++;
+    return rvalue;
+}
+
+HexValue gen_imm_value(Context *c __attribute__((unused)),
+                       YYLTYPE *locp,
+                       int value,
+                       int bit_width)
+{
+    HexValue rvalue;
+    rvalue.type = IMMEDIATE;
+    rvalue.bit_width = bit_width;
+    rvalue.is_unsigned = false;
+    rvalue.is_dotnew = false;
+    rvalue.is_manual = false;
+    rvalue.imm.type = VALUE;
+    rvalue.imm.value = value;
+    return rvalue;
+}
+
+void rvalue_free(Context *c, YYLTYPE *locp, HexValue *rvalue)
+{
+    if (rvalue->type == TEMP && !rvalue->is_manual) {
+        const char *bit_suffix = (rvalue->bit_width == 64) ? "i64" : "i32";
+        OUT(c, locp, "tcg_temp_free_", bit_suffix, "(", rvalue, ");\n");
+    }
+}
+
+static void rvalue_free_manual(Context *c, YYLTYPE *locp, HexValue *rvalue)
+{
+    rvalue->is_manual = false;
+    rvalue_free(c, locp, rvalue);
+}
+
+static void rvalue_free_ext(Context *c, YYLTYPE *locp, HexValue *rvalue,
+                            bool free_manual) {
+    if (free_manual) {
+        rvalue_free_manual(c, locp, rvalue);
+    } else {
+        rvalue_free(c, locp, rvalue);
+    }
+}
+
+HexValue rvalue_materialize(Context *c, YYLTYPE *locp, HexValue *rvalue)
+{
+    if (rvalue->type == IMMEDIATE) {
+        HexValue tmp = gen_tmp(c, locp, rvalue->bit_width);
+        tmp.is_unsigned = rvalue->is_unsigned;
+        const char *bit_suffix = (rvalue->bit_width == 64) ? "i64" : "i32";
+        OUT(c, locp, "tcg_gen_movi_", bit_suffix,
+            "(", &tmp, ", ", rvalue, ");\n");
+        rvalue_free(c, locp, rvalue);
+        return tmp;
+    }
+    return *rvalue;
+}
+
+HexValue rvalue_extend(Context *c, YYLTYPE *locp, HexValue *rvalue)
+{
+    if (rvalue->type == IMMEDIATE) {
+        HexValue res = *rvalue;
+        res.bit_width = 64;
+        return res;
+    } else {
+        if (rvalue->bit_width == 32) {
+            HexValue res = gen_tmp(c, locp, 64);
+            const char *sign_suffix = (rvalue->is_unsigned) ? "u" : "";
+            OUT(c, locp, "tcg_gen_ext", sign_suffix,
+                "_i32_i64(", &res, ", ", rvalue, ");\n");
+            rvalue_free(c, locp, rvalue);
+            return res;
+        }
+    }
+    return *rvalue;
+}
+
+HexValue rvalue_truncate(Context *c, YYLTYPE *locp, HexValue *rvalue)
+{
+    if (rvalue->type == IMMEDIATE) {
+        HexValue res = *rvalue;
+        res.bit_width = 32;
+        return res;
+    } else {
+        if (rvalue->bit_width == 64) {
+            HexValue res = gen_tmp(c, locp, 32);
+            OUT(c, locp, "tcg_gen_trunc_i64_tl(", &res, ", ", rvalue, ");\n");
+            rvalue_free(c, locp, rvalue);
+            return res;
+        }
+    }
+    return *rvalue;
+}
+
+int find_variable(Context *c, YYLTYPE *locp, HexValue *varid)
+{
+    for (int i = 0; i < c->inst.allocated_count; i++) {
+        if (!strcmp(varid->var.name, c->inst.allocated[i].name)) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+void varid_allocate(Context *c,
+                    YYLTYPE *locp,
+                    HexValue *varid,
+                    int width,
+                    bool is_unsigned)
+{
+    varid->bit_width = width;
+    const char *bit_suffix = width == 64 ? "64" : "32";
+    yyassert(c, locp, c->inst.allocated_count < ALLOC_LIST_LEN,
+             "Too many automatic variables required!");
+    int index = find_variable(c, locp, varid);
+    bool found = index != -1;
+    if (found) {
+        free((char *) varid->var.name);
+        varid->var.name = c->inst.allocated[index].name;
+        varid->bit_width = c->inst.allocated[index].bit_width;
+        varid->is_unsigned = c->inst.allocated[index].is_unsigned;
+    } else {
+        EMIT_HEAD(c, "TCGv_i%s %s", bit_suffix, varid->var.name);
+        EMIT_HEAD(c, " = tcg_temp_local_new_i%s();\n", bit_suffix);
+        c->inst.allocated[c->inst.allocated_count].name = varid->var.name;
+        c->inst.allocated[c->inst.allocated_count].bit_width = width;
+        c->inst.allocated[c->inst.allocated_count].is_unsigned = is_unsigned;
+        c->inst.allocated_count++;
+    }
+}
+
+void ea_free(Context *c, YYLTYPE *locp)
+{
+    OUT(c, locp, "tcg_temp_free(EA);\n");
+}
+
+enum OpTypes {
+    IMM_IMM = 0,
+    IMM_REG = 1,
+    REG_IMM = 2,
+    REG_REG = 3,
+};
+
+HexValue gen_bin_cmp(Context *c,
+                     YYLTYPE *locp,
+                     const char *type,
+                     HexValue *op1_ptr,
+                     HexValue *op2_ptr)
+{
+    HexValue op1 = *op1_ptr;
+    HexValue op2 = *op2_ptr;
+    enum OpTypes op_types = (op1.type != IMMEDIATE) << 1
+                            | (op2.type != IMMEDIATE);
+
+    /* Find bit width of the two operands, if at least one is 64 bit use a */
+    /* 64bit operation, eventually extend 32bit operands. */
+    bool op_is64bit = op1.bit_width == 64 || op2.bit_width == 64;
+    const char *bit_suffix = op_is64bit ? "i64" : "i32";
+    int bit_width = (op_is64bit) ? 64 : 32;
+    if (op_is64bit) {
+        switch (op_types) {
+        case IMM_IMM:
+            break;
+        case IMM_REG:
+            op2 = rvalue_extend(c, locp, &op2);
+            break;
+        case REG_IMM:
+            op1 = rvalue_extend(c, locp, &op1);
+            break;
+        case REG_REG:
+            op1 = rvalue_extend(c, locp, &op1);
+            op2 = rvalue_extend(c, locp, &op2);
+            break;
+        }
+    }
+
+    HexValue res = gen_tmp(c, locp, bit_width);
+
+    switch (op_types) {
+    case IMM_IMM:
+    {
+        OUT(c, locp, "tcg_gen_movi_", bit_suffix,
+            "(", &res, ", ", &op1, " == ", &op2, ");\n");
+        break;
+    }
+    case IMM_REG:
+    {
+        HexValue swp = op2;
+        op2 = op1;
+        op1 = swp;
+        /* Swap comparison direction */
+        type = cmp_swap(c, locp, type);
+    }
+    /* fallthrough */
+    case REG_IMM:
+    {
+        OUT(c, locp, "tcg_gen_setcondi_", bit_suffix, "(");
+        OUT(c, locp, type, ", ", &res, ", ", &op1, ", ", &op2, ");\n");
+        break;
+    }
+    case REG_REG:
+    {
+        OUT(c, locp, "tcg_gen_setcond_", bit_suffix, "(");
+        OUT(c, locp, type, ", ", &res, ", ", &op1, ", ", &op2, ");\n");
+        break;
+    }
+    default:
+    {
+        fprintf(stderr, "Error in evalutating immediateness!");
+        abort();
+    }
+    }
+
+    /* Free operands */
+    rvalue_free(c, locp, &op1);
+    rvalue_free(c, locp, &op2);
+
+    return res;
+}
+
+static void gen_add_op(Context *c, YYLTYPE *locp, unsigned bit_width,
+                       const char *bit_suffix, HexValue *res,
+                       enum OpTypes op_types, HexValue *op1, HexValue *op2)
+{
+    switch (op_types) {
+    case IMM_IMM:
+        OUT(c, locp, "int", &bit_width, "_t ", res,
+            " = ", op1, " + ", op2, ";\n");
+        break;
+    case IMM_REG:
+        OUT(c, locp, "tcg_gen_addi_", bit_suffix,
+            "(", res, ", ", op2, ", ", op1, ");\n");
+        break;
+    case REG_IMM:
+        OUT(c, locp, "tcg_gen_addi_", bit_suffix,
+            "(", res, ", ", op1, ", ", op2, ");\n");
+        break;
+    case REG_REG:
+        OUT(c, locp, "tcg_gen_add_", bit_suffix,
+            "(", res, ", ", op1, ", ", op2, ");\n");
+        break;
+    }
+    rvalue_free(c, locp, op1);
+    rvalue_free(c, locp, op2);
+}
+
+static void gen_sub_op(Context *c, YYLTYPE *locp, unsigned bit_width,
+                       const char *bit_suffix, HexValue *res,
+                       enum OpTypes op_types, HexValue *op1, HexValue *op2)
+{
+    switch (op_types) {
+    case IMM_IMM:
+        OUT(c, locp, "int", &bit_width, "_t ", res,
+            " = ", op1, " - ", op2, ";\n");
+        break;
+    case IMM_REG:
+        OUT(c, locp, "tcg_gen_subfi_", bit_suffix,
+            "(", res, ", ", op1, ", ", op2, ");\n");
+        break;
+    case REG_IMM:
+        OUT(c, locp, "tcg_gen_subi_", bit_suffix,
+            "(", res, ", ", op1, ", ", op2, ");\n");
+        break;
+    case REG_REG:
+        OUT(c, locp, "tcg_gen_sub_", bit_suffix,
+            "(", res, ", ", op1, ", ", op2, ");\n");
+        break;
+    }
+    rvalue_free(c, locp, op1);
+    rvalue_free(c, locp, op2);
+}
+
+static void gen_mul_op(Context *c, YYLTYPE *locp,
+                       const char *bit_suffix, HexValue *res,
+                       enum OpTypes op_types, HexValue *op1, HexValue *op2)
+{
+    switch (op_types) {
+    case IMM_IMM:
+        OUT(c, locp, "int64_t ", res, " = ", op1, " * ", op2, ";\n");
+        break;
+    case IMM_REG:
+        OUT(c, locp, "tcg_gen_muli_", bit_suffix,
+            "(", res, ", ", op2, ", (int64_t)", op1, ");\n");
+        break;
+    case REG_IMM:
+        OUT(c, locp, "tcg_gen_muli_", bit_suffix,
+            "(", res, ", ", op1, ", (int64_t)", op2, ");\n");
+        break;
+    case REG_REG:
+        OUT(c, locp, "tcg_gen_mul_", bit_suffix,
+            "(", res, ", ", op1, ", ", op2, ");\n");
+        break;
+    }
+    rvalue_free(c, locp, op1);
+    rvalue_free(c, locp, op2);
+}
+
+static void gen_div_op(Context *c, YYLTYPE *locp, HexValue *res,
+                       enum OpTypes op_types, HexValue *op1, HexValue *op2)
+{
+    switch (op_types) {
+    case IMM_IMM:
+        OUT(c, locp, "int64_t ", res, " = ", op1, " / ", op2, ";\n");
+        break;
+    case IMM_REG:
+    case REG_IMM:
+    case REG_REG:
+        OUT(c, locp, res, " = gen_helper_divu("
+            "cpu_env, ", op1, ", ", op2, ");\n");
+        break;
+    }
+    rvalue_free(c, locp, op1);
+    rvalue_free(c, locp, op2);
+}
+
+static void gen_asl_op(Context *c, YYLTYPE *locp, unsigned bit_width,
+                       bool op_is64bit, const char *bit_suffix, HexValue *res,
+                       enum OpTypes op_types, HexValue *op1_ptr,
+                       HexValue *op2_ptr)
+{
+    HexValue op1 = *op1_ptr;
+    HexValue op2 = *op2_ptr;
+    switch (op_types) {
+    case IMM_IMM:
+        OUT(c, locp, "int", &bit_width, "_t ", res,
+            " = ", &op1, " << ", &op2, ";\n");
+        break;
+    case REG_IMM:
+        {
+            /* Need to work around assert(op2 < 64) in tcg_gen_shli */
+            if (op_is64bit) {
+                op2 = rvalue_extend(c, locp, &op2);
+            }
+            op2 = rvalue_materialize(c, locp, &op2);
+            const char *mask = op_is64bit ? "0xffffffffffffffc0"
+                                          : "0xffffffc0";
+            HexValue zero = gen_tmp_value(c, locp, "0", bit_width);
+            HexValue tmp = gen_tmp(c, locp, bit_width);
+            OUT(c, locp, "tcg_gen_andi_", bit_suffix,
+                "(", &tmp, ", ", &op2, ", ", mask, ");\n");
+            OUT(c, locp, "tcg_gen_movcond_i", &bit_width);
+            OUT(c, locp, "(TCG_COND_EQ, ", &tmp, ", ", &tmp, ", ", &zero);
+            OUT(c, locp, ", ", &op2, ", ", &zero, ");\n");
+            OUT(c, locp, "tcg_gen_shl_", bit_suffix,
+                "(", res, ", ", &op1, ", ", &tmp, ");\n");
+            rvalue_free(c, locp, &zero);
+            rvalue_free(c, locp, &tmp);
+        }
+        break;
+    case IMM_REG:
+        op1.bit_width = bit_width;
+        op1 = rvalue_materialize(c, locp, &op1);
+        /* Fallthrough */
+    case REG_REG:
+        OUT(c, locp, "tcg_gen_shl_", bit_suffix,
+            "(", res, ", ", &op1, ", ", &op2, ");\n");
+        break;
+    }
+    if (op_types != IMM_IMM) {
+        /* Handle left shift by 64 which hexagon-sim expects to clear out */
+        /* register */
+        HexValue edge = gen_tmp_value(c, locp, "64", bit_width);
+        HexValue zero = gen_tmp_value(c, locp, "0", bit_width);
+        if (op_is64bit) {
+            op2 = rvalue_extend(c, locp, &op2);
+        }
+        op1 = rvalue_materialize(c, locp, &op1);
+        op2 = rvalue_materialize(c, locp, &op2);
+        OUT(c, locp, "tcg_gen_movcond_i", &bit_width);
+        if (op_types == REG_REG || op_types == IMM_REG) {
+            OUT(c, locp, "(TCG_COND_EQ, ", res, ", ", &op2, ", ", &edge);
+        } else {
+            OUT(c, locp, "(TCG_COND_EQ, ", res, ", ", &op2, ", ", &edge);
+        }
+        OUT(c, locp, ", ", &zero, ", ", res, ");\n");
+        rvalue_free(c, locp, &edge);
+        rvalue_free(c, locp, &zero);
+    }
+    rvalue_free(c, locp, &op1);
+    rvalue_free(c, locp, &op2);
+}
+
+static void gen_asr_op(Context *c, YYLTYPE *locp, unsigned bit_width,
+                       const char *bit_suffix, HexValue *res,
+                       enum OpTypes op_types, HexValue *op1, HexValue *op2)
+{
+    switch (op_types) {
+    case IMM_IMM:
+        OUT(c, locp, "int", &bit_width, "_t ", res,
+            " = ", op1, " >> ", op2, ";\n");
+        break;
+    case REG_IMM:
+        OUT(c, locp, "tcg_gen_sari_", bit_suffix,
+            "(", res, ", ", op1, ", ", op2, ");\n");
+        break;
+    case IMM_REG:
+        rvalue_materialize(c, locp, op1);
+        /* Fallthrough */
+    case REG_REG:
+        OUT(c, locp, "tcg_gen_sar_", bit_suffix,
+            "(", res, ", ", op1, ", ", op2, ");\n");
+        break;
+    }
+    rvalue_free(c, locp, op1);
+    rvalue_free(c, locp, op2);
+}
+
+static void gen_lsr_op(Context *c, YYLTYPE *locp, unsigned bit_width,
+                       const char *bit_suffix, HexValue *res,
+                       enum OpTypes op_types, HexValue *op1_ptr, HexValue *op2)
+{
+    HexValue op1 = *op1_ptr;
+    switch (op_types) {
+    case IMM_IMM:
+        OUT(c, locp, "int", &bit_width, "_t ",
+            res, " = ", &op1, " >> ", op2, ";\n");
+        break;
+    case REG_IMM:
+        OUT(c, locp, "tcg_gen_shri_", bit_suffix,
+            "(", res, ", ", &op1, ", ", op2, ");\n");
+        break;
+    case IMM_REG:
+        op1 = rvalue_materialize(c, locp, &op1);
+        /* Fallthrough */
+    case REG_REG:
+        OUT(c, locp, "tcg_gen_shr_", bit_suffix,
+            "(", res, ", ", &op1, ", ", op2, ");\n");
+        break;
+    }
+    rvalue_free(c, locp, &op1);
+    rvalue_free(c, locp, op2);
+}
+
+static void gen_andb_op(Context *c, YYLTYPE *locp, unsigned bit_width,
+                        const char *bit_suffix, HexValue *res,
+                        enum OpTypes op_types, HexValue *op1, HexValue *op2)
+{
+    switch (op_types) {
+    case IMM_IMM:
+        OUT(c, locp, "int", &bit_width, "_t ",
+            res, " = ", op1, " & ", op2, ";\n");
+        break;
+    case IMM_REG:
+        OUT(c, locp, "tcg_gen_andi_", bit_suffix,
+            "(", res, ", ", op2, ", ", op1, ");\n");
+        break;
+    case REG_IMM:
+        OUT(c, locp, "tcg_gen_andi_", bit_suffix,
+            "(", res, ", ", op1, ", ", op2, ");\n");
+        break;
+    case REG_REG:
+        OUT(c, locp, "tcg_gen_and_", bit_suffix,
+            "(", res, ", ", op1, ", ", op2, ");\n");
+        break;
+    }
+    rvalue_free(c, locp, op1);
+    rvalue_free(c, locp, op2);
+}
+
+static void gen_orb_op(Context *c, YYLTYPE *locp, unsigned bit_width,
+                       const char *bit_suffix, HexValue *res,
+                       enum OpTypes op_types, HexValue *op1, HexValue *op2)
+{
+    switch (op_types) {
+    case IMM_IMM:
+        OUT(c, locp, "int", &bit_width, "_t ",
+            res, " = ", op1, " & ", op2, ";\n");
+        break;
+    case IMM_REG:
+        OUT(c, locp, "tcg_gen_ori_", bit_suffix,
+            "(", res, ", ", op2, ", ", op1, ");\n");
+        break;
+    case REG_IMM:
+        OUT(c, locp, "tcg_gen_ori_", bit_suffix,
+            "(", res, ", ", op1, ", ", op2, ");\n");
+        break;
+    case REG_REG:
+        OUT(c, locp, "tcg_gen_or_", bit_suffix,
+            "(", res, ", ", op1, ", ", op2, ");\n");
+        break;
+    }
+    rvalue_free(c, locp, op1);
+    rvalue_free(c, locp, op2);
+}
+
+static void gen_xorb_op(Context *c, YYLTYPE *locp, unsigned bit_width,
+                        const char *bit_suffix, HexValue *res,
+                        enum OpTypes op_types, HexValue *op1, HexValue *op2)
+{
+    switch (op_types) {
+    case IMM_IMM:
+        OUT(c, locp, "int", &bit_width, "_t ",
+            res, " = ", op1, " & ", op2, ";\n");
+        break;
+    case IMM_REG:
+        OUT(c, locp, "tcg_gen_xori_", bit_suffix,
+            "(", res, ", ", op2, ", ", op1, ");\n");
+        break;
+    case REG_IMM:
+        OUT(c, locp, "tcg_gen_xori_", bit_suffix,
+            "(", res, ", ", op1, ", ", op2, ");\n");
+        break;
+    case REG_REG:
+        OUT(c, locp, "tcg_gen_xor_", bit_suffix,
+            "(", res, ", ", op1, ", ", op2, ");\n");
+        break;
+    }
+    rvalue_free(c, locp, op1);
+    rvalue_free(c, locp, op2);
+}
+
+static void gen_andl_op(Context *c, YYLTYPE *locp, unsigned bit_width,
+                        const char *bit_suffix, HexValue *res,
+                        enum OpTypes op_types, HexValue *op1, HexValue *op2)
+{
+    HexValue zero, tmp1, tmp2;
+    switch (op_types) {
+    case IMM_IMM:
+        OUT(c, locp, "int", &bit_width, "_t ",
+            res, " = ", op1, " && ", op2, ";\n");
+        break;
+    case IMM_REG:
+        zero = gen_tmp_value(c, locp, "0", 32);
+        tmp2 = gen_bin_cmp(c, locp, "TCG_COND_NE", op2, &zero);
+        OUT(c, locp, "tcg_gen_andi_", bit_suffix,
+            "(", res, ", ", op1, " != 0 , ", &tmp2, ");\n");
+        rvalue_free(c, locp, &tmp2);
+        break;
+    case REG_IMM:
+        zero = gen_tmp_value(c, locp, "0", 32);
+        tmp1 = gen_bin_cmp(c, locp, "TCG_COND_NE", op1, &zero);
+        OUT(c, locp, "tcg_gen_andi_", bit_suffix,
+            "(", res, ", ", &tmp1, ", ", op2, " != 0);\n");
+        rvalue_free(c, locp, &tmp1);
+        break;
+    case REG_REG:
+        zero = gen_tmp_value(c, locp, "0", 32);
+        zero.is_manual = true;
+        tmp1 = gen_bin_cmp(c, locp, "TCG_COND_NE", op1, &zero);
+        tmp2 = gen_bin_cmp(c, locp, "TCG_COND_NE", op2, &zero);
+        OUT(c, locp, "tcg_gen_and_", bit_suffix,
+            "(", res, ", ", &tmp1, ", ", &tmp2, ");\n");
+        rvalue_free_manual(c, locp, &zero);
+        rvalue_free(c, locp, &tmp1);
+        rvalue_free(c, locp, &tmp2);
+        break;
+    }
+}
+
+static void gen_mini_op(Context *c, YYLTYPE *locp, unsigned bit_width,
+                        HexValue *res, enum OpTypes op_types,
+                        HexValue *op1_ptr, HexValue *op2_ptr)
+{
+    HexValue op1 = *op1_ptr;
+    HexValue op2 = *op2_ptr;
+    const char *comparison = res->is_unsigned
+                             ? "TCG_COND_LEU"
+                             : "TCG_COND_LE";
+    switch (op_types) {
+    case IMM_IMM:
+        OUT(c, locp, "int", &bit_width, "_t ", res, " = (", &op1, " <= ");
+        OUT(c, locp, &op2, ") ? ", &op1, " : ", &op2, ";\n");
+        break;
+    case IMM_REG:
+        op1.bit_width = bit_width;
+        op1 = rvalue_materialize(c, locp, &op1);
+        OUT(c, locp, "tcg_gen_movcond_i", &bit_width);
+        OUT(c, locp, "(", comparison, ", ", res, ", ", &op1, ", ", &op2);
+        OUT(c, locp, ", ", &op1, ", ", &op2, ");\n");
+        break;
+    case REG_IMM:
+        op2.bit_width = bit_width;
+        op2 = rvalue_materialize(c, locp, &op2);
+        /* Fallthrough */
+    case REG_REG:
+        OUT(c, locp, "tcg_gen_movcond_i", &bit_width);
+        OUT(c, locp, "(", comparison, ", ", res, ", ", &op1, ", ", &op2);
+        OUT(c, locp, ", ", &op1, ", ", &op2, ");\n");
+        break;
+    }
+    rvalue_free(c, locp, &op1);
+    rvalue_free(c, locp, &op2);
+}
+
+static void gen_maxi_op(Context *c, YYLTYPE *locp, unsigned bit_width,
+                        HexValue *res, enum OpTypes op_types,
+                        HexValue *op1_ptr, HexValue *op2_ptr)
+{
+    HexValue op1 = *op1_ptr;
+    HexValue op2 = *op2_ptr;
+    const char *comparison = res->is_unsigned
+                             ? "TCG_COND_LEU"
+                             : "TCG_COND_LE";
+    switch (op_types) {
+    case IMM_IMM:
+        OUT(c, locp, "int", &bit_width, "_t ", res, " = (", &op1, " <= ");
+        OUT(c, locp, &op2, ") ? ", &op2, " : ", &op1, ";\n");
+        break;
+    case IMM_REG:
+        op1.bit_width = bit_width;
+        op1 = rvalue_materialize(c, locp, &op1);
+        OUT(c, locp, "tcg_gen_movcond_i", &bit_width);
+        OUT(c, locp, "(", comparison, ", ", res, ", ", &op1, ", ", &op2);
+        OUT(c, locp, ", ", &op2, ", ", &op1, ");\n");
+        break;
+    case REG_IMM:
+        op2.bit_width = bit_width;
+        op2 = rvalue_materialize(c, locp, &op2);
+        /* Fallthrough */
+    case REG_REG:
+        OUT(c, locp, "tcg_gen_movcond_i", &bit_width);
+        OUT(c, locp, "(", comparison, ", ", res, ", ", &op1, ", ", &op2);
+        OUT(c, locp, ", ", &op2, ", ", &op1, ");\n");
+        break;
+    }
+    rvalue_free(c, locp, &op1);
+    rvalue_free(c, locp, &op2);
+}
+
+static void gen_mod_op(Context *c, YYLTYPE *locp, HexValue *res,
+                       enum OpTypes op_types, HexValue *op1, HexValue *op2)
+{
+    switch (op_types) {
+    case IMM_IMM:
+        OUT(c, locp, "int64_t ", res, " = ", op1, " % ", op2, ";\n");
+        break;
+    case IMM_REG:
+    case REG_IMM:
+    case REG_REG:
+        OUT(c, locp, "gen_helper_mod(",
+            res, ", ", op1, ", ", op2, ");\n");
+        break;
+    }
+    rvalue_free(c, locp, op1);
+    rvalue_free(c, locp, op2);
+}
+
+/* Code generation functions */
+HexValue gen_bin_op(Context *c,
+                    YYLTYPE *locp,
+                    enum OpType type,
+                    HexValue *operand1,
+                    HexValue *operand2)
+{
+    /* Replicate operands to avoid side effects */
+    HexValue op1 = *operand1;
+    HexValue op2 = *operand2;
+
+    /* Enforce variables' size */
+    if (op1.type == VARID) {
+        int index = find_variable(c, locp, &op1);
+        yyassert(c, locp, index >= 0, "Variable in bin_op must exist!\n");
+        op1.bit_width = c->inst.allocated[index].bit_width;
+    }
+    if (op2.type == VARID) {
+        int index = find_variable(c, locp, &op2);
+        yyassert(c, locp, index >= 0, "Variable in bin_op must exist!\n");
+        op2.bit_width = c->inst.allocated[index].bit_width;
+    }
+
+    enum OpTypes op_types = (op1.type != IMMEDIATE) << 1
+                            | (op2.type != IMMEDIATE);
+
+    /* Find bit width of the two operands, if at least one is 64 bit use a */
+    /* 64bit operation, eventually extend 32bit operands. */
+    bool op_is64bit = op1.bit_width == 64 || op2.bit_width == 64;
+    /* Shift greater than 32 are 64 bits wide */
+    if (type == ASL_OP && op2.type == IMMEDIATE &&
+        op2.imm.type == VALUE && op2.imm.value >= 32)
+        op_is64bit = true;
+    const char *bit_suffix = op_is64bit ? "i64" : "i32";
+    int bit_width = (op_is64bit) ? 64 : 32;
+    /* Handle bit width */
+    if (op_is64bit) {
+        switch (op_types) {
+        case IMM_IMM:
+            break;
+        case IMM_REG:
+            op2 = rvalue_extend(c, locp, &op2);
+            break;
+        case REG_IMM:
+            op1 = rvalue_extend(c, locp, &op1);
+            break;
+        case REG_REG:
+            op1 = rvalue_extend(c, locp, &op1);
+            op2 = rvalue_extend(c, locp, &op2);
+            break;
+        }
+    }
+    HexValue res;
+    if (op_types != IMM_IMM) {
+        res = gen_tmp(c, locp, bit_width);
+    } else {
+        res.type = IMMEDIATE;
+        res.is_dotnew = false;
+        res.is_manual = false;
+        res.imm.type = QEMU_TMP;
+        res.imm.index = c->inst.qemu_tmp_count;
+        res.bit_width = bit_width;
+    }
+    /* Handle signedness, if both unsigned -> result is unsigned, else signed */
+    res.is_unsigned = op1.is_unsigned && op2.is_unsigned;
+
+    switch (type) {
+    case ADD_OP:
+        gen_add_op(c, locp, bit_width, bit_suffix, &res, op_types, &op1, &op2);
+        break;
+    case SUB_OP:
+        gen_sub_op(c, locp, bit_width, bit_suffix, &res, op_types, &op1, &op2);
+        break;
+    case MUL_OP:
+        gen_mul_op(c, locp, bit_suffix, &res, op_types, &op1, &op2);
+        break;
+    case DIV_OP:
+        gen_div_op(c, locp, &res, op_types, &op1, &op2);
+        break;
+    case ASL_OP:
+        gen_asl_op(c, locp, bit_width, op_is64bit, bit_suffix, &res, op_types,
+                   &op1, &op2);
+        break;
+    case ASR_OP:
+        gen_asr_op(c, locp, bit_width, bit_suffix, &res, op_types, &op1, &op2);
+        break;
+    case LSR_OP:
+        gen_lsr_op(c, locp, bit_width, bit_suffix, &res, op_types, &op1, &op2);
+        break;
+    case ANDB_OP:
+        gen_andb_op(c, locp, bit_width, bit_suffix, &res, op_types, &op1, &op2);
+        break;
+    case ORB_OP:
+        gen_orb_op(c, locp, bit_width, bit_suffix, &res, op_types, &op1, &op2);
+        break;
+    case XORB_OP:
+        gen_xorb_op(c, locp, bit_width, bit_suffix, &res, op_types, &op1, &op2);
+        break;
+    case ANDL_OP:
+        gen_andl_op(c, locp, bit_width, bit_suffix, &res, op_types, &op1, &op2);
+        break;
+    case MINI_OP:
+        gen_mini_op(c, locp, bit_width, &res, op_types, &op1, &op2);
+        break;
+    case MAXI_OP:
+        gen_maxi_op(c, locp, bit_width, &res, op_types, &op1, &op2);
+        break;
+    case MOD_OP:
+        gen_mod_op(c, locp, &res, op_types, &op1, &op2);
+        break;
+    }
+    if (op_types == IMM_IMM) {
+        c->inst.qemu_tmp_count++;
+    }
+    return res;
+}
+
+HexValue gen_cast_op(Context *c,
+                     YYLTYPE *locp,
+                     HexValue *source,
+                     unsigned target_width) {
+    if (source->bit_width == target_width) {
+        return *source;
+    } else if (source->type == IMMEDIATE) {
+        HexValue res = *source;
+        res.bit_width = target_width;
+        return res;
+    } else {
+        HexValue res = gen_tmp(c, locp, target_width);
+        /* Truncate */
+        if (source->bit_width > target_width) {
+            OUT(c, locp, "tcg_gen_trunc_i64_tl(", &res, ", ", source, ");\n");
+        } else {
+            if (source->is_unsigned) {
+                /* Extend unsigned */
+                OUT(c, locp, "tcg_gen_extu_i32_i64(",
+                    &res, ", ", source, ");\n");
+            } else {
+                /* Extend signed */
+                OUT(c, locp, "tcg_gen_ext_i32_i64(",
+                    &res, ", ", source, ");\n");
+            }
+        }
+        rvalue_free(c, locp, source);
+        return res;
+    }
+}
+
+HexValue gen_extend_op(Context *c,
+                       YYLTYPE *locp,
+                       HexValue *src_width_ptr,
+                       HexValue *dst_width_ptr,
+                       HexValue *value_ptr,
+                       bool is_unsigned) {
+    HexValue src_width = *src_width_ptr;
+    HexValue dst_width = *dst_width_ptr;
+    HexValue value = *value_ptr;
+    src_width = rvalue_extend(c, locp, &src_width);
+    value = rvalue_extend(c, locp, &value);
+    src_width = rvalue_materialize(c, locp, &src_width);
+    value = rvalue_materialize(c, locp, &value);
+
+    HexValue res = gen_tmp(c, locp, 64);
+    HexValue shift = gen_tmp_value(c, locp, "64", 64);
+    HexValue zero = gen_tmp_value(c, locp, "0", 64);
+    OUT(c, locp, "tcg_gen_sub_i64(",
+        &shift, ", ", &shift, ", ", &src_width, ");\n");
+    if (is_unsigned) {
+        HexValue mask = gen_tmp_value(c, locp, "0xffffffffffffffff", 64);
+        OUT(c, locp, "tcg_gen_shr_i64(",
+            &mask, ", ", &mask, ", ", &shift, ");\n");
+        OUT(c, locp, "tcg_gen_and_i64(",
+            &res, ", ", &value, ", ", &mask, ");\n");
+        rvalue_free(c, locp, &mask);
+    } else {
+        OUT(c, locp, "tcg_gen_shl_i64(",
+            &res, ", ", &value, ", ", &shift, ");\n");
+        OUT(c, locp, "tcg_gen_sar_i64(",
+            &res, ", ", &res, ", ", &shift, ");\n");
+    }
+    OUT(c, locp, "tcg_gen_movcond_i64(", COND_EQ, ", ", &res, ", ");
+    OUT(c, locp, &src_width, ", ", &zero, ", ", &zero, ", ", &res, ");\n");
+
+    rvalue_free(c, locp, &src_width);
+    rvalue_free(c, locp, &dst_width);
+    rvalue_free(c, locp, &value);
+    rvalue_free(c, locp, &shift);
+    rvalue_free(c, locp, &zero);
+
+    res.is_unsigned = is_unsigned;
+    return res;
+}
+
+void gen_rdeposit_op(Context *c,
+                     YYLTYPE *locp,
+                     HexValue *dest,
+                     HexValue *value,
+                     HexValue *begin,
+                     HexValue *width)
+{
+    HexValue dest_m = *dest;
+    dest_m.is_manual = true;
+
+    HexValue value_m = rvalue_extend(c, locp, value);
+    HexValue begin_m = rvalue_extend(c, locp, begin);
+    HexValue width_orig = *width;
+    width_orig.is_manual = true;
+    HexValue width_m = rvalue_extend(c, locp, &width_orig);
+    width_m = rvalue_materialize(c, locp, &width_m);
+
+    HexValue mask = gen_tmp_value(c, locp, "0xffffffffffffffffUL", 64);
+    mask.is_unsigned = true;
+    HexValue k64 = gen_tmp_value(c, locp, "64", 64);
+    k64 = gen_bin_op(c, locp, SUB_OP, &k64, &width_m);
+    mask = gen_bin_op(c, locp, LSR_OP, &mask, &k64);
+    begin_m.is_manual = true;
+    mask = gen_bin_op(c, locp, ASL_OP, &mask, &begin_m);
+    mask.is_manual = true;
+    value_m = gen_bin_op(c, locp, ASL_OP, &value_m, &begin_m);
+    value_m = gen_bin_op(c, locp, ANDB_OP, &value_m, &mask);
+
+    OUT(c, locp, "tcg_gen_not_i64(", &mask, ", ", &mask, ");\n");
+    mask.is_manual = false;
+    HexValue res = gen_bin_op(c, locp, ANDB_OP, &dest_m, &mask);
+    res = gen_bin_op(c, locp, ORB_OP, &res, &value_m);
+
+    if (dest->bit_width != res.bit_width) {
+        res = rvalue_truncate(c, locp, &res);
+    }
+
+    HexValue zero = gen_tmp_value(c, locp, "0", res.bit_width);
+    OUT(c, locp, "tcg_gen_movcond_i", &res.bit_width, "(TCG_COND_NE, ", dest);
+    OUT(c, locp, ", ", &width_orig, ", ", &zero, ", ", &res, ", ", dest,
+        ");\n");
+
+    rvalue_free(c, locp, &zero);
+    rvalue_free(c, locp, width);
+    rvalue_free(c, locp, &res);
+}
+
+void gen_deposit_op(Context *c,
+                    YYLTYPE *locp,
+                    HexValue *dest,
+                    HexValue *value,
+                    HexValue *index,
+                    HexCast *cast)
+{
+    yyassert(c, locp, index->type == IMMEDIATE,
+             "Deposit index must be immediate!\n");
+    HexValue value_m = *value;
+    int bit_width = (dest->bit_width == 64) ? 64 : 32;
+    int width = cast->bit_width;
+    /* If the destination value is 32, truncate the value, otherwise extend */
+    if (dest->bit_width != value->bit_width) {
+        if (bit_width == 32) {
+            value_m = rvalue_truncate(c, locp, &value_m);
+        } else {
+            value_m = rvalue_extend(c, locp, &value_m);
+        }
+    }
+    value_m = rvalue_materialize(c, locp, &value_m);
+    OUT(c, locp, "tcg_gen_deposit_i", &bit_width, "(", dest, ", ", dest, ", ");
+    OUT(c, locp, &value_m, ", ", index, " * ", &width, ", ", &width, ");\n");
+    rvalue_free(c, locp, index);
+    rvalue_free(c, locp, &value_m);
+}
+
+HexValue gen_rextract_op(Context *c,
+                         YYLTYPE *locp,
+                         HexValue *source,
+                         int begin,
+                         int width) {
+    int bit_width = (source->bit_width == 64) ? 64 : 32;
+    HexValue res = gen_tmp(c, locp, bit_width);
+    OUT(c, locp, "tcg_gen_extract_i", &bit_width, "(", &res);
+    OUT(c, locp, ", ", source, ", ", &begin, ", ", &width, ");\n");
+    rvalue_free(c, locp, source);
+    return res;
+}
+
+HexValue gen_extract_op(Context *c,
+                        YYLTYPE *locp,
+                        HexValue *source,
+                        HexValue *index,
+                        HexExtract *extract) {
+    yyassert(c, locp, index->type == IMMEDIATE,
+             "Extract index must be immediate!\n");
+    int bit_width = (source->bit_width == 64) ? 64 : 32;
+    const char *sign_prefix = (extract->is_unsigned) ? "" : "s";
+    int width = extract->bit_width;
+    HexValue res = gen_tmp(c, locp, bit_width);
+    res.is_unsigned = extract->is_unsigned;
+    OUT(c, locp, "tcg_gen_", sign_prefix, "extract_i", &bit_width,
+        "(", &res, ", ", source);
+    OUT(c, locp, ", ", index, " * ", &width, ", ", &width, ");\n");
+
+    /* Some extract operations have bit_width != storage_bit_width */
+    if (extract->storage_bit_width > bit_width) {
+        HexValue tmp = gen_tmp(c, locp, extract->storage_bit_width);
+        tmp.is_unsigned = extract->is_unsigned;
+        if (extract->is_unsigned) {
+            /* Extend unsigned */
+            OUT(c, locp, "tcg_gen_extu_i32_i64(",
+                &tmp, ", ", &res, ");\n");
+        } else {
+            /* Extend signed */
+            OUT(c, locp, "tcg_gen_ext_i32_i64(",
+                &tmp, ", ", &res, ");\n");
+        }
+        rvalue_free(c, locp, &res);
+        res = tmp;
+    }
+
+    rvalue_free(c, locp, source);
+    rvalue_free(c, locp, index);
+    return res;
+}
+
+HexValue gen_read_creg(Context *c, YYLTYPE *locp, HexValue *reg)
+{
+    yyassert(c, locp, reg->type == REGISTER, "reg must be a register!");
+    if (reg->reg.id < 'a') {
+        HexValue tmp = gen_tmp_value(c, locp, "0", 32);
+        const char *id = creg_str[(uint8_t)reg->reg.id];
+        OUT(c, locp, "READ_REG(", &tmp, ", ", id, ");\n");
+        rvalue_free(c, locp, reg);
+        return tmp;
+    }
+    return *reg;
+}
+
+void gen_write_creg(Context *c,
+                    YYLTYPE *locp,
+                    HexValue *reg,
+                    HexValue *value)
+{
+    yyassert(c, locp, reg->type == REGISTER, "reg must be a register!");
+    HexValue value_m = *value;
+    value_m = rvalue_truncate(c, locp, &value_m);
+    value_m = rvalue_materialize(c, locp, &value_m);
+    OUT(c,
+        locp,
+        "gen_log_reg_write(", creg_str[(uint8_t)reg->reg.id], ", ",
+        &value_m, ");\n");
+    OUT(c,
+        locp,
+        "ctx_log_reg_write(ctx, ", creg_str[(uint8_t)reg->reg.id], ");\n");
+    rvalue_free(c, locp, reg);
+    rvalue_free(c, locp, &value_m);
+}
+
+void gen_assign(Context *c,
+                YYLTYPE *locp,
+                HexValue *dest,
+                HexValue *value)
+{
+    HexValue value_m = *value;
+    if (dest->type == REGISTER &&
+        dest->reg.type == CONTROL && dest->reg.id < 'a') {
+        gen_write_creg(c, locp, dest, &value_m);
+        return;
+    }
+    /* Create (if not present) and assign to temporary variable */
+    if (dest->type == VARID) {
+        varid_allocate(c, locp, dest, value_m.bit_width, value_m.is_unsigned);
+    }
+    int bit_width = dest->bit_width == 64 ? 64 : 32;
+    if (bit_width != value_m.bit_width) {
+        if (bit_width == 64) {
+            value_m = rvalue_extend(c, locp, &value_m);
+        } else {
+            value_m = rvalue_truncate(c, locp, &value_m);
+        }
+    }
+    value_m = rvalue_materialize(c, locp, &value_m);
+    if (value_m.type == IMMEDIATE) {
+        OUT(c, locp, "tcg_gen_movi_i", &bit_width,
+            "(", dest, ", ", &value_m, ");\n");
+    } else {
+        OUT(c, locp, "tcg_gen_mov_i", &bit_width,
+            "(", dest, ", ", &value_m, ");\n");
+    }
+    rvalue_free(c, locp, &value_m);
+}
+
+HexValue gen_convround(Context *c,
+                       YYLTYPE *locp,
+                       HexValue *source)
+{
+    HexValue src = *source;
+    src.is_manual = true;
+
+    unsigned bit_width = src.bit_width;
+    const char *size = (bit_width == 32) ? "32" : "64";
+    HexValue res = gen_tmp(c, locp, bit_width);
+    HexValue mask = gen_tmp_value(c, locp, "0x3", bit_width);
+    mask.is_manual = true;
+    HexValue and = gen_bin_op(c, locp, ANDB_OP, &src, &mask);
+    HexValue one = gen_tmp_value(c, locp, "1", bit_width);
+    HexValue src_p1 = gen_bin_op(c, locp, ADD_OP, &src, &one);
+
+    OUT(c, locp, "tcg_gen_movcond_i", size, "(TCG_COND_EQ, ", &res);
+    OUT(c, locp, ", ", &and, ", ", &mask, ", ");
+    OUT(c, locp, &src_p1, ", ", &src, ");\n");
+
+    /* Free src but use the original `is_manual` value */
+    rvalue_free(c, locp, source);
+
+    /* Free the rest of the values */
+    rvalue_free_manual(c, locp, &mask);
+    rvalue_free(c, locp, &and);
+    rvalue_free(c, locp, &src_p1);
+
+    return res;
+}
+
+static HexValue gen_convround_n_a(Context *c,
+                                  YYLTYPE *locp,
+                                  HexValue *a,
+                                  HexValue *n)
+{
+    HexValue res = gen_tmp(c, locp, 64);
+    OUT(c, locp, "tcg_gen_ext_i32_i64(", &res, ", ", a, ");\n");
+    rvalue_free(c, locp, a);
+    rvalue_free(c, locp, n);
+    return res;
+}
+
+static HexValue gen_convround_n_b(Context *c,
+                                  YYLTYPE *locp,
+                                  HexValue *a,
+                                  HexValue *n)
+{
+    HexValue res = gen_tmp(c, locp, 64);
+    OUT(c, locp, "tcg_gen_ext_i32_i64(", &res, ", ", a, ");\n");
+
+    HexValue one = gen_tmp_value(c, locp, "1", 32);
+    HexValue tmp = gen_tmp(c, locp, 32);
+    HexValue tmp_64 = gen_tmp(c, locp, 64);
+
+    OUT(c, locp, "tcg_gen_shl_i32(", &tmp);
+    OUT(c, locp, ", ", &one, ", ", n, ");\n");
+    OUT(c, locp, "tcg_gen_and_i32(", &tmp);
+    OUT(c, locp, ", ", &tmp, ", ", a, ");\n");
+    OUT(c, locp, "tcg_gen_shri_i32(", &tmp);
+    OUT(c, locp, ", ", &tmp, ", 1);\n");
+    OUT(c, locp, "tcg_gen_ext_i32_i64(", &tmp_64, ", ", &tmp, ");\n");
+    OUT(c, locp, "tcg_gen_add_i64(", &res);
+    OUT(c, locp, ", ", &res, ", ", &tmp_64, ");\n");
+
+    rvalue_free(c, locp, a);
+    rvalue_free(c, locp, n);
+    rvalue_free(c, locp, &one);
+    rvalue_free(c, locp, &tmp);
+    rvalue_free(c, locp, &tmp_64);
+
+    return res;
+}
+
+static HexValue gen_convround_n_c(Context *c,
+                                  YYLTYPE *locp,
+                                  HexValue *a,
+                                  HexValue *n)
+{
+    HexValue res = gen_tmp(c, locp, 64);
+    OUT(c, locp, "tcg_gen_ext_i32_i64(", &res, ", ", a, ");\n");
+
+    HexValue one = gen_tmp_value(c, locp, "1", 32);
+    HexValue tmp = gen_tmp(c, locp, 32);
+    HexValue tmp_64 = gen_tmp(c, locp, 64);
+
+    OUT(c, locp, "tcg_gen_subi_i32(", &tmp);
+    OUT(c, locp, ", ", n, ", 1);\n");
+    OUT(c, locp, "tcg_gen_shl_i32(", &tmp);
+    OUT(c, locp, ", ", &one, ", ", &tmp, ");\n");
+    OUT(c, locp, "tcg_gen_ext_i32_i64(", &tmp_64, ", ", &tmp, ");\n");
+    OUT(c, locp, "tcg_gen_add_i64(", &res);
+    OUT(c, locp, ", ", &res, ", ", &tmp_64, ");\n");
+
+    rvalue_free(c, locp, a);
+    rvalue_free(c, locp, n);
+    rvalue_free(c, locp, &one);
+    rvalue_free(c, locp, &tmp);
+    rvalue_free(c, locp, &tmp_64);
+
+    return res;
+}
+
+HexValue gen_convround_n(Context *c,
+                         YYLTYPE *locp,
+                         HexValue *source_ptr,
+                         HexValue *bit_pos_ptr)
+{
+    /* If input is 64 bit cast it to 32 */
+    HexValue source = gen_cast_op(c, locp, source_ptr, 32);
+    HexValue bit_pos = gen_cast_op(c, locp, bit_pos_ptr, 32);
+
+    source = rvalue_materialize(c, locp, &source);
+    bit_pos = rvalue_materialize(c, locp, &bit_pos);
+
+    bool free_source_sym = !rvalue_equal(&source, source_ptr);
+    bool free_bit_pos_sym = !rvalue_equal(&bit_pos, bit_pos_ptr);
+    source.is_manual = true;
+    bit_pos.is_manual = true;
+
+    HexValue r1 = gen_convround_n_a(c, locp, &source, &bit_pos);
+    HexValue r2 = gen_convround_n_b(c, locp, &source, &bit_pos);
+    HexValue r3 = gen_convround_n_c(c, locp, &source, &bit_pos);
+
+    HexValue l_32 = gen_tmp_value(c, locp, "1", 32);
+
+    HexValue cond = gen_tmp(c, locp, 32);
+    HexValue cond_64 = gen_tmp(c, locp, 64);
+    HexValue mask = gen_tmp(c, locp, 32);
+    HexValue n_64 = gen_tmp(c, locp, 64);
+    HexValue res = gen_tmp(c, locp, 64);
+    HexValue zero = gen_tmp_value(c, locp, "0", 64);
+
+    OUT(c, locp, "tcg_gen_sub_i32(", &mask);
+    OUT(c, locp, ", ", &bit_pos, ", ", &l_32, ");\n");
+    OUT(c, locp, "tcg_gen_shl_i32(", &mask);
+    OUT(c, locp, ", ", &l_32, ", ", &mask, ");\n");
+    OUT(c, locp, "tcg_gen_sub_i32(", &mask);
+    OUT(c, locp, ", ", &mask, ", ", &l_32, ");\n");
+    OUT(c, locp, "tcg_gen_and_i32(", &cond);
+    OUT(c, locp, ", ", &source, ", ", &mask, ");\n");
+    OUT(c, locp, "tcg_gen_extu_i32_i64(", &cond_64, ", ", &cond, ");\n");
+    OUT(c, locp, "tcg_gen_ext_i32_i64(", &n_64, ", ", &bit_pos, ");\n");
+
+    OUT(c, locp, "tcg_gen_movcond_i64");
+    OUT(c, locp, "(TCG_COND_EQ, ", &res, ", ", &cond_64, ", ", &zero);
+    OUT(c, locp, ", ", &r2, ", ", &r3, ");\n");
+
+    OUT(c, locp, "tcg_gen_movcond_i64");
+    OUT(c, locp, "(TCG_COND_EQ, ", &res, ", ", &n_64, ", ", &zero);
+    OUT(c, locp, ", ", &r1, ", ", &res, ");\n");
+
+    OUT(c, locp, "tcg_gen_shr_i64(", &res);
+    OUT(c, locp, ", ", &res, ", ", &n_64, ");\n");
+
+    rvalue_free_ext(c, locp, &source, free_source_sym);
+    rvalue_free_ext(c, locp, &bit_pos, free_bit_pos_sym);
+
+    rvalue_free(c, locp, &r1);
+    rvalue_free(c, locp, &r2);
+    rvalue_free(c, locp, &r3);
+
+    rvalue_free(c, locp, &cond);
+    rvalue_free(c, locp, &cond_64);
+    rvalue_free(c, locp, &l_32);
+    rvalue_free(c, locp, &mask);
+    rvalue_free(c, locp, &n_64);
+    rvalue_free(c, locp, &zero);
+
+    res = rvalue_truncate(c, locp, &res);
+    return res;
+}
+
+HexValue gen_round(Context *c,
+                   YYLTYPE *locp,
+                   HexValue *source,
+                   HexValue *position) {
+    yyassert(c, locp, source->bit_width <= 32,
+             "fRNDN not implemented for bit widths > 32!");
+
+    HexValue src = *source;
+    HexValue pos = *position;
+
+    HexValue src_width = gen_imm_value(c, locp, src.bit_width, 32);
+    HexValue dst_width = gen_imm_value(c, locp, 64, 32);
+    HexValue a = gen_extend_op(c, locp, &src_width, &dst_width, &src, false);
+
+    src_width = gen_imm_value(c, locp, 5, 32);
+    dst_width = gen_imm_value(c, locp, 64, 32);
+    HexValue b = gen_extend_op(c, locp, &src_width, &dst_width, &pos, true);
+
+    /* Disable auto-free of values used more than once */
+    a.is_manual = true;
+    b.is_manual = true;
+
+    HexValue res = gen_tmp(c, locp, 64);
+
+    HexValue one = gen_tmp_value(c, locp, "1", 64);
+    HexValue n_m1 = gen_bin_op(c, locp, SUB_OP, &b, &one);
+    one = gen_tmp_value(c, locp, "1", 64);
+    HexValue shifted = gen_bin_op(c, locp, ASL_OP, &one, &n_m1);
+    HexValue sum = gen_bin_op(c, locp, ADD_OP, &shifted, &a);
+
+    HexValue zero = gen_tmp_value(c, locp, "0", 64);
+    OUT(c, locp, "tcg_gen_movcond_i64");
+    OUT(c, locp, "(TCG_COND_EQ, ", &res, ", ", &b, ", ", &zero);
+    OUT(c, locp, ", ", &a, ", ", &sum, ");\n");
+
+    rvalue_free_manual(c, locp, &a);
+    rvalue_free_manual(c, locp, &b);
+    rvalue_free(c, locp, &zero);
+    rvalue_free(c, locp, &sum);
+
+    return res;
+}
+
+/* Circular addressing mode with auto-increment */
+HexValue gen_circ_op(Context *c,
+                     YYLTYPE *locp,
+                     HexValue *addr,
+                     HexValue *increment,
+                     HexValue *modifier) {
+    HexValue increment_m = *increment;
+    HexValue res = gen_tmp(c, locp, addr->bit_width);
+    res.is_unsigned = addr->is_unsigned;
+    HexValue cs = gen_tmp(c, locp, 32);
+    increment_m = rvalue_materialize(c, locp, &increment_m);
+    OUT(c, locp, "READ_REG(", &cs, ", HEX_REG_CS0 + MuN);\n");
+    OUT(c,
+        locp,
+        "gen_helper_fcircadd(",
+        &res,
+        ", ",
+        addr,
+        ", ",
+        &increment_m,
+        ", ",
+        modifier);
+    OUT(c, locp, ", ", &cs, ");\n");
+    rvalue_free(c, locp, addr);
+    rvalue_free(c, locp, &increment_m);
+    rvalue_free(c, locp, modifier);
+    rvalue_free(c, locp, &cs);
+    return res;
+}
+
+HexValue gen_locnt_op(Context *c, YYLTYPE *locp, HexValue *source)
+{
+    HexValue source_m = *source;
+    const char *bit_suffix = source->bit_width == 64 ? "64" : "32";
+    HexValue res = gen_tmp(c, locp, source->bit_width == 64 ? 64 : 32);
+    res.type = TEMP;
+    source_m = rvalue_materialize(c, locp, &source_m);
+    OUT(c, locp, "tcg_gen_not_i", bit_suffix, "(",
+        &res, ", ", &source_m, ");\n");
+    OUT(c, locp, "tcg_gen_clzi_i", bit_suffix, "(", &res, ", ", &res, ", ");
+    OUT(c, locp, bit_suffix, ");\n");
+    rvalue_free(c, locp, &source_m);
+    return res;
+}
+
+HexValue gen_ctpop_op(Context *c, YYLTYPE *locp, HexValue *source)
+{
+    HexValue source_m = *source;
+    const char *bit_suffix = source_m.bit_width == 64 ? "64" : "32";
+    HexValue res = gen_tmp(c, locp, source_m.bit_width == 64 ? 64 : 32);
+    res.type = TEMP;
+    source_m = rvalue_materialize(c, locp, &source_m);
+    OUT(c, locp, "tcg_gen_ctpop_i", bit_suffix,
+        "(", &res, ", ", &source_m, ");\n");
+    rvalue_free(c, locp, &source_m);
+    return res;
+}
+
+HexValue gen_fbrev_4(Context *c, YYLTYPE *locp, HexValue *source)
+{
+    HexValue source_m = *source;
+
+    HexValue res = gen_tmp(c, locp, 32);
+    HexValue tmp1 = gen_tmp(c, locp, 32);
+    HexValue tmp2 = gen_tmp(c, locp, 32);
+
+    source_m = rvalue_materialize(c, locp, &source_m);
+    source_m = rvalue_truncate(c, locp, &source_m);
+
+    OUT(c, locp, "tcg_gen_mov_tl(", &res, ", ", &source_m, ");\n");
+    OUT(c, locp, "tcg_gen_andi_tl(", &tmp1, ", ", &res, ", 0xaaaaaaaa);\n");
+    OUT(c, locp, "tcg_gen_shri_tl(", &tmp1, ", ", &tmp1, ", 1);\n");
+    OUT(c, locp, "tcg_gen_andi_tl(", &tmp2, ", ", &res, ", 0x55555555);\n");
+    OUT(c, locp, "tcg_gen_shli_tl(", &tmp2, ", ", &tmp2, ", 1);\n");
+    OUT(c, locp, "tcg_gen_or_tl(", &res, ", ", &tmp1, ", ", &tmp2, ");\n");
+    OUT(c, locp, "tcg_gen_andi_tl(", &tmp1, ", ", &res, ", 0xcccccccc);\n");
+    OUT(c, locp, "tcg_gen_shri_tl(", &tmp1, ", ", &tmp1, ", 2);\n");
+    OUT(c, locp, "tcg_gen_andi_tl(", &tmp2, ", ", &res, ", 0x33333333);\n");
+    OUT(c, locp, "tcg_gen_shli_tl(", &tmp2, ", ", &tmp2, ", 2);\n");
+    OUT(c, locp, "tcg_gen_or_tl(", &res, ", ", &tmp1, ", ", &tmp2, ");\n");
+    OUT(c, locp, "tcg_gen_andi_tl(", &tmp1, ", ", &res, ", 0xf0f0f0f0);\n");
+    OUT(c, locp, "tcg_gen_shri_tl(", &tmp1, ", ", &tmp1, ", 4);\n");
+    OUT(c, locp, "tcg_gen_andi_tl(", &tmp2, ", ", &res, ", 0x0f0f0f0f);\n");
+    OUT(c, locp, "tcg_gen_shli_tl(", &tmp2, ", ", &tmp2, ", 4);\n");
+    OUT(c, locp, "tcg_gen_or_tl(", &res, ", ", &tmp1, ", ", &tmp2, ");\n");
+    OUT(c, locp, "tcg_gen_andi_tl(", &tmp1, ", ", &res, ", 0xff00ff00);\n");
+    OUT(c, locp, "tcg_gen_shri_tl(", &tmp1, ", ", &tmp1, ", 8);\n");
+    OUT(c, locp, "tcg_gen_andi_tl(", &tmp2, ", ", &res, ", 0x00ff00ff);\n");
+    OUT(c, locp, "tcg_gen_shli_tl(", &tmp2, ", ", &tmp2, ", 8);\n");
+    OUT(c, locp, "tcg_gen_or_tl(", &res, ", ", &tmp1, ", ", &tmp2, ");\n");
+    OUT(c, locp, "tcg_gen_shri_tl(", &tmp1, ", ", &res, ", 16);\n");
+    OUT(c, locp, "tcg_gen_shli_tl(", &tmp2, ", ", &res, ", 16);\n");
+    OUT(c, locp, "tcg_gen_or_tl(", &res, ", ", &tmp1, ", ", &tmp2, ");\n");
+
+    rvalue_free(c, locp, &tmp1);
+    rvalue_free(c, locp, &tmp2);
+    rvalue_free(c, locp, &source_m);
+
+    return res;
+}
+
+HexValue gen_fbrev_8(Context *c, YYLTYPE *locp, HexValue *source)
+{
+    HexValue source_m = *source;
+
+    source_m = rvalue_extend(c, locp, &source_m);
+    source_m = rvalue_materialize(c, locp, &source_m);
+
+    HexValue res = gen_tmp(c, locp, 64);
+    HexValue tmp1 = gen_tmp(c, locp, 64);
+    HexValue tmp2 = gen_tmp(c, locp, 64);
+
+    OUT(c, locp, "tcg_gen_mov_i64(",
+        &res, ", ", &source_m, ");\n");
+    OUT(c, locp, "tcg_gen_andi_i64(",
+        &tmp1, ", ", &res, ", 0xaaaaaaaaaaaaaaaa);\n");
+    OUT(c, locp, "tcg_gen_shri_i64(",
+        &tmp1, ", ", &tmp1, ", 1);\n");
+    OUT(c, locp, "tcg_gen_andi_i64(",
+        &tmp2, ", ", &res, ", 0x5555555555555555);\n");
+    OUT(c, locp, "tcg_gen_shli_i64(",
+        &tmp2, ", ", &tmp2, ", 1);\n");
+    OUT(c, locp, "tcg_gen_or_i64(", &res, ", ", &tmp1, ", ", &tmp2, ");\n");
+    OUT(c, locp, "tcg_gen_andi_i64(",
+        &tmp1, ", ", &res, ", 0xcccccccccccccccc);\n");
+    OUT(c, locp, "tcg_gen_shri_i64(",
+        &tmp1, ", ", &tmp1, ", 2);\n");
+    OUT(c, locp, "tcg_gen_andi_i64(",
+        &tmp2, ", ", &res, ", 0x3333333333333333);\n");
+    OUT(c, locp, "tcg_gen_shli_i64(",
+        &tmp2, ", ", &tmp2, ", 2);\n");
+    OUT(c, locp, "tcg_gen_or_i64(", &res, ", ", &tmp1, ", ", &tmp2, ");\n");
+    OUT(c, locp, "tcg_gen_andi_i64(",
+        &tmp1, ", ", &res, ", 0xf0f0f0f0f0f0f0f0);\n");
+    OUT(c, locp, "tcg_gen_shri_i64(",
+        &tmp1, ", ", &tmp1, ", 4);\n");
+    OUT(c, locp, "tcg_gen_andi_i64(",
+        &tmp2, ", ", &res, ", 0x0f0f0f0f0f0f0f0f);\n");
+    OUT(c, locp, "tcg_gen_shli_i64(",
+        &tmp2, ", ", &tmp2, ", 4);\n");
+    OUT(c, locp, "tcg_gen_or_i64(", &res, ", ", &tmp1, ", ", &tmp2, ");\n");
+    OUT(c, locp, "tcg_gen_andi_i64(",
+        &tmp1, ", ", &res, ", 0xff00ff00ff00ff00);\n");
+    OUT(c, locp, "tcg_gen_shri_i64(",
+        &tmp1, ", ", &tmp1, ", 8);\n");
+    OUT(c, locp, "tcg_gen_andi_i64(",
+        &tmp2, ", ", &res, ", 0x00ff00ff00ff00ff);\n");
+    OUT(c, locp, "tcg_gen_shli_i64(",
+        &tmp2, ", ", &tmp2, ", 8);\n");
+    OUT(c, locp, "tcg_gen_or_i64(", &res, ", ", &tmp1, ", ", &tmp2, ");\n");
+    OUT(c, locp, "tcg_gen_andi_i64(",
+        &tmp1, ", ", &res, ", 0xffff0000ffff0000);\n");
+    OUT(c, locp, "tcg_gen_shri_i64(",
+        &tmp1, ", ", &tmp1, ", 16);\n");
+    OUT(c, locp, "tcg_gen_andi_i64(",
+        &tmp2, ", ", &res, ", 0x0000ffff0000ffff);\n");
+    OUT(c, locp, "tcg_gen_shli_i64(",
+        &tmp2, ", ", &tmp2, ", 16);\n");
+    OUT(c, locp, "tcg_gen_or_i64(", &res, ", ", &tmp1, ", ", &tmp2, ");\n");
+    OUT(c, locp, "tcg_gen_shri_i64(", &tmp1, ", ", &res, ", 32);\n");
+    OUT(c, locp, "tcg_gen_shli_i64(", &tmp2, ", ", &res, ", 32);\n");
+    OUT(c, locp, "tcg_gen_or_i64(", &res, ", ", &tmp1, ", ", &tmp2, ");\n");
+
+    rvalue_free(c, locp, &tmp1);
+    rvalue_free(c, locp, &tmp2);
+    rvalue_free(c, locp, &source_m);
+
+    return res;
+}
+
+HexValue gen_rotl(Context *c, YYLTYPE *locp, HexValue *source, HexValue *n)
+{
+    const char *suffix = source->bit_width == 64 ? "i64" : "i32";
+
+    HexValue res = gen_tmp(c, locp, source->bit_width);
+    res.is_unsigned = source->is_unsigned;
+    HexValue tmp_l = gen_tmp(c, locp, source->bit_width);
+    HexValue tmp_r = gen_tmp(c, locp, source->bit_width);
+    HexValue shr = gen_tmp(c, locp, source->bit_width);
+
+    OUT(c, locp, "tcg_gen_movi_", suffix, "(",
+        &shr, ", ", &source->bit_width, ");\n");
+    OUT(c, locp, "tcg_gen_subi_", suffix, "(",
+        &shr, ", ", &shr, ", ", n, ");\n");
+    OUT(c, locp, "tcg_gen_shli_", suffix, "(",
+        &tmp_l, ", ", source, ", ", n, ");\n");
+    OUT(c, locp, "tcg_gen_shr_", suffix, "(",
+        &tmp_r, ", ", source, ", ", &shr, ");\n");
+    OUT(c, locp, "tcg_gen_or_", suffix, "(",
+        &res, ", ", &tmp_l, ", ", &tmp_r, ");\n");
+
+    rvalue_free(c, locp, source);
+    rvalue_free(c, locp, n);
+    rvalue_free(c, locp, &tmp_l);
+    rvalue_free(c, locp, &tmp_r);
+    rvalue_free(c, locp, &shr);
+
+    return res;
+}
+
+const char *INTERLEAVE_MASKS[6] = {
+    "0x5555555555555555ULL",
+    "0x3333333333333333ULL",
+    "0x0f0f0f0f0f0f0f0fULL",
+    "0x00ff00ff00ff00ffULL",
+    "0x0000ffff0000ffffULL",
+    "0x00000000ffffffffULL",
+};
+
+HexValue gen_deinterleave(Context *c, YYLTYPE *locp, HexValue *mixed)
+{
+    HexValue src = rvalue_extend(c, locp, mixed);
+
+    HexValue a = gen_tmp(c, locp, 64);
+    a.is_unsigned = true;
+    HexValue b = gen_tmp(c, locp, 64);
+    b.is_unsigned = true;
+
+    const char **masks = INTERLEAVE_MASKS;
+
+    OUT(c, locp, "tcg_gen_shri_i64(", &a, ", ", &src, ", 1);\n");
+    OUT(c, locp, "tcg_gen_andi_i64(", &a, ", ", &a, ", ", masks[0], ");\n");
+    OUT(c, locp, "tcg_gen_andi_i64(", &b, ", ", &src, ", ", masks[0], ");\n");
+
+    HexValue res = gen_tmp(c, locp, 64);
+    res.is_unsigned = true;
+
+    unsigned shift = 1;
+    for (unsigned i = 1; i < 6; ++i) {
+        OUT(c, locp, "tcg_gen_shri_i64(", &res, ", ", &b, ", ", &shift, ");\n");
+        OUT(c, locp, "tcg_gen_or_i64(", &b, ", ", &res, ", ", &b, ");\n");
+        OUT(c, locp, "tcg_gen_andi_i64(", &b, ", ", &b, ", ", masks[i], ");\n");
+        OUT(c, locp, "tcg_gen_shri_i64(", &res, ", ", &a, ", ", &shift, ");\n");
+        OUT(c, locp, "tcg_gen_or_i64(", &a, ", ", &res, ", ", &a, ");\n");
+        OUT(c, locp, "tcg_gen_andi_i64(", &a, ", ", &a, ", ", masks[i], ");\n");
+        shift <<= 1;
+    }
+
+    OUT(c, locp, "tcg_gen_shli_i64(", &a, ", ", &a, ", 32);\n");
+    OUT(c, locp, "tcg_gen_or_i64(", &res, ", ", &a, ", ", &b, ");\n");
+
+    rvalue_free(c, locp, &a);
+    rvalue_free(c, locp, &b);
+
+    return res;
+}
+
+HexValue gen_interleave(Context *c,
+                        YYLTYPE *locp,
+                        HexValue *odd,
+                        HexValue *even)
+{
+    HexValue a = rvalue_truncate(c, locp, odd);
+    a.is_unsigned = true;
+    HexValue b = rvalue_truncate(c, locp, even);
+    a.is_unsigned = true;
+
+    a = rvalue_extend(c, locp, &a);
+    b = rvalue_extend(c, locp, &b);
+
+    HexValue res = gen_tmp(c, locp, 64);
+    res.is_unsigned = true;
+
+    const char **masks = INTERLEAVE_MASKS;
+
+    unsigned shift = 16;
+    for (int i = 4; i >= 0; --i) {
+        OUT(c, locp, "tcg_gen_shli_i64(", &res, ", ", &a, ", ", &shift, ");\n");
+        OUT(c, locp, "tcg_gen_or_i64(", &a, ", ", &res, ", ", &a, ");\n");
+        OUT(c, locp, "tcg_gen_andi_i64(", &a, ", ", &a, ", ", masks[i], ");\n");
+        OUT(c, locp, "tcg_gen_shli_i64(", &res, ", ", &b, ", ", &shift, ");\n");
+        OUT(c, locp, "tcg_gen_or_i64(", &b, ", ", &res, ", ", &b, ");\n");
+        OUT(c, locp, "tcg_gen_andi_i64(", &b, ", ", &b, ", ", masks[i], ");\n");
+        shift >>= 1;
+    }
+
+    OUT(c, locp, "tcg_gen_shli_i64(", &a, ", ", &a, ", 1);\n");
+    OUT(c, locp, "tcg_gen_or_i64(", &res, ", ", &a, ", ", &b, ");\n");
+
+    rvalue_free(c, locp, &a);
+    rvalue_free(c, locp, &b);
+
+    return res;
+}
+
+bool reg_equal(HexReg *r1, HexReg *r2)
+{
+    return !memcmp(r1, r2, sizeof(HexReg));
+}
+
+bool pre_equal(HexPre *p1, HexPre *p2)
+{
+    return !memcmp(p1, p2, sizeof(HexPre));
+}
+
+bool rvalue_equal(HexValue *v1, HexValue *v2)
+{
+    if (v1->is_dotnew != v2->is_dotnew) {
+        return false;
+    } else if (v1->type == REGISTER && v2->type == REGISTER) {
+        return reg_equal(&(v1->reg), &(v2->reg));
+    } else if (v1->type == PREDICATE && v2->type == PREDICATE) {
+        return pre_equal(&(v1->pre), &(v2->pre));
+    } else {
+        return false;
+    }
+}
+
+void emit_header(Context *c)
+{
+    EMIT_SIG(c, START_COMMENT " %s " END_COMMENT "\n", c->inst.name);
+    EMIT_SIG(c, "void emit_%s(DisasContext *ctx, Insn *insn, Packet *pkt",
+             c->inst.name);
+}
+
+void emit_arg(Context *c, YYLTYPE *locp, HexValue *arg)
+{
+    switch (arg->type) {
+    case REGISTER:
+        if (arg->reg.type == DOTNEW) {
+            EMIT_SIG(c, ", TCGv N%cN", arg->reg.id);
+        } else {
+            bool is64 = (arg->bit_width == 64);
+            const char *type = is64 ? "TCGv_i64" : "TCGv_i32";
+            char reg_id[5] = { 0 };
+            reg_compose(c, locp, &(arg->reg), reg_id);
+            EMIT_SIG(c, ", %s %s", type, reg_id);
+            /* MuV register requires also MuN to provide its index */
+            if (arg->reg.type == MODIFIER) {
+                EMIT_SIG(c, ", int MuN");
+            }
+        }
+        break;
+    case PREDICATE:
+        {
+            char suffix = arg->is_dotnew ? 'N' : 'V';
+            EMIT_SIG(c, ", TCGv P%c%c", arg->pre.id, suffix);
+        }
+        break;
+    default:
+        {
+            fprintf(stderr, "emit_arg got unsupported argument!");
+            abort();
+        }
+    }
+}
+
+void emit_footer(Context *c)
+{
+    EMIT(c, "}\n");
+    EMIT(c, "\n");
+}
+
+void free_variables(Context *c, YYLTYPE *locp)
+{
+    for (unsigned i = 0; i < c->inst.allocated_count; ++i) {
+        Var *var = &c->inst.allocated[i];
+        const char *suffix = var->bit_width == 64 ? "i64" : "i32";
+        OUT(c, locp, "tcg_temp_free_", suffix, "(", var->name, ");\n");
+    }
+}
+
+void free_instruction(Context *c)
+{
+    /* Reset buffers */
+    c->signature_c = 0;
+    c->out_c = 0;
+    c->header_c = 0;
+    /* Free allocated register tracking */
+    for (int i = 0; i < c->inst.allocated_count; i++) {
+        free((char *)c->inst.allocated[i].name);
+    }
+    /* Free INAME token value */
+    free(c->inst.name);
+    /* Initialize instruction-specific portion of the context */
+    memset(&(c->inst), 0, sizeof(Inst));
+}
diff --git a/target/hexagon/idef-parser/parser-helpers.h b/target/hexagon/idef-parser/parser-helpers.h
new file mode 100644
index 0000000000..36d260ecb7
--- /dev/null
+++ b/target/hexagon/idef-parser/parser-helpers.h
@@ -0,0 +1,293 @@ 
+/*
+ * Copyright(c) 2019-2020 rev.ng Srls. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; withOUT even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; 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 "idef-parser.tab.h"
+#include "idef-parser.yy.h"
+#include "parser-helpers.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);
+
+/* Print functions */
+void str_print(Context *c, YYLTYPE *locp, char *string);
+
+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 pre_print(Context *c, YYLTYPE *locp, HexPre *pre, 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_out(Context *c, YYLTYPE *locp, void *pointer);
+
+/* Copy output code buffer into stdout */
+void commit(Context *c);
+
+#define OUT_IMPL(c, locp, x)                                            \
+    do {                                                                \
+        if (__builtin_types_compatible_p(typeof(*x), char)) {           \
+            str_print((c), (locp), (char *) x);                         \
+        } else if (__builtin_types_compatible_p(typeof(*x), uint64_t)) { \
+            uint64_print((c), (locp), (uint64_t *) x);                  \
+        } else if (__builtin_types_compatible_p(typeof(*x), int)) {     \
+            int_print((c), (locp), (int *) x);                          \
+        } else if (__builtin_types_compatible_p(typeof(*x), unsigned)) { \
+            uint_print((c), (locp), (unsigned *) x);                    \
+        } else if (__builtin_types_compatible_p(typeof(*x), HexValue)) { \
+            rvalue_out((c), (locp), (HexValue *) x);                 \
+        } else {                                                        \
+            yyassert(c, locp, false, "Unhandled print type!");          \
+        }                                                               \
+    } while (0);
+
+/* Make a 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, int bit_width);
+
+HexValue gen_local_tmp(Context *c, YYLTYPE *locp, int bit_width);
+
+HexValue gen_tmp_value(Context *c,
+                          YYLTYPE *locp,
+                          const char *value,
+                          int bit_width);
+
+HexValue gen_imm_value(Context *c __attribute__((unused)),
+                          YYLTYPE *locp,
+                          int value,
+                          int bit_width);
+
+void rvalue_free(Context *c, YYLTYPE *locp, HexValue *rvalue);
+
+HexValue rvalue_materialize(Context *c, YYLTYPE *locp, HexValue *rvalue);
+
+HexValue rvalue_extend(Context *c, YYLTYPE *locp, HexValue *rvalue);
+
+HexValue rvalue_truncate(Context *c, YYLTYPE *locp, HexValue *rvalue);
+
+int find_variable(Context *c, YYLTYPE *locp, HexValue *varid);
+
+void varid_allocate(Context *c,
+                    YYLTYPE *locp,
+                    HexValue *varid,
+                    int width,
+                    bool is_unsigned);
+
+void ea_free(Context *c, YYLTYPE *locp);
+
+HexValue gen_bin_cmp(Context *c,
+                     YYLTYPE *locp,
+                     const char *type,
+                     HexValue *op1_ptr,
+                     HexValue *op2_ptr);
+
+/* Code generation functions */
+HexValue gen_bin_op(Context *c,
+                       YYLTYPE *locp,
+                       enum OpType type,
+                       HexValue *operand1,
+                       HexValue *operand2);
+
+HexValue gen_cast_op(Context *c,
+                        YYLTYPE *locp,
+                        HexValue *source,
+                        unsigned target_width);
+
+HexValue gen_extend_op(Context *c,
+                          YYLTYPE *locp,
+                          HexValue *src_width_ptr,
+                          HexValue *dst_width_ptr,
+                          HexValue *value_ptr,
+                          bool is_unsigned);
+
+void gen_rdeposit_op(Context *c,
+                     YYLTYPE *locp,
+                     HexValue *dest,
+                     HexValue *value,
+                     HexValue *begin,
+                     HexValue *width);
+
+void gen_deposit_op(Context *c,
+                           YYLTYPE *locp,
+                           HexValue *dest,
+                           HexValue *value,
+                           HexValue *index,
+                           HexCast *cast);
+
+HexValue gen_rextract_op(Context *c,
+                         YYLTYPE *locp,
+                         HexValue *source,
+                         int begin,
+                         int width);
+
+HexValue gen_extract_op(Context *c,
+                           YYLTYPE *locp,
+                           HexValue *source,
+                           HexValue *index,
+                           HexExtract *extract);
+
+HexValue gen_read_creg(Context *c, YYLTYPE *locp, HexValue *reg);
+
+void gen_write_creg(Context *c,
+                           YYLTYPE *locp,
+                           HexValue *reg,
+                           HexValue *value);
+
+void gen_assign(Context *c,
+                YYLTYPE *locp,
+                HexValue *dest,
+                HexValue *value);
+
+HexValue gen_convround(Context *c,
+                          YYLTYPE *locp,
+                          HexValue *source);
+
+HexValue gen_round(Context *c,
+                   YYLTYPE *locp,
+                   HexValue *source,
+                   HexValue *position);
+
+HexValue gen_convround_n(Context *c,
+                         YYLTYPE *locp,
+                         HexValue *source_ptr,
+                         HexValue *bit_pos_ptr);
+
+/* Circular addressing mode with auto-increment */
+HexValue gen_circ_op(Context *c,
+                        YYLTYPE *locp,
+                        HexValue *addr,
+                        HexValue *increment,
+                        HexValue *modifier);
+
+HexValue gen_locnt_op(Context *c, YYLTYPE *locp, HexValue *source);
+
+HexValue gen_ctpop_op(Context *c, YYLTYPE *locp, HexValue *source);
+
+HexValue gen_fbrev_4(Context *c, YYLTYPE *locp, HexValue *source);
+
+HexValue gen_fbrev_8(Context *c, YYLTYPE *locp, HexValue *source);
+
+HexValue gen_rotl(Context *c, YYLTYPE *locp, HexValue *source, HexValue *n);
+
+HexValue gen_deinterleave(Context *c, YYLTYPE *locp, HexValue *mixed);
+
+HexValue gen_interleave(Context *c,
+                        YYLTYPE *locp,
+                        HexValue *odd,
+                        HexValue *even);
+
+
+bool reg_equal(HexReg *r1, HexReg *r2);
+
+bool pre_equal(HexPre *p1, HexPre *p2);
+
+bool rvalue_equal(HexValue *v1, HexValue *v2);
+
+void emit_header(Context *c);
+
+void emit_arg(Context *c, YYLTYPE *locp, HexValue *arg);
+
+void emit_footer(Context *c);
+
+void free_variables(Context *c, YYLTYPE *locp);
+
+void free_instruction(Context *c);
+
+#endif /* PARSER_HELPERS_h */
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index 5dda04dc29..e6abcc472f 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -197,7 +197,7 @@  idef_parser_input_generated = custom_target(
     command: [python, '@INPUT@', semantics_generated, attribs_def, gen_tcg_h, '@OUTPUT@'],
 )
 
-idef_parser_input_generated_prep = custom_target(
+preprocessed_idef_parser_input_generated = custom_target(
     'idef_parser_input.preprocessed.h.inc',
     output: 'idef_parser_input.preprocessed.h.inc',
     input: idef_parser_input_generated,
@@ -210,4 +210,25 @@  flex = generator(find_program('flex'),
                  output: ['@BASENAME@.yy.c', '@BASENAME@.yy.h'],
                  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@'])
+
+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',
+                         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@'],
+)
+
 target_arch += {'hexagon': hexagon_ss}
diff --git a/tests/docker/dockerfiles/alpine.docker b/tests/docker/dockerfiles/alpine.docker
index 1120e8555d..04a85afe3b 100644
--- a/tests/docker/dockerfiles/alpine.docker
+++ b/tests/docker/dockerfiles/alpine.docker
@@ -9,6 +9,7 @@  ENV PACKAGES \
 	alsa-lib-dev \
 	bash \
 	binutils \
+	bison \
 	coreutils \
 	curl-dev \
 	flex \
diff --git a/tests/docker/dockerfiles/centos7.docker b/tests/docker/dockerfiles/centos7.docker
index 95966ea7e6..33c38dc35b 100644
--- a/tests/docker/dockerfiles/centos7.docker
+++ b/tests/docker/dockerfiles/centos7.docker
@@ -5,6 +5,7 @@  RUN yum -y update
 
 # Please keep this list sorted alphabetically
 ENV PACKAGES \
+    bison \
     bzip2 \
     bzip2-devel \
     ccache \
diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker
index 5919aa0697..0d4e07ae29 100644
--- a/tests/docker/dockerfiles/centos8.docker
+++ b/tests/docker/dockerfiles/centos8.docker
@@ -3,6 +3,7 @@  FROM centos:8.3.2011
 RUN dnf -y update
 ENV PACKAGES \
     SDL2-devel \
+    bison \
     bzip2 \
     bzip2-devel \
     dbus-daemon \
diff --git a/tests/docker/dockerfiles/debian10.docker b/tests/docker/dockerfiles/debian10.docker
index 5a1c902d45..6517257f46 100644
--- a/tests/docker/dockerfiles/debian10.docker
+++ b/tests/docker/dockerfiles/debian10.docker
@@ -17,6 +17,7 @@  RUN apt update && \
     DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \
     DEBIAN_FRONTEND=noninteractive eatmydata \
     apt install -y --no-install-recommends \
+        bison \
         bc \
         build-essential \
         ca-certificates \
diff --git a/tests/docker/dockerfiles/fedora-i386-cross.docker b/tests/docker/dockerfiles/fedora-i386-cross.docker
index 768bc1c9df..ce42ea2d2b 100644
--- a/tests/docker/dockerfiles/fedora-i386-cross.docker
+++ b/tests/docker/dockerfiles/fedora-i386-cross.docker
@@ -1,5 +1,6 @@ 
 FROM fedora:31
 ENV PACKAGES \
+    bison \
     bzip2 \
     diffutils \
     findutils \
diff --git a/tests/docker/dockerfiles/fedora-win32-cross.docker b/tests/docker/dockerfiles/fedora-win32-cross.docker
index f75aea6c22..cb5261167f 100644
--- a/tests/docker/dockerfiles/fedora-win32-cross.docker
+++ b/tests/docker/dockerfiles/fedora-win32-cross.docker
@@ -2,6 +2,7 @@  FROM fedora:32
 
 # Please keep this list sorted alphabetically
 ENV PACKAGES \
+    bison \
     bc \
     bzip2 \
     diffutils \
diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker
index e9b9e19be7..e433671152 100644
--- a/tests/docker/dockerfiles/fedora-win64-cross.docker
+++ b/tests/docker/dockerfiles/fedora-win64-cross.docker
@@ -2,6 +2,7 @@  FROM fedora:32
 
 # Please keep this list sorted alphabetically
 ENV PACKAGES \
+    bison \
     bc \
     bzip2 \
     diffutils \
diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker
index b656d8bab8..c590281afb 100644
--- a/tests/docker/dockerfiles/fedora.docker
+++ b/tests/docker/dockerfiles/fedora.docker
@@ -2,6 +2,7 @@  FROM fedora:32
 
 # Please keep this list sorted alphabetically
 ENV PACKAGES \
+    bison \
     bc \
     brlapi-devel \
     bzip2 \
diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker
index ce1db959a2..debdb029c1 100644
--- a/tests/docker/dockerfiles/opensuse-leap.docker
+++ b/tests/docker/dockerfiles/opensuse-leap.docker
@@ -3,6 +3,7 @@  FROM opensuse/leap:15.2
 # Please keep this list sorted alphabetically
 ENV PACKAGES \
     bc \
+    bison \
     brlapi-devel \
     bzip2 \
     cyrus-sasl-devel \
diff --git a/tests/docker/dockerfiles/ubuntu.docker b/tests/docker/dockerfiles/ubuntu.docker
index e2f55eb892..90e57e1943 100644
--- a/tests/docker/dockerfiles/ubuntu.docker
+++ b/tests/docker/dockerfiles/ubuntu.docker
@@ -11,6 +11,7 @@ 
 
 FROM ubuntu:20.04
 ENV PACKAGES \
+    bison \
     ccache \
     clang \
     dbus \
diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker
index 2068118180..e291d1655b 100644
--- a/tests/docker/dockerfiles/ubuntu1804.docker
+++ b/tests/docker/dockerfiles/ubuntu1804.docker
@@ -1,5 +1,6 @@ 
 FROM ubuntu:18.04
 ENV PACKAGES \
+    bison \
     ccache \
     clang \
     flex \
diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker
index 13d43a7b90..bcab92b28a 100644
--- a/tests/docker/dockerfiles/ubuntu2004.docker
+++ b/tests/docker/dockerfiles/ubuntu2004.docker
@@ -1,5 +1,6 @@ 
 FROM ubuntu:20.04
-ENV PACKAGES bison \
+ENV PACKAGES \
+    bison \
     bsdmainutils \
     ccache \
     clang-10\