All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v7 00/13] target/hexagon: introduce idef-parser
@ 2021-12-17  9:01 Anton Johansson via
  2021-12-17  9:01 ` [PATCH v7 01/13] target/hexagon: update MAINTAINERS for idef-parser Anton Johansson via
                   ` (12 more replies)
  0 siblings, 13 replies; 24+ messages in thread
From: Anton Johansson via @ 2021-12-17  9:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: ale, tsimpson, bcain, babush, nizzo, richard.henderson

This patchset introduces the idef-parser for target/hexagon.

It's the seventh iteration of the patchset and includes fixes suggested in
previous iterations.

`idef-parser` is a build-time tool built using flex and bison. Its aim
is to generate a large part of the tiny code generator frontend for
Hexagon. The prototype of idef-parser has been presented at KVM Forum
2019 ("QEMU-Hexagon: Automatic Translation of the ISA Manual Pseudcode
to Tiny Code Instructions"):

    https://www.youtube.com/watch?v=3EpnTYBOXCI

`target/hexagon/idef-parser/README.rst` provides an overview of the
parser and its inner working.

A couple of notes:

* Other than minor changes, tweaks, and cleanup, this patchset includes
  one change to the type system of idef-parser. Variables in the parser
  are no longer automatically typed, but we instead rely on declartions
  found inside `fHIDE(int var;)` macros in the input code.

* These commits build successfully on the CI (including using clang),
  with one notable exception. Presently, the `build-user-hexagon` job
  fails due to not being able to find `flex`. We believe this to be
  caused by `debian-hexagon-cross` not being built by the CI.

  Last patch, we also introduced a commit to make sure containers
  produced by the developer Docker registry (as opposed to the official
  one) is used. Otherwise, the changes we made to the containers would not
  take effect.

  However, as Daniel pointed out, our solution is a hack.
  Since this is a problem only for developers when introducing new
  dependencies for the containers, we might consider not merging the
  last patch at all. But it's required in order to get some success in
  testing on the CI it required.

  Help on these matters is appreciated.

Alessandro Di Federico (5):
  target/hexagon: update MAINTAINERS for idef-parser
  target/hexagon: import README for idef-parser
  target/hexagon: prepare input for the idef-parser
  target/hexagon: call idef-parser functions
  gitlab-ci: do not use qemu-project Docker registry

Anton Johansson (1):
  target/hexagon: import parser for idef-parser

Niccolò Izzo (2):
  target/hexagon: introduce new helper functions
  target/hexagon: import additional tests

Paolo Montesel (5):
  target/hexagon: make slot number an unsigned
  target/hexagon: make helper functions non-static
  target/hexagon: expose next PC in DisasContext
  target/hexagon: import flex/bison to docker files
  target/hexagon: import lexer for idef-parser

 .gitlab-ci.d/container-cross.yml              |    2 +-
 .gitlab-ci.d/container-template.yml           |    4 +-
 .gitlab-ci.d/windows.yml                      |    2 +
 MAINTAINERS                                   |   11 +-
 meson_options.txt                             |    3 +
 target/hexagon/README                         |    5 +
 target/hexagon/gen_helper_funcs.py            |   16 +-
 target/hexagon/gen_helper_protos.py           |   16 +-
 target/hexagon/gen_idef_parser_funcs.py       |  123 +
 target/hexagon/gen_tcg_funcs.py               |   39 +-
 target/hexagon/genptr.c                       |  229 +-
 target/hexagon/genptr.h                       |   44 +
 target/hexagon/helper.h                       |    2 +
 target/hexagon/hex_common.py                  |   10 +
 target/hexagon/idef-parser/README.rst         |  722 +++++
 target/hexagon/idef-parser/idef-parser.h      |  259 ++
 target/hexagon/idef-parser/idef-parser.lex    |  571 ++++
 target/hexagon/idef-parser/idef-parser.y      | 1064 +++++++
 target/hexagon/idef-parser/macros.inc         |  140 +
 target/hexagon/idef-parser/parser-helpers.c   | 2548 +++++++++++++++++
 target/hexagon/idef-parser/parser-helpers.h   |  379 +++
 target/hexagon/idef-parser/prepare            |   24 +
 target/hexagon/macros.h                       |   11 +-
 target/hexagon/meson.build                    |  137 +-
 target/hexagon/op_helper.c                    |   39 +-
 target/hexagon/op_helper.h                    |   37 +
 target/hexagon/translate.c                    |    3 +-
 target/hexagon/translate.h                    |    1 +
 tests/docker/dockerfiles/alpine.docker        |    2 +
 tests/docker/dockerfiles/centos8.docker       |    2 +
 tests/docker/dockerfiles/debian-amd64.docker  |    2 +
 tests/docker/dockerfiles/debian-native.docker |    3 +
 .../dockerfiles/debian-riscv64-cross.docker   |    3 +
 .../dockerfiles/debian-tricore-cross.docker   |    2 +
 tests/docker/dockerfiles/debian10.docker      |    3 +
 .../dockerfiles/fedora-i386-cross.docker      |    3 +
 .../dockerfiles/fedora-win32-cross.docker     |    3 +
 .../dockerfiles/fedora-win64-cross.docker     |    3 +
 tests/docker/dockerfiles/fedora.docker        |    2 +
 tests/docker/dockerfiles/opensuse-leap.docker |    2 +
 tests/docker/dockerfiles/ubuntu.docker        |    3 +
 tests/docker/dockerfiles/ubuntu1804.docker    |    2 +
 tests/docker/dockerfiles/ubuntu2004.docker    |    2 +
 tests/tcg/hexagon/Makefile.target             |   30 +-
 tests/tcg/hexagon/crt.S                       |   26 +
 tests/tcg/hexagon/test_abs.S                  |   20 +
 tests/tcg/hexagon/test_bitcnt.S               |   42 +
 tests/tcg/hexagon/test_bitsplit.S             |   25 +
 tests/tcg/hexagon/test_call.S                 |   60 +
 tests/tcg/hexagon/test_clobber.S              |   35 +
 tests/tcg/hexagon/test_cmp.S                  |   34 +
 tests/tcg/hexagon/test_cmpy.S                 |   31 +
 tests/tcg/hexagon/test_dotnew.S               |   36 +
 tests/tcg/hexagon/test_ext.S                  |   16 +
 tests/tcg/hexagon/test_fibonacci.S            |   33 +
 tests/tcg/hexagon/test_hl.S                   |   19 +
 tests/tcg/hexagon/test_hwloops.S              |   22 +
 tests/tcg/hexagon/test_jmp.S                  |   25 +
 tests/tcg/hexagon/test_lsr.S                  |   39 +
 tests/tcg/hexagon/test_mpyi.S                 |   20 +
 tests/tcg/hexagon/test_overflow.S             |   63 +
 tests/tcg/hexagon/test_packet.S               |   26 +
 tests/tcg/hexagon/test_reorder.S              |   29 +
 tests/tcg/hexagon/test_round.S                |   31 +
 tests/tcg/hexagon/test_vavgw.S                |   33 +
 tests/tcg/hexagon/test_vcmpb.S                |   32 +
 tests/tcg/hexagon/test_vcmpw.S                |   29 +
 tests/tcg/hexagon/test_vcmpy.S                |   50 +
 tests/tcg/hexagon/test_vlsrw.S                |   23 +
 tests/tcg/hexagon/test_vmaxh.S                |   37 +
 tests/tcg/hexagon/test_vminh.S                |   37 +
 tests/tcg/hexagon/test_vpmpyh.S               |   30 +
 tests/tcg/hexagon/test_vspliceb.S             |   33 +
 73 files changed, 7353 insertions(+), 91 deletions(-)
 create mode 100644 target/hexagon/gen_idef_parser_funcs.py
 create mode 100644 target/hexagon/idef-parser/README.rst
 create mode 100644 target/hexagon/idef-parser/idef-parser.h
 create mode 100644 target/hexagon/idef-parser/idef-parser.lex
 create mode 100644 target/hexagon/idef-parser/idef-parser.y
 create mode 100644 target/hexagon/idef-parser/macros.inc
 create mode 100644 target/hexagon/idef-parser/parser-helpers.c
 create mode 100644 target/hexagon/idef-parser/parser-helpers.h
 create mode 100755 target/hexagon/idef-parser/prepare
 create mode 100644 target/hexagon/op_helper.h
 create mode 100644 tests/tcg/hexagon/crt.S
 create mode 100644 tests/tcg/hexagon/test_abs.S
 create mode 100644 tests/tcg/hexagon/test_bitcnt.S
 create mode 100644 tests/tcg/hexagon/test_bitsplit.S
 create mode 100644 tests/tcg/hexagon/test_call.S
 create mode 100644 tests/tcg/hexagon/test_clobber.S
 create mode 100644 tests/tcg/hexagon/test_cmp.S
 create mode 100644 tests/tcg/hexagon/test_cmpy.S
 create mode 100644 tests/tcg/hexagon/test_dotnew.S
 create mode 100644 tests/tcg/hexagon/test_ext.S
 create mode 100644 tests/tcg/hexagon/test_fibonacci.S
 create mode 100644 tests/tcg/hexagon/test_hl.S
 create mode 100644 tests/tcg/hexagon/test_hwloops.S
 create mode 100644 tests/tcg/hexagon/test_jmp.S
 create mode 100644 tests/tcg/hexagon/test_lsr.S
 create mode 100644 tests/tcg/hexagon/test_mpyi.S
 create mode 100644 tests/tcg/hexagon/test_overflow.S
 create mode 100644 tests/tcg/hexagon/test_packet.S
 create mode 100644 tests/tcg/hexagon/test_reorder.S
 create mode 100644 tests/tcg/hexagon/test_round.S
 create mode 100644 tests/tcg/hexagon/test_vavgw.S
 create mode 100644 tests/tcg/hexagon/test_vcmpb.S
 create mode 100644 tests/tcg/hexagon/test_vcmpw.S
 create mode 100644 tests/tcg/hexagon/test_vcmpy.S
 create mode 100644 tests/tcg/hexagon/test_vlsrw.S
 create mode 100644 tests/tcg/hexagon/test_vmaxh.S
 create mode 100644 tests/tcg/hexagon/test_vminh.S
 create mode 100644 tests/tcg/hexagon/test_vpmpyh.S
 create mode 100644 tests/tcg/hexagon/test_vspliceb.S

--
2.33.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v7 01/13] target/hexagon: update MAINTAINERS for idef-parser
  2021-12-17  9:01 [PATCH v7 00/13] target/hexagon: introduce idef-parser Anton Johansson via
@ 2021-12-17  9:01 ` Anton Johansson via
  2021-12-20 22:50   ` Taylor Simpson
  2021-12-17  9:01 ` [PATCH v7 02/13] target/hexagon: import README " Anton Johansson via
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 24+ messages in thread
From: Anton Johansson via @ 2021-12-17  9:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: ale, tsimpson, bcain, babush, nizzo, richard.henderson

From: Alessandro Di Federico <ale@rev.ng>

Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
 MAINTAINERS | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 7543eb4d59..f6fbc5f664 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -200,6 +200,8 @@ Hexagon TCG CPUs
 M: Taylor Simpson <tsimpson@quicinc.com>
 S: Supported
 F: target/hexagon/
+X: target/hexagon/idef-parser/
+X: target/hexagon/gen_idef_parser_funcs.py
 F: linux-user/hexagon/
 F: tests/tcg/hexagon/
 F: disas/hexagon.c
@@ -207,6 +209,13 @@ F: configs/targets/hexagon-linux-user/default.mak
 F: docker/dockerfiles/debian-hexagon-cross.docker
 F: docker/dockerfiles/debian-hexagon-cross.docker.d/build-toolchain.sh
 
+Hexagon idef-parser
+M: Alessandro Di Federico <ale@rev.ng>
+M: Anton Johansson <anjo@rev.ng>
+S: Supported
+F: target/hexagon/idef-parser/
+F: target/hexagon/gen_idef_parser_funcs.py
+
 HPPA (PA-RISC) TCG CPUs
 M: Richard Henderson <richard.henderson@linaro.org>
 S: Maintained
@@ -2788,7 +2797,7 @@ R: Paolo Bonzini <pbonzini@redhat.com>
 R: Bandan Das <bsd@redhat.com>
 R: Stefan Hajnoczi <stefanha@redhat.com>
 R: Thomas Huth <thuth@redhat.com>
-R: Darren Kenny <darren.kenny@oracle.com> 
+R: Darren Kenny <darren.kenny@oracle.com>
 R: Qiuhao Li <Qiuhao.Li@outlook.com>
 S: Maintained
 F: tests/qtest/fuzz/
-- 
2.33.1



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v7 02/13] target/hexagon: import README for idef-parser
  2021-12-17  9:01 [PATCH v7 00/13] target/hexagon: introduce idef-parser Anton Johansson via
  2021-12-17  9:01 ` [PATCH v7 01/13] target/hexagon: update MAINTAINERS for idef-parser Anton Johansson via
@ 2021-12-17  9:01 ` Anton Johansson via
  2021-12-22 21:05   ` Taylor Simpson
  2021-12-17  9:01 ` [PATCH v7 03/13] target/hexagon: make slot number an unsigned Anton Johansson via
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 24+ messages in thread
From: Anton Johansson via @ 2021-12-17  9:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: ale, tsimpson, bcain, babush, nizzo, richard.henderson

From: Alessandro Di Federico <ale@rev.ng>

Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Anton Johansson <anjo@rev.ng>
---
 target/hexagon/README                 |   5 +
 target/hexagon/idef-parser/README.rst | 722 ++++++++++++++++++++++++++
 2 files changed, 727 insertions(+)
 create mode 100644 target/hexagon/idef-parser/README.rst

diff --git a/target/hexagon/README b/target/hexagon/README
index 372e24747c..6cb5affddb 100644
--- a/target/hexagon/README
+++ b/target/hexagon/README
@@ -27,6 +27,10 @@ Hexagon-specific code are
         encode*.def             Encoding patterns for each instruction
         iclass.def              Instruction class definitions used to determine
                                 legal VLIW slots for each instruction
+    qemu/target/hexagon/idef-parser
+        Parser that, given the high-level definitions of an instruction,
+        produces a C function generating equivalent tiny code instructions.
+        See README.rst.
     qemu/linux-user/hexagon
         Helpers for loading the ELF file and making Linux system calls,
         signals, etc
@@ -47,6 +51,7 @@ header files in <BUILD_DIR>/target/hexagon
         gen_tcg_funcs.py                -> tcg_funcs_generated.c.inc
         gen_tcg_func_table.py           -> tcg_func_table_generated.c.inc
         gen_helper_funcs.py             -> helper_funcs_generated.c.inc
+        gen_idef_parser_funcs.py        -> idef_parser_input.h
 
 Qemu helper functions have 3 parts
     DEF_HELPER declaration indicates the signature of the helper
diff --git a/target/hexagon/idef-parser/README.rst b/target/hexagon/idef-parser/README.rst
new file mode 100644
index 0000000000..65e6bf4ee5
--- /dev/null
+++ b/target/hexagon/idef-parser/README.rst
@@ -0,0 +1,722 @@
+Hexagon ISA instruction definitions to tinycode generator compiler
+------------------------------------------------------------------
+
+idef-parser is a small compiler able to translate the Hexagon ISA description
+language into tinycode generator code, that can be easily integrated into QEMU.
+
+Compilation Example
+-------------------
+
+To better understand the scope of the idef-parser, we'll explore an applicative
+example. Let's start by one of the simplest Hexagon instruction: the ``add``.
+
+The ISA description language represents the ``add`` instruction as
+follows:
+
+.. code:: c
+
+   A2_add(RdV, in RsV, in RtV) {
+       { RdV=RsV+RtV;}
+   }
+
+idef-parser will compile the above code into the following code:
+
+.. code:: c
+
+   /* A2_add */
+   void emit_A2_add(DisasContext *ctx, Insn *insn, Packet *pkt, TCGv_i32 RdV,
+                    TCGv_i32 RsV, TCGv_i32 RtV)
+   /*  { RdV=RsV+RtV;} */
+   {
+       TCGv_i32 tmp_0 = tcg_temp_new_i32();
+       tcg_gen_add_i32(tmp_0, RsV, RtV);
+       tcg_gen_mov_i32(RdV, tmp_0);
+       tcg_temp_free_i32(tmp_0);
+   }
+
+The output of the compilation process will be a function, containing the
+tinycode generator code, implementing the correct semantics. That function will
+not access any global variable, because all the accessed data structures will be
+passed explicitly as function parameters. Among the passed parameters we will
+have TCGv (tinycode variables) representing the input and output registers of
+the architecture, integers representing the immediates that come from the code,
+and other data structures which hold information about the disassemblation
+context (``DisasContext`` struct).
+
+Let's begin by describing the input code. The ``add`` instruction is associated
+with a unique identifier, in this case ``A2_add``, which allows to distinguish
+variants of the same instruction, and expresses the class to which the
+instruction belongs, in this case ``A2`` corresponds to the Hexagon
+``ALU32/ALU`` instruction subclass.
+
+After the instruction identifier, we have a series of parameters that represents
+TCG variables that will be passed to the generated function. Parameters marked
+with ``in`` are already initialized, while the others are output parameters.
+
+We will leverage this information to infer several information:
+
+-  Fill in the output function signature with the correct TCGv registers
+-  Fill in the output function signature with the immediate integers
+-  Keep track of which registers, among the declared one, have been
+   initialized
+
+Let's now observe the actual instruction description code, in this case:
+
+.. code:: c
+
+   { RdV=RsV+RtV;}
+
+This code is composed by a subset of the C syntax, and is the result of the
+application of some macro definitions contained in the ``macros.h`` file.
+
+This file is used to reduce the complexity of the input language where complex
+variants of similar constructs can be mapped to a unique primitive, so that the
+idef-parser has to handle a lower number of computation primitives.
+
+As you may notice, the description code modifies the registers which have been
+declared by the declaration statements. In this case all the three registers
+will be declared, ``RsV`` and ``RtV`` will also be read and ``RdV`` will be
+written.
+
+Now let's have a quick look at the generated code, line by line.
+
+::
+
+   TCGv_i32 tmp_0 = tcg_temp_new_i32();
+
+This code starts by declaring a temporary TCGv to hold the result from the sum
+operation.
+
+::
+
+   tcg_gen_add_i32(tmp_0, RsV, RtV);
+
+Then, we are generating the sum tinycode operator between the selected
+registers, storing the result in the just declared temporary.
+
+::
+
+   tcg_gen_mov_i32(RdV, tmp_0);
+
+The result of the addition is now stored in the temporary, we move it into the
+correct destination register. This code may seem inefficient, but QEMU will
+perform some optimizations on the tinycode, reducing the unnecessary copy.
+
+::
+
+   tcg_temp_free_i32(tmp_0);
+
+Finally, we free the temporary we used to hold the addition result.
+
+Parser Input
+------------
+
+Before moving on to the structure of idef-parser itself, let us spend some words
+on its' input. There are two preprocessing steps applied to the generated
+instruction semantics in ``semantics_generated.pyinc`` that we need to consider.
+Firstly,
+
+::
+
+    gen_idef_parser_funcs.py
+
+which takes instruction semantics in ``semantics_generated.pyinc`` to C-like
+pseudo code, output into ``idef_parser_input.h.inc``. For instance, the
+``J2_jumpr`` instruction which jumps to an address stored in a register
+argument. This is instruction is defined as
+
+::
+
+    SEMANTICS( \
+        "J2_jumpr", \
+        "jumpr Rs32", \
+        """{fJUMPR(RsN,RsV,COF_TYPE_JUMPR);}""" \
+    )
+
+in ``semantics_generated.pyinc``. Running ``gen_idef_parser_funcs.py``
+we obtain the pseudo code
+
+::
+
+    J2_jumpr(in RsV) {
+        {fJUMPR(RsN,RsV,COF_TYPE_JUMPR);}
+    }
+
+with macros such as ``fJUMPR`` intact.
+
+The second step is to expand macros into a form suitable for our parser.
+These macros are defined in ``idef-parser/macros.inc`` and the step is
+carried out by the ``prepare`` script which runs the C preprocessor on
+``idef_parser_input.h.inc`` to produce
+``idef_parser_input.preprocessed.h.inc``.
+
+To finish the above example, after preprocessing ``J2_jumpr`` we obtain
+
+::
+
+    J2_jumpr(in RsV) {
+        {(PC = RsV);}
+    }
+
+where ``fJUMPR(RsN,RsV,COF_TYPE_JUMPR);`` was expanded to ``(PC = RsV)``,
+signifying a write to the Program Counter ``PC``.  Note, that ``PC`` in
+this expression is not a variable in the strict C sense since it is not
+declared anywhere, but rather a symbol which is easy to match in
+idef-parser later on.
+
+Parser Structure
+----------------
+
+The idef-parser is built using the ``flex`` and ``bison``.
+
+``flex`` is used to split the input string into tokens, each described using a
+regular expression. The token description is contained in the
+``idef-parser.lex`` source file. The flex-generated scanner takes care also to
+extract from the input text other meaningful information, e.g., the numerical
+value in case of an immediate constant, and decorates the token with the
+extracted information.
+
+``bison`` is used to generate the actual parser, starting from the parsing
+description contained in the ``idef-parser.y`` file. The generated parser
+executes the ``main`` function at the end of the ``idef-parser.y`` file, which
+opens input and output files, creates the parsing context, and eventually calls
+the ``yyparse()`` function, which starts the execution of the LALR(1) parser
+(see `Wikipedia <https://en.wikipedia.org/wiki/LALR_parser>`__ for more
+information about LALR parsing techniques). The LALR(1) parser, whenever it has
+to shift a token, calls the ``yylex()`` function, which is defined by the
+flex-generated code, and reads the input file returning the next scanned token.
+
+The tokens are mapped on the source language grammar, defined in the
+``idef-parser.y`` file to build a unique syntactic tree, according to the
+specified operator precedences and associativity rules.
+
+The grammar describes the whole file which contains the Hexagon instruction
+descriptions, therefore it starts from the ``input`` nonterminal, which is a
+list of instructions, each instruction is represented by the following grammar
+rule, representing the structure of the input file shown above:
+
+::
+
+   instruction : INAME arguments code
+               | error
+
+   arguments : '(' ')'
+             | '(' argument_list ')';
+
+   argument_list : argument_decl ',' argument_list
+                 | argument_decl
+
+   argument_decl : REG
+                 | PRED
+                 | IN REG
+                 | IN PRED
+                 | IMM
+                 | var
+                 ;
+
+   code        : '{' statements '}'
+
+   statements  : statements statement
+               | statement
+
+   statement   : control_statement
+               | var_decl ';'
+               | rvalue ';'
+               | code_block
+               | ';'
+
+   code_block  : '{' statements '}'
+               | '{' '}'
+
+With this initial portion of the grammar we are defining the instruction, its'
+arguments, and its' statements. Each argument is defined by the
+``argument_decl`` rule, and can be either
+
+::
+
+    Description                  Example
+    ----------------------------------------
+    output register              RsV
+    output predicate register    P0
+    input register               in RsV
+    input predicate register     in P0
+    immediate value              1234
+    local variable               EA
+
+Note, the only local variable allowed to be used as an argument is the effective
+address ``EA``. Similarly, each statement can be a ``control_statement``, a
+variable declaration such as ``int a;``, a code block, which is just a
+bracket-enclosed list of statements, a ``';'``, which is a ``nop`` instruction,
+and an ``rvalue ';'``.
+
+Expressions
+~~~~~~~~~~~
+
+Allowed in the input code are C language expressions with a few exceptions
+to simplify parsing. For instance, variable names such as ``RdV``, ``RssV``,
+``PdV``, ``CsV``, and other idiomatic register names from Hexagon, are
+reserved specifically for register arguments. These arguments then map to
+``TCGv_i32`` or ``TCGv_i64`` depending on the register size. Similarly, ``UiV``,
+``riV``, etc. refer to immediate arguments and will map to C integers.
+
+Also, as mentioned earlier, the names ``PC``, ``SP``, ``FP``, etc. are used to
+refer to Hexagon registers such as the program counter, stack pointer, and frame
+pointer seen here. Writes to these registers then correspond to assignments
+``PC = ...``, and reads correspond to uses of the variable ``PC``.
+
+Moreover, another example of one such exception is the selective expansion of
+macros present in ``macros.h``. As an example, consider the ``fABS`` macro which
+in plain C is defined as
+
+::
+
+    #define fABS(A) (((A) < 0) ? (-(A)) : (A))
+
+and returns the absolute value of the argument ``A``. This macro is not included
+in ``idef-parser/macros.inc`` and as such is not expanded and kept as a "call"
+``fABS(...)``. Reason being, that ``fABS`` is easier to match and map to
+``tcg_gen_abs_<width>``, compared to the full ternary expression above. Loads of
+macros in ``macros.h`` are kept unexpanded to aid in parsing, as seen in the
+example above, for more information see ``idef-parser/idef-parser.lex``.
+
+Finally, in mapping these input expressions to tinycode generators, idef-parser
+tries to perform as much as possible in plain C. Such as, performing binary
+operations in C instead of tinycode generators, thus effectively constant
+folding the expression.
+
+Variables and Variable Declarations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Similarly to C, variables in the input code must be explicitly declared, such as
+``int var1;`` which declares an uninitialized variable ``var1``. Initialization
+``int var2 = 0;`` is also allowed and behaves as expected. In tinycode
+generators the previous declarations are mapped to
+
+::
+
+    int var1;           ->      TCGv_i32 var1 = tcg_temp_local_new_i32();
+
+    int var2 = 0;       ->      TCGv_i32 var1 = tcg_temp_local_new_i32();
+                                tcg_gen_movi_i32(j, ((int64_t) 0ULL));
+
+which are later automatically freed at the end of the function they're declared
+in. Contrary to C, we only allow variables to be declared with an integer type
+specified in the following table (without permutation of keywords)
+
+::
+
+    type                        bit-width    signedness
+    ----------------------------------------------------------
+    int                         32           signed
+    signed
+    signed int
+
+    unsigned                    32           unsigned
+    unsigned int
+
+    long                        64           signed
+    long int
+    signed long
+    signed long int
+
+    unsigned long               64           unsigned
+    unsigned long int
+
+    long long                   64           signed
+    long long int
+    signed long long
+    signed long long int
+
+    unsigned long long          64           unsigned
+    unsigned long long int
+
+    size[1,2,4,8][s,u]_t        8-64         signed or unsigned
+
+In idef-parser, variable names are matched by a generic ``VARID`` token,
+which will feature the variable name as a decoration. For a variable declaration
+idef-parser calls ``gen_varid_allocate`` with the ``VARID`` token to save the
+name, size, and bit width of the newly declared variable. In addition, this
+function also ensures that variables aren't declared multiple times, and prints
+and error message if that is the case. Upon use of a variable, the ``VARID``
+token is used to lookup the size and bit width of the variable.
+
+Type System
+~~~~~~~~~~~
+
+idef-parser features a simple type system which is used to correctly implement
+the signedness and bit width of the operations.
+
+The type of each ``rvalue`` is determined by two attributes: its bit width
+(``unsigned bit_width``) and its signedness (``HexSignedness signedness``).
+
+For each operation, the type of ``rvalue``\ s influence the way in which the
+operands are handled and emitted. For example a right shift between signed
+operators will be an arithmetic shift, while one between unsigned operators
+will be a logical shift. If one of the two operands is signed, and the other
+is unsigned, the operation will be signed.
+
+The bit width also influences the outcome of the operations, in particular while
+the input languages features a fine granularity type system, with types of 8,
+16, 32, 64 (and more for vectorial instructions) bits, the tinycode only
+features 32 and 64 bit widths. We propagate as much as possible the fine
+granularity type, until the value has to be used inside an operation between
+``rvalue``\ s; in that case if one of the two operands is greater than 32 bits
+we promote the whole operation to 64 bit, taking care of properly extending the
+two operands. Fortunately, the most critical instructions already feature
+explicit casts and zero/sign extensions which are properly propagated down to
+our parser.
+
+The combination of ``rvalue``\ s are handled through the use of the
+``gen_bin_op`` and ``gen_bin_cmp`` helper functions. These two functions handle
+the appropriate compile-time or run-time emission of operations to perform the
+required computation.
+
+Control Statements
+~~~~~~~~~~~~~~~~~~
+
+``control_statement``\ s are all the statements which modify the order of
+execution of the generated code according to input parameters. They are expanded
+by the following grammar rule:
+
+::
+
+   control_statement : frame_check
+                     | cancel_statement
+                     | if_statement
+                     | for_statement
+                     | fpart1_statement
+
+``if_statement``\ s require the emission of labels and branch instructions which
+effectively perform conditional jumps (``tcg_gen_brcondi``) according to the
+value of an expression. Note, the tinycode generators we produce for conditional
+statements do not perfectly mirror what would be expected in C, for instance we
+do not reproduce short-circuiting of the ``&&`` operator, and use of the ``||``
+operator is disallowed. All the predicated instructions, and in general all the
+instructions where there could be alternative values assigned to an ``lvalue``,
+like C-style ternary expressions:
+
+::
+
+   rvalue            : rvalue QMARK rvalue COLON rvalue
+
+are handled using the conditional move tinycode instruction
+(``tcg_gen_movcond``), which avoids the additional complexity of managing labels
+and jumps.
+
+Instead, regarding the ``for`` loops, exploiting the fact that they always
+iterate on immediate values, therefore their iteration ranges are always known
+at compile time, we implemented those emitting plain C ``for`` loops. This is
+possible because the loops will be executed in the QEMU code, leading to the
+consequential unrolling of the for loop, since the tinycode generator
+instructions will be executed multiple times, and the respective generated
+tinycode will represent the unrolled execution of the loop.
+
+Parsing Context
+~~~~~~~~~~~~~~~
+
+All the helper functions in ``idef-parser.y`` carry two fixed parameters, which
+are the parsing context ``c`` and the ``YYLLOC`` location information. The
+context is explicitly passed to all the functions because the parser we generate
+is a reentrant one, meaning that it does not have any global variable, and
+therefore the instruction compilation could easily be parallelized in the
+future. Finally for each rule we propagate information about the location of the
+involved tokens to generate pretty error reporting, able to highlight the
+portion of the input code which generated each error.
+
+Debugging
+---------
+
+Developing the idef-parser can lead to two types of errors: compile-time errors
+and parsing errors.
+
+Compile-time errors in Bison-generated parsers are usually due to conflicts in
+the described grammar. Conflicts forbid the grammar to produce a unique
+derivation tree, thus must be solved (except for the dangling else problem,
+which is marked as expected through the ``%expect 1`` Bison option).
+
+For solving conflicts you need a basic understanding of `shift-reduce conflicts
+<https://www.gnu.org/software/Bison/manual/html_node/Shift_002fReduce.html>`__
+and `reduce-reduce conflicts
+<https://www.gnu.org/software/Bison/manual/html_node/Reduce_002fReduce.html>`__,
+then, if you are using a Bison version > 3.7.1 you can ask Bison to generate
+some counterexamples which highlight ambiguous derivations, passing the
+``-Wcex`` option to Bison. In general shift/reduce conflicts are solved by
+redesigning the grammar in an unambiguous way or by setting the token priority
+correctly, while reduce/reduce conflicts are solved by redesigning the
+interested part of the grammar.
+
+Run-time errors can be divided between lexing and parsing errors, lexing errors
+are hard to detect, since the ``var`` token will catch everything which is not
+catched by other tokens, but easy to fix, because most of the time a simple
+regex editing will be enough.
+
+idef-parser features a fancy parsing error reporting scheme, which for each
+parsing error reports the fragment of the input text which was involved in the
+parsing rule that generated an error.
+
+Implementing an instruction goes through several sequential steps, here are some
+suggestions to make each instruction proceed to the next step.
+
+-  not-emitted
+
+   Means that the parsing of the input code relative to that instruction failed,
+   this could be due to a lexical error or to some mismatch between the order of
+   valid tokens and a parser rule. You should check that tokens are correctly
+   identified and mapped, and that there is a rule matching the token sequence
+   that you need to parse.
+
+-  emitted
+
+   This instruction class contains all the instructions which are emitted but
+   fail to compile when included in QEMU. The compilation errors are shown by
+   the QEMU building process and will lead to fixing the bug.  Most common
+   errors regard the mismatch of parameters for tinycode generator functions,
+   which boil down to errors in the idef-parser type system.
+
+-  compiled
+
+   These instruction generate valid tinycode generator code, which however fail
+   the QEMU or the harness tests, these cases must be handled manually by
+   looking into the failing tests and looking at the generated tinycode
+   generator instruction and at the generated tinycode itself. Tip: handle the
+   failing harness tests first, because they usually feature only a single
+   instruction, thus will require less execution trace navigation. If a
+   multi-threaded test fail, fixing all the other tests will be the easier
+   option, hoping that the multi-threaded one will be indirectly fixed.
+
+   An example of debugging this type of failure is provided in the following
+   section.
+
+-  tests-passed
+
+   This is the final goal for each instruction, meaning that the instruction
+   passes the test suite.
+
+Another approach to fix QEMU system test, where many instructions might fail, is
+to compare the execution trace of your implementation with the reference
+implementations already present in QEMU. To do so you should obtain a QEMU build
+where the instruction pass the test, and run it with the following command:
+
+::
+
+   sudo unshare -p sudo -u <USER> bash -c \
+   'env -i <qemu-hexagon full path> -d cpu <TEST>'
+
+And do the same for your implementation, the generated execution traces will be
+inherently aligned and can be inspected for behavioral differences using the
+``diff`` tool.
+
+Example of debugging erroneous tinycode generator code
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The goal of this section is to provide a complete example of debugging
+incorrectly emitted tinycode generator for a single instruction.
+
+Let's first introduce a bug in the tinycode generator of the ``A2_add``
+instruction,
+
+::
+
+    void emit_A2_add(DisasContext *ctx, Insn *insn, Packet *pkt, TCGv_i32 RdV,
+                     TCGv_i32 RsV, TCGv_i32 RtV)
+    /*  RdV=RsV+RtV;} */
+    {
+        TCGv_i32 tmp_0 = tcg_temp_new_i32();
+        tcg_gen_add_i32(tmp_0, RsV, RsV);
+        tcg_gen_mov_i32(RdV, tmp_0);
+        tcg_temp_free_i32(tmp_0);
+    }
+
+Here the bug, albeit hard to spot, is in ``tcg_gen_add_i32(tmp_0, RsV, RsV);``
+where we compute ``RsV + RsV`` instead of ``RsV + RtV``, as would be expected.
+This particular bug is a bit tricky to pinpoint when debugging, since the
+``A2_add`` instruction is so ubiquitous. As a result, pretty much all tests will
+fail and therefore not provide a lot of information about the bug.
+
+For example, let's run the ``check-tcg`` tests
+
+::
+
+    make check-tcg TIMEOUT=1200 \
+                   DOCKER_IMAGE=debian-hexagon-cross \
+                   ENGINE=podman V=1 \
+                   DOCKER_CROSS_CC_GUEST=hexagon-unknown-linux-musl-clang
+
+In the output, we find a failure in the very first test case ``float_convs``
+due to a segmentation fault. Similarly, all harness and libc tests will fail as
+well. At this point we have no clue where the actual bug lies, and need to start
+ruling out instructions. As such a good starting point is to utilize the debug
+options ``-d in_asm,cpu`` of QEMU to inspect the Hexagon instructions being run,
+alongside the CPU state. We additionally need a working version of the emulator
+to compare our buggy CPU state against, running
+
+::
+
+    meson configure -Dhexagon_idef_parser_enabled=false
+
+will disable the idef-parser for all instructions and fallback on manual
+tinycode generator overrides, or on helper function implementations. Recompiling
+gives us ``qemu-hexagon`` which passes all tests. If ``qemu-heaxgon-buggy`` is
+our binary with the incorrect tinycode generators, we can compare the CPU state
+between the two versions
+
+::
+
+    ./qemu-hexagon-buggy -d in_asm,cpu float_convs &> out_buggy
+    ./qemu-hexagon       -d in_asm,cpu float_convs &> out_working
+
+Looking at ``diff -u out_buggy out_working`` shows us that the CPU state begins
+to diverge on line 141, with an incorrect value in the ``R1`` register
+
+::
+
+    @@ -138,7 +138,7 @@
+
+     General Purpose Registers = {
+       r0 = 0x4100f9c0
+    -  r1 = 0x00042108
+    +  r1 = 0x00000000
+       r2 = 0x00021084
+       r3 = 0x00000000
+       r4 = 0x00000000
+
+If we also look into ``out_buggy`` directly we can inspect the input assembly
+which the caused the incorrect CPU state, around line 141 we find
+
+::
+
+    116 |  ----------------
+    117 |  IN: _start_c
+    118 |  0x000210b0:  0xa09dc002	{	allocframe(R29,#0x10):raw }
+    ... |  ...
+    137 |  0x000210fc:  0x5a00c4aa	{	call PC+2388 }
+    138 |
+    139 |  General Purpose Registers = {
+    140 |    r0 = 0x4100fa70
+    141 |    r1 = 0x00042108
+    142 |    r2 = 0x00021084
+    143 |    r3 = 0x00000000
+
+Importantly, we see some Hexagon assembly followed by a dump of the CPU state,
+now the CPU state is actually dumped before the input assembly above is ran.
+As such, we are actually interested in the instructions ran before this.
+
+Scrolling up a bit, we find
+
+::
+
+    54 |  ----------------
+    55 |  IN: _start
+    56 |  0x00021088:  0x6a09c002	{	R2 = C9/pc }
+    57 |  0x0002108c:  0xbfe2ff82	{	R2 = add(R2,#0xfffffffc) }
+    58 |  0x00021090:  0x9182c001	{	R1 = memw(R2+#0x0) }
+    59 |  0x00021094:  0xf302c101	{	R1 = add(R2,R1) }
+    60 |  0x00021098:  0x7800c01e	{	R30 = #0x0 }
+    61 |  0x0002109c:  0x707dc000	{	R0 = R29 }
+    62 |  0x000210a0:  0x763dfe1d	{	R29 = and(R29,#0xfffffff0) }
+    63 |  0x000210a4:  0xa79dfdfe	{	memw(R29+#0xfffffff8) = R29 }
+    64 |  0x000210a8:  0xbffdff1d	{	R29 = add(R29,#0xfffffff8) }
+    65 |  0x000210ac:  0x5a00c002	{	call PC+4 }
+    66 |
+    67 |  General Purpose Registers = {
+    68 |    r0 = 0x00000000
+    69 |    r1 = 0x00000000
+    70 |    r2 = 0x00000000
+    71 |    r3 = 0x00000000
+
+Remember, the instructions on lines 56-65 are ran on the CPU state shown below
+instructions, and as the CPU state has not diverged at this point, we know the
+starting state is accurate. The bug must then lie within the instructions shown
+here. Next we may notice that ``R1`` is only touched by lines 57 and 58, that is
+by
+
+::
+
+    58 |  0x00021090:  0x9182c001	{	R1 = memw(R2+#0x0) }
+    59 |  0x00021094:  0xf302c101	{	R1 = add(R2,R1) }
+
+Therefore, we are either dealing with an correct load instruction
+``R1 = memw(R2+#0x0)`` or with an incorrect add ``R1 = add(R2,R1)``. At this
+point it might be easy enough to go directly to the emitted code for the
+instructions mentioned and look for bugs, but we could also run
+``./qemu-heaxgon -d op,in_asm float_conv`` where we find for the following
+tinycode for the Hexagon ``add`` instruction
+
+::
+
+   ---- 00021094
+   mov_i32 pkt_has_store_s1,$0x0
+   add_i32 tmp0,r2,r2
+   mov_i32 loc2,tmp0
+   mov_i32 new_r1,loc2
+   mov_i32 r1,new_r1
+
+Here we have finally located our bug ``add_i32 tmp0,r2,r2``.
+
+Limitations and Future Development
+----------------------------------
+
+The main limitation of the current parser is given by the syntax-driven nature
+of the Bison-generated parsers. This has the severe implication of only being
+able to generate code in the order of evaluation of the various rules, without,
+in any case, being able to backtrack and alter the generated code.
+
+An example limitation is highlighted by this statement of the input language:
+
+::
+
+   { (PsV==0xff) ? (PdV=0xff) : (PdV=0x00); }
+
+This ternary assignment, when written in this form requires us to emit some
+proper control flow statements, which emit a jump to the first or to the second
+code block, whose implementation is extremely convoluted, because when matching
+the ternary assignment, the code evaluating the two assignments will be already
+generated.
+
+Instead we pre-process that statement, making it become:
+
+::
+
+   { PdV = ((PsV==0xff)) ? 0xff : 0x00; }
+
+Which can be easily matched by the following parser rules:
+
+::
+
+   statement             | rvalue ';'
+
+   rvalue                : rvalue QMARK rvalue COLON rvalue
+                         | rvalue EQ rvalue
+                         | LPAR rvalue RPAR
+                         | assign_statement
+                         | IMM
+
+   assign_statement      : pred ASSIGN rvalue
+
+Another example that highlight the limitation of the flex/bison parser can be
+found even in the add operation we already saw:
+
+::
+
+   TCGv_i32 tmp_0 = tcg_temp_new_i32();
+   tcg_gen_add_i32(tmp_0, RsV, RtV);
+   tcg_gen_mov_i32(RdV, tmp_0);
+
+The fact that we cannot directly use ``RdV`` as the destination of the sum is a
+consequence of the syntax-driven nature of the parser. In fact when we parse the
+assignment, the ``rvalue`` token, representing the sum has already been reduced,
+and thus its code emitted and unchangeable. We rely on the fact that QEMU will
+optimize our code reducing the useless move operations and the relative
+temporaries.
+
+A possible improvement of the parser regards the support for vectorial
+instructions and floating point instructions, which will require the extension
+of the scanner, the parser, and a partial re-design of the type system, allowing
+to build the vectorial semantics over the available vectorial tinycode generator
+primitives.
+
+A more radical improvement will use the parser, not to generate directly the
+tinycode generator code, but to generate an intermediate representation like the
+LLVM IR, which in turn could be compiled using the clang TCG backend. That code
+could be furtherly optimized, overcoming the limitations of the syntax-driven
+parsing and could lead to a more optimized generated code.
-- 
2.33.1



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v7 03/13] target/hexagon: make slot number an unsigned
  2021-12-17  9:01 [PATCH v7 00/13] target/hexagon: introduce idef-parser Anton Johansson via
  2021-12-17  9:01 ` [PATCH v7 01/13] target/hexagon: update MAINTAINERS for idef-parser Anton Johansson via
  2021-12-17  9:01 ` [PATCH v7 02/13] target/hexagon: import README " Anton Johansson via
@ 2021-12-17  9:01 ` Anton Johansson via
  2021-12-22 21:47   ` Taylor Simpson
  2021-12-17  9:01 ` [PATCH v7 04/13] target/hexagon: make helper functions non-static Anton Johansson via
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 24+ messages in thread
From: Anton Johansson via @ 2021-12-17  9:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: ale, tsimpson, bcain, babush, nizzo, richard.henderson

From: Paolo Montesel <babush@rev.ng>

Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Paolo Montesel <babush@rev.ng>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/hexagon/genptr.c | 24 +++++++++++++-----------
 target/hexagon/macros.h |  2 +-
 2 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index 4419d30e23..2f73300c90 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -30,7 +30,8 @@
 #include "gen_tcg.h"
 #include "gen_tcg_hvx.h"
 
-static inline void gen_log_predicated_reg_write(int rnum, TCGv val, int slot)
+static inline void gen_log_predicated_reg_write(int rnum, TCGv val,
+                                                uint32_t slot)
 {
     TCGv zero = tcg_constant_tl(0);
     TCGv slot_mask = tcg_temp_new();
@@ -62,7 +63,8 @@ static inline void gen_log_reg_write(int rnum, TCGv val)
     }
 }
 
-static void gen_log_predicated_reg_write_pair(int rnum, TCGv_i64 val, int slot)
+static void gen_log_predicated_reg_write_pair(int rnum, TCGv_i64 val,
+                                              uint32_t slot)
 {
     TCGv val32 = tcg_temp_new();
     TCGv zero = tcg_constant_tl(0);
@@ -390,7 +392,7 @@ static inline void gen_store_conditional8(DisasContext *ctx,
     tcg_gen_movi_tl(hex_llsc_addr, ~0);
 }
 
-static inline void gen_store32(TCGv vaddr, TCGv src, int width, int slot)
+static inline void gen_store32(TCGv vaddr, TCGv src, int width, uint32_t slot)
 {
     tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
     tcg_gen_movi_tl(hex_store_width[slot], width);
@@ -398,49 +400,49 @@ static inline void gen_store32(TCGv vaddr, TCGv src, int width, int slot)
 }
 
 static inline void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src,
-                              DisasContext *ctx, int slot)
+                              DisasContext *ctx, uint32_t slot)
 {
     gen_store32(vaddr, src, 1, slot);
     ctx->store_width[slot] = 1;
 }
 
 static inline void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
-                               DisasContext *ctx, int slot)
+                               DisasContext *ctx, uint32_t slot)
 {
     TCGv tmp = tcg_constant_tl(src);
     gen_store1(cpu_env, vaddr, tmp, ctx, slot);
 }
 
 static inline void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src,
-                              DisasContext *ctx, int slot)
+                              DisasContext *ctx, uint32_t slot)
 {
     gen_store32(vaddr, src, 2, slot);
     ctx->store_width[slot] = 2;
 }
 
 static inline void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
-                               DisasContext *ctx, int slot)
+                               DisasContext *ctx, uint32_t slot)
 {
     TCGv tmp = tcg_constant_tl(src);
     gen_store2(cpu_env, vaddr, tmp, ctx, slot);
 }
 
 static inline void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src,
-                              DisasContext *ctx, int slot)
+                              DisasContext *ctx, uint32_t slot)
 {
     gen_store32(vaddr, src, 4, slot);
     ctx->store_width[slot] = 4;
 }
 
 static inline void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
-                               DisasContext *ctx, int slot)
+                               DisasContext *ctx, uint32_t slot)
 {
     TCGv tmp = tcg_constant_tl(src);
     gen_store4(cpu_env, vaddr, tmp, ctx, slot);
 }
 
 static inline void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src,
-                              DisasContext *ctx, int slot)
+                              DisasContext *ctx, uint32_t slot)
 {
     tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
     tcg_gen_movi_tl(hex_store_width[slot], 8);
@@ -449,7 +451,7 @@ static inline void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src,
 }
 
 static inline void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src,
-                               DisasContext *ctx, int slot)
+                               DisasContext *ctx, uint32_t slot)
 {
     TCGv_i64 tmp = tcg_constant_i64(src);
     gen_store8(cpu_env, vaddr, tmp, ctx, slot);
diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h
index 19d103cad5..3a64357090 100644
--- a/target/hexagon/macros.h
+++ b/target/hexagon/macros.h
@@ -185,7 +185,7 @@
 #define LOAD_CANCEL(EA) do { CANCEL; } while (0)
 
 #ifdef QEMU_GENERATE
-static inline void gen_pred_cancel(TCGv pred, int slot_num)
+static inline void gen_pred_cancel(TCGv pred, uint32_t slot_num)
  {
     TCGv slot_mask = tcg_temp_new();
     TCGv tmp = tcg_temp_new();
-- 
2.33.1



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v7 04/13] target/hexagon: make helper functions non-static
  2021-12-17  9:01 [PATCH v7 00/13] target/hexagon: introduce idef-parser Anton Johansson via
                   ` (2 preceding siblings ...)
  2021-12-17  9:01 ` [PATCH v7 03/13] target/hexagon: make slot number an unsigned Anton Johansson via
@ 2021-12-17  9:01 ` Anton Johansson via
  2021-12-17  9:01 ` [PATCH v7 05/13] target/hexagon: introduce new helper functions Anton Johansson via
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Anton Johansson via @ 2021-12-17  9:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: ale, tsimpson, bcain, babush, nizzo, richard.henderson

From: Paolo Montesel <babush@rev.ng>

Make certain helper functions non-static, making them available outside
genptr.c. These functions are required by code generated by the
idef-parser.

This commit also makes some op_helper.c non-static in order to avoid
having them marked as unused when using the idef-parser generated code.

Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Paolo Montesel <babush@rev.ng>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Taylor Simpson <tsimpson@quicinc.com>
---
 target/hexagon/genptr.c    | 59 +++++++++++++++++++++-----------------
 target/hexagon/genptr.h    | 30 +++++++++++++++++++
 target/hexagon/op_helper.c | 29 +++++++++----------
 target/hexagon/op_helper.h | 37 ++++++++++++++++++++++++
 4 files changed, 113 insertions(+), 42 deletions(-)
 create mode 100644 target/hexagon/op_helper.h

diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index 2f73300c90..ae798e921e 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -29,6 +29,13 @@
 #undef QEMU_GENERATE
 #include "gen_tcg.h"
 #include "gen_tcg_hvx.h"
+#include "genptr.h"
+
+TCGv gen_read_preg(TCGv pred, uint8_t num)
+{
+    tcg_gen_mov_tl(pred, hex_pred[num]);
+    return pred;
+}
 
 static inline void gen_log_predicated_reg_write(int rnum, TCGv val,
                                                 uint32_t slot)
@@ -54,7 +61,7 @@ static inline void gen_log_predicated_reg_write(int rnum, TCGv val,
     tcg_temp_free(slot_mask);
 }
 
-static inline void gen_log_reg_write(int rnum, TCGv val)
+void gen_log_reg_write(int rnum, TCGv val)
 {
     tcg_gen_mov_tl(hex_new_value[rnum], val);
     if (HEX_DEBUG) {
@@ -116,7 +123,7 @@ static void gen_log_reg_write_pair(int rnum, TCGv_i64 val)
     }
 }
 
-static inline void gen_log_pred_write(DisasContext *ctx, int pnum, TCGv val)
+void gen_log_pred_write(DisasContext *ctx, int pnum, TCGv val)
 {
     TCGv base_val = tcg_temp_new();
 
@@ -270,7 +277,7 @@ static inline void gen_write_ctrl_reg_pair(DisasContext *ctx, int reg_num,
     }
 }
 
-static TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign)
+TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign)
 {
     if (sign) {
         tcg_gen_sextract_tl(result, src, N * 8, 8);
@@ -280,7 +287,7 @@ static TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign)
     return result;
 }
 
-static TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign)
+TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign)
 {
     TCGv_i64 res64 = tcg_temp_new_i64();
     if (sign) {
@@ -294,7 +301,7 @@ static TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign)
     return result;
 }
 
-static inline TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign)
+TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign)
 {
     if (sign) {
         tcg_gen_sextract_tl(result, src, N * 16, 16);
@@ -304,12 +311,12 @@ static inline TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign)
     return result;
 }
 
-static inline void gen_set_half(int N, TCGv result, TCGv src)
+void gen_set_half(int N, TCGv result, TCGv src)
 {
     tcg_gen_deposit_tl(result, result, src, N * 16, 16);
 }
 
-static inline void gen_set_half_i64(int N, TCGv_i64 result, TCGv src)
+void gen_set_half_i64(int N, TCGv_i64 result, TCGv src)
 {
     TCGv_i64 src64 = tcg_temp_new_i64();
     tcg_gen_extu_i32_i64(src64, src);
@@ -317,7 +324,7 @@ static inline void gen_set_half_i64(int N, TCGv_i64 result, TCGv src)
     tcg_temp_free_i64(src64);
 }
 
-static void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src)
+void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src)
 {
     TCGv_i64 src64 = tcg_temp_new_i64();
     tcg_gen_extu_i32_i64(src64, src);
@@ -392,57 +399,57 @@ static inline void gen_store_conditional8(DisasContext *ctx,
     tcg_gen_movi_tl(hex_llsc_addr, ~0);
 }
 
-static inline void gen_store32(TCGv vaddr, TCGv src, int width, uint32_t slot)
+void gen_store32(TCGv vaddr, TCGv src, int width, uint32_t slot)
 {
     tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
     tcg_gen_movi_tl(hex_store_width[slot], width);
     tcg_gen_mov_tl(hex_store_val32[slot], src);
 }
 
-static inline void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src,
-                              DisasContext *ctx, uint32_t slot)
+void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
+                uint32_t slot)
 {
     gen_store32(vaddr, src, 1, slot);
     ctx->store_width[slot] = 1;
 }
 
-static inline void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
-                               DisasContext *ctx, uint32_t slot)
+void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src, DisasContext *ctx,
+                 uint32_t slot)
 {
     TCGv tmp = tcg_constant_tl(src);
     gen_store1(cpu_env, vaddr, tmp, ctx, slot);
 }
 
-static inline void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src,
-                              DisasContext *ctx, uint32_t slot)
+void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
+                uint32_t slot)
 {
     gen_store32(vaddr, src, 2, slot);
     ctx->store_width[slot] = 2;
 }
 
-static inline void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
-                               DisasContext *ctx, uint32_t slot)
+void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src, DisasContext *ctx,
+                 uint32_t slot)
 {
     TCGv tmp = tcg_constant_tl(src);
     gen_store2(cpu_env, vaddr, tmp, ctx, slot);
 }
 
-static inline void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src,
-                              DisasContext *ctx, uint32_t slot)
+void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
+                uint32_t slot)
 {
     gen_store32(vaddr, src, 4, slot);
     ctx->store_width[slot] = 4;
 }
 
-static inline void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
-                               DisasContext *ctx, uint32_t slot)
+void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src, DisasContext *ctx,
+                 uint32_t slot)
 {
     TCGv tmp = tcg_constant_tl(src);
     gen_store4(cpu_env, vaddr, tmp, ctx, slot);
 }
 
-static inline void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src,
-                              DisasContext *ctx, uint32_t slot)
+void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src, DisasContext *ctx,
+                uint32_t slot)
 {
     tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
     tcg_gen_movi_tl(hex_store_width[slot], 8);
@@ -450,14 +457,14 @@ static inline void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src,
     ctx->store_width[slot] = 8;
 }
 
-static inline void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src,
-                               DisasContext *ctx, uint32_t slot)
+void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src, DisasContext *ctx,
+                 uint32_t slot)
 {
     TCGv_i64 tmp = tcg_constant_i64(src);
     gen_store8(cpu_env, vaddr, tmp, ctx, slot);
 }
 
-static TCGv gen_8bitsof(TCGv result, TCGv value)
+TCGv gen_8bitsof(TCGv result, TCGv value)
 {
     TCGv zero = tcg_constant_tl(0);
     TCGv ones = tcg_constant_tl(0xff);
diff --git a/target/hexagon/genptr.h b/target/hexagon/genptr.h
index c158005d2a..d71dd7e1ce 100644
--- a/target/hexagon/genptr.h
+++ b/target/hexagon/genptr.h
@@ -19,7 +19,37 @@
 #define HEXAGON_GENPTR_H
 
 #include "insn.h"
+#include "tcg/tcg.h"
+#include "translate.h"
 
 extern const SemanticInsn opcode_genptr[];
 
+void gen_store32(TCGv vaddr, TCGv src, int width, uint32_t slot);
+void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
+                uint32_t slot);
+void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
+                uint32_t slot);
+void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
+                uint32_t slot);
+void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src, DisasContext *ctx,
+                uint32_t slot);
+void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src, DisasContext *ctx,
+                 uint32_t slot);
+void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src, DisasContext *ctx,
+                 uint32_t slot);
+void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src, DisasContext *ctx,
+                 uint32_t slot);
+void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src, DisasContext *ctx,
+                 uint32_t slot);
+TCGv gen_read_preg(TCGv pred, uint8_t num);
+void gen_log_reg_write(int rnum, TCGv val);
+void gen_log_pred_write(DisasContext *ctx, int pnum, TCGv val);
+TCGv gen_8bitsof(TCGv result, TCGv value);
+void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src);
+TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign);
+TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign);
+TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign);
+void gen_set_half(int N, TCGv result, TCGv src);
+void gen_set_half_i64(int N, TCGv_i64 result, TCGv src);
+
 #endif
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 057baf9a48..722a115007 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -29,6 +29,7 @@
 #include "fma_emu.h"
 #include "mmvec/mmvec.h"
 #include "mmvec/macros.h"
+#include "op_helper.h"
 
 #define SF_BIAS        127
 #define SF_MANTBITS    23
@@ -49,8 +50,8 @@ void QEMU_NORETURN HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp)
     do_raise_exception_err(env, excp, 0);
 }
 
-static void log_reg_write(CPUHexagonState *env, int rnum,
-                          target_ulong val, uint32_t slot)
+void log_reg_write(CPUHexagonState *env, int rnum, target_ulong val,
+                   uint32_t slot)
 {
     HEX_DEBUG_LOG("log_reg_write[%d] = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")",
                   rnum, val, val);
@@ -81,8 +82,8 @@ static void log_pred_write(CPUHexagonState *env, int pnum, target_ulong val)
     }
 }
 
-static void log_store32(CPUHexagonState *env, target_ulong addr,
-                        target_ulong val, int width, int slot)
+void log_store32(CPUHexagonState *env, target_ulong addr, target_ulong val,
+                 int width, int slot)
 {
     HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
                   ", %" PRId32 " [0x08%" PRIx32 "])\n",
@@ -92,8 +93,8 @@ static void log_store32(CPUHexagonState *env, target_ulong addr,
     env->mem_log_stores[slot].data32 = val;
 }
 
-static void log_store64(CPUHexagonState *env, target_ulong addr,
-                        int64_t val, int width, int slot)
+void log_store64(CPUHexagonState *env, target_ulong addr, int64_t val,
+                 int width, int slot)
 {
     HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
                   ", %" PRId64 " [0x016%" PRIx64 "])\n",
@@ -103,7 +104,7 @@ static void log_store64(CPUHexagonState *env, target_ulong addr,
     env->mem_log_stores[slot].data64 = val;
 }
 
-static void write_new_pc(CPUHexagonState *env, target_ulong addr)
+void write_new_pc(CPUHexagonState *env, target_ulong addr)
 {
     HEX_DEBUG_LOG("write_new_pc(0x" TARGET_FMT_lx ")\n", addr);
 
@@ -521,32 +522,28 @@ static void check_noshuf(CPUHexagonState *env, uint32_t slot)
     }
 }
 
-static uint8_t mem_load1(CPUHexagonState *env, uint32_t slot,
-                         target_ulong vaddr)
+uint8_t mem_load1(CPUHexagonState *env, uint32_t slot, target_ulong vaddr)
 {
     uintptr_t ra = GETPC();
     check_noshuf(env, slot);
     return cpu_ldub_data_ra(env, vaddr, ra);
 }
 
-static uint16_t mem_load2(CPUHexagonState *env, uint32_t slot,
-                          target_ulong vaddr)
+uint16_t mem_load2(CPUHexagonState *env, uint32_t slot, target_ulong vaddr)
 {
     uintptr_t ra = GETPC();
     check_noshuf(env, slot);
     return cpu_lduw_data_ra(env, vaddr, ra);
 }
 
-static uint32_t mem_load4(CPUHexagonState *env, uint32_t slot,
-                          target_ulong vaddr)
+uint32_t mem_load4(CPUHexagonState *env, uint32_t slot, target_ulong vaddr)
 {
     uintptr_t ra = GETPC();
     check_noshuf(env, slot);
     return cpu_ldl_data_ra(env, vaddr, ra);
 }
 
-static uint64_t mem_load8(CPUHexagonState *env, uint32_t slot,
-                          target_ulong vaddr)
+uint64_t mem_load8(CPUHexagonState *env, uint32_t slot, target_ulong vaddr)
 {
     uintptr_t ra = GETPC();
     check_noshuf(env, slot);
@@ -1459,7 +1456,7 @@ void HELPER(vwhist128qm)(CPUHexagonState *env, int32_t uiV)
     }
 }
 
-static void cancel_slot(CPUHexagonState *env, uint32_t slot)
+void cancel_slot(CPUHexagonState *env, uint32_t slot)
 {
     HEX_DEBUG_LOG("Slot %d cancelled\n", slot);
     env->slot_cancelled |= (1 << slot);
diff --git a/target/hexagon/op_helper.h b/target/hexagon/op_helper.h
new file mode 100644
index 0000000000..2d39637b8f
--- /dev/null
+++ b/target/hexagon/op_helper.h
@@ -0,0 +1,37 @@
+/*
+ *  Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HEXAGON_OP_HELPER_H
+#define HEXAGON_OP_HELPER_H
+
+/* Misc functions */
+void cancel_slot(CPUHexagonState *env, uint32_t slot);
+void write_new_pc(CPUHexagonState *env, target_ulong addr);
+
+uint8_t mem_load1(CPUHexagonState *env, uint32_t slot, target_ulong vaddr);
+uint16_t mem_load2(CPUHexagonState *env, uint32_t slot, target_ulong vaddr);
+uint32_t mem_load4(CPUHexagonState *env, uint32_t slot, target_ulong vaddr);
+uint64_t mem_load8(CPUHexagonState *env, uint32_t slot, target_ulong vaddr);
+
+void log_reg_write(CPUHexagonState *env, int rnum, target_ulong val,
+                   uint32_t slot);
+void log_store64(CPUHexagonState *env, target_ulong addr, int64_t val,
+                 int width, int slot);
+void log_store32(CPUHexagonState *env, target_ulong addr, target_ulong val,
+                 int width, int slot);
+
+#endif
-- 
2.33.1



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v7 05/13] target/hexagon: introduce new helper functions
  2021-12-17  9:01 [PATCH v7 00/13] target/hexagon: introduce idef-parser Anton Johansson via
                   ` (3 preceding siblings ...)
  2021-12-17  9:01 ` [PATCH v7 04/13] target/hexagon: make helper functions non-static Anton Johansson via
@ 2021-12-17  9:01 ` Anton Johansson via
  2021-12-21 18:51   ` Taylor Simpson
  2021-12-22 19:29   ` Taylor Simpson
  2021-12-17  9:01 ` [PATCH v7 06/13] target/hexagon: expose next PC in DisasContext Anton Johansson via
                   ` (7 subsequent siblings)
  12 siblings, 2 replies; 24+ messages in thread
From: Anton Johansson via @ 2021-12-17  9:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: ale, tsimpson, bcain, babush, nizzo, richard.henderson

From: Niccolò Izzo <nizzo@rev.ng>

These helpers will be employed by the idef-parser generated code.
"Helper" can here mean two things, a helper in the QEMU sense added to
`helper.h` and `op_helper.c`, but also helper functions providing a
manual TCG implementation of a certain features.

Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Niccolò Izzo <nizzo@rev.ng>
Signed-off-by: Anton Johansson <anjo@rev.ng>
---
 target/hexagon/genptr.c    | 166 +++++++++++++++++++++++++++++++++++--
 target/hexagon/genptr.h    |  16 +++-
 target/hexagon/helper.h    |   2 +
 target/hexagon/macros.h    |   9 ++
 target/hexagon/op_helper.c |  10 +++
 5 files changed, 195 insertions(+), 8 deletions(-)

diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index ae798e921e..44a1ec9ccf 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -31,6 +31,12 @@
 #include "gen_tcg_hvx.h"
 #include "genptr.h"
 
+TCGv gen_read_reg(TCGv result, int num)
+{
+    tcg_gen_mov_tl(result, hex_gpr[num]);
+    return result;
+}
+
 TCGv gen_read_preg(TCGv pred, uint8_t num)
 {
     tcg_gen_mov_tl(pred, hex_pred[num]);
@@ -399,18 +405,19 @@ static inline void gen_store_conditional8(DisasContext *ctx,
     tcg_gen_movi_tl(hex_llsc_addr, ~0);
 }
 
-void gen_store32(TCGv vaddr, TCGv src, int width, uint32_t slot)
+void gen_store32(DisasContext *ctx, TCGv vaddr, TCGv src, tcg_target_long width,
+                 uint32_t slot)
 {
     tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
     tcg_gen_movi_tl(hex_store_width[slot], width);
     tcg_gen_mov_tl(hex_store_val32[slot], src);
+    ctx->store_width[slot] = width;
 }
 
 void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
                 uint32_t slot)
 {
-    gen_store32(vaddr, src, 1, slot);
-    ctx->store_width[slot] = 1;
+    gen_store32(ctx, vaddr, src, 1, slot);
 }
 
 void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src, DisasContext *ctx,
@@ -423,8 +430,7 @@ void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src, DisasContext *ctx,
 void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
                 uint32_t slot)
 {
-    gen_store32(vaddr, src, 2, slot);
-    ctx->store_width[slot] = 2;
+    gen_store32(ctx, vaddr, src, 2, slot);
 }
 
 void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src, DisasContext *ctx,
@@ -437,8 +443,7 @@ void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src, DisasContext *ctx,
 void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
                 uint32_t slot)
 {
-    gen_store32(vaddr, src, 4, slot);
-    ctx->store_width[slot] = 4;
+    gen_store32(ctx, vaddr, src, 4, slot);
 }
 
 void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src, DisasContext *ctx,
@@ -643,5 +648,152 @@ static void vec_to_qvec(size_t size, intptr_t dstoff, intptr_t srcoff)
     tcg_temp_free_i64(mask);
 }
 
+void gen_set_usr_field(int field, TCGv val)
+{
+    tcg_gen_deposit_tl(hex_new_value[HEX_REG_USR], hex_new_value[HEX_REG_USR],
+                       val,
+                       reg_field_info[field].offset,
+                       reg_field_info[field].width);
+}
+
+void gen_set_usr_fieldi(int field, int x)
+{
+    TCGv val = tcg_const_tl(x);
+    gen_set_usr_field(field, val);
+    tcg_temp_free(val);
+}
+
+void gen_write_new_pc(TCGv addr)
+{
+    /* If there are multiple branches in a packet, ignore the second one */
+    TCGv zero = tcg_const_tl(0);
+    tcg_gen_movcond_tl(TCG_COND_NE, hex_next_PC, hex_branch_taken, zero,
+                       hex_next_PC, addr);
+    tcg_gen_movi_tl(hex_branch_taken, 1);
+    tcg_temp_free(zero);
+}
+
+void gen_sat_i32(TCGv dest, TCGv source, int width)
+{
+    TCGv max_val = tcg_const_tl((1 << (width - 1)) - 1);
+    TCGv min_val = tcg_const_tl(-(1 << (width - 1)));
+    tcg_gen_smin_tl(dest, source, max_val);
+    tcg_gen_smax_tl(dest, dest, min_val);
+    tcg_temp_free(max_val);
+    tcg_temp_free(min_val);
+}
+
+void gen_sat_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width)
+{
+    gen_sat_i32(dest, source, width);
+    tcg_gen_setcond_tl(TCG_COND_NE, ovfl, source, dest);
+}
+
+void gen_satu_i32(TCGv dest, TCGv source, int width)
+{
+    TCGv max_val = tcg_const_tl((1 << width) - 1);
+    tcg_gen_movcond_tl(TCG_COND_GTU, dest, source, max_val, max_val, source);
+    TCGv zero = tcg_const_tl(0);
+    tcg_gen_movcond_tl(TCG_COND_LT, dest, source, zero, zero, dest);
+    tcg_temp_free(max_val);
+    tcg_temp_free(zero);
+}
+
+void gen_satu_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width)
+{
+    gen_satu_i32(dest, source, width);
+    tcg_gen_setcond_tl(TCG_COND_NE, ovfl, source, dest);
+}
+
+void gen_sat_i64(TCGv_i64 dest, TCGv_i64 source, int width)
+{
+    TCGv_i64 max_val = tcg_const_i64((1 << (width - 1)) - 1);
+    TCGv_i64 min_val = tcg_const_i64(-(1 << (width - 1)));
+    tcg_gen_smin_i64(dest, source, max_val);
+    tcg_gen_smax_i64(dest, dest, min_val);
+    tcg_temp_free_i64(max_val);
+    tcg_temp_free_i64(min_val);
+}
+
+void gen_sat_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width)
+{
+    gen_sat_i64(dest, source, width);
+    TCGv_i64 ovfl_64 = tcg_temp_new_i64();
+    tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, dest, source);
+    tcg_gen_trunc_i64_tl(ovfl, ovfl_64);
+    tcg_temp_free_i64(ovfl_64);
+}
+
+void gen_satu_i64(TCGv_i64 dest, TCGv_i64 source, int width)
+{
+    TCGv_i64 max_val = tcg_const_i64((1 << width) - 1);
+    tcg_gen_movcond_i64(TCG_COND_GTU, dest, source, max_val, max_val, source);
+    TCGv_i64 zero = tcg_const_i64(0);
+    tcg_gen_movcond_i64(TCG_COND_LT, dest, source, zero, zero, dest);
+    tcg_temp_free_i64(max_val);
+    tcg_temp_free_i64(zero);
+}
+
+void gen_satu_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width)
+{
+    gen_sat_i64(dest, source, width);
+    TCGv_i64 ovfl_64 = tcg_temp_new_i64();
+    tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, dest, source);
+    tcg_gen_trunc_i64_tl(ovfl, ovfl_64);
+    tcg_temp_free_i64(ovfl_64);
+}
+
+/* Implements the fADDSAT64 macro in TCG */
+void gen_add_sat_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b)
+{
+    TCGv_i64 sum = tcg_temp_local_new_i64();
+    tcg_gen_add_i64(sum, a, b);
+
+    TCGv_i64 xor = tcg_temp_new_i64();
+    tcg_gen_xor_i64(xor, a, b);
+
+    TCGv_i64 mask = tcg_constant_i64(0x8000000000000000ULL);
+
+    TCGv_i64 cond1 = tcg_temp_local_new_i64();
+    tcg_gen_and_i64(cond1, xor, mask);
+    tcg_temp_free_i64(xor);
+
+    TCGv_i64 cond2 = tcg_temp_local_new_i64();
+    tcg_gen_xor_i64(cond2, a, sum);
+    tcg_gen_and_i64(cond2, cond2, mask);
+
+    TCGLabel *no_ovfl_label = gen_new_label();
+    TCGLabel *ovfl_label = gen_new_label();
+    TCGLabel *ret_label = gen_new_label();
+
+    tcg_gen_brcondi_i64(TCG_COND_NE, cond1, 0, no_ovfl_label);
+    tcg_temp_free_i64(cond1);
+    tcg_gen_brcondi_i64(TCG_COND_NE, cond2, 0, ovfl_label);
+    tcg_temp_free_i64(cond2);
+    tcg_gen_br(no_ovfl_label);
+
+    gen_set_label(no_ovfl_label);
+    tcg_gen_mov_i64(ret, sum);
+    tcg_gen_br(ret_label);
+
+    gen_set_label(ovfl_label);
+    TCGv_i64 cond3 = tcg_temp_new_i64();
+    tcg_gen_and_i64(cond3, sum, mask);
+    tcg_temp_free_i64(mask);
+    tcg_temp_free_i64(sum);
+    TCGv_i64 max_pos = tcg_constant_i64(0x7FFFFFFFFFFFFFFFLL);
+    TCGv_i64 max_neg = tcg_constant_i64(0x8000000000000000LL);
+    TCGv_i64 zero = tcg_constant_i64(0);
+    tcg_gen_movcond_i64(TCG_COND_NE, ret, cond3, zero, max_pos, max_neg);
+    tcg_temp_free_i64(max_pos);
+    tcg_temp_free_i64(max_neg);
+    tcg_temp_free_i64(zero);
+    tcg_temp_free_i64(cond3);
+    SET_USR_FIELD(USR_OVF, 1);
+    tcg_gen_br(ret_label);
+
+    gen_set_label(ret_label);
+}
+
 #include "tcg_funcs_generated.c.inc"
 #include "tcg_func_table_generated.c.inc"
diff --git a/target/hexagon/genptr.h b/target/hexagon/genptr.h
index d71dd7e1ce..e4e248d6f4 100644
--- a/target/hexagon/genptr.h
+++ b/target/hexagon/genptr.h
@@ -24,7 +24,8 @@
 
 extern const SemanticInsn opcode_genptr[];
 
-void gen_store32(TCGv vaddr, TCGv src, int width, uint32_t slot);
+void gen_store32(DisasContext *ctx, TCGv vaddr, TCGv src, tcg_target_long width,
+                 uint32_t slot);
 void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
                 uint32_t slot);
 void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
@@ -44,6 +45,18 @@ void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src, DisasContext *ctx,
 TCGv gen_read_preg(TCGv pred, uint8_t num);
 void gen_log_reg_write(int rnum, TCGv val);
 void gen_log_pred_write(DisasContext *ctx, int pnum, TCGv val);
+void gen_write_new_pc(TCGv addr);
+void gen_set_usr_field(int field, TCGv val);
+void gen_set_usr_fieldi(int field, int x);
+void gen_sat_i32(TCGv dest, TCGv source, int width);
+void gen_sat_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width);
+void gen_satu_i32(TCGv dest, TCGv source, int width);
+void gen_satu_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width);
+void gen_sat_i64(TCGv_i64 dest, TCGv_i64 source, int width);
+void gen_sat_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width);
+void gen_satu_i64(TCGv_i64 dest, TCGv_i64 source, int width);
+void gen_satu_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width);
+void gen_add_sat_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b);
 TCGv gen_8bitsof(TCGv result, TCGv value);
 void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src);
 TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign);
@@ -51,5 +64,6 @@ TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign);
 TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign);
 void gen_set_half(int N, TCGv result, TCGv src);
 void gen_set_half_i64(int N, TCGv_i64 result, TCGv src);
+TCGv gen_read_reg(TCGv result, int num);
 
 #endif
diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h
index c89aa4ed4d..506d4e11c3 100644
--- a/target/hexagon/helper.h
+++ b/target/hexagon/helper.h
@@ -27,6 +27,8 @@ DEF_HELPER_3(gather_store, void, env, i32, int)
 DEF_HELPER_1(commit_hvx_stores, void, env)
 DEF_HELPER_FLAGS_4(fcircadd, TCG_CALL_NO_RWG_SE, s32, s32, s32, s32, s32)
 DEF_HELPER_FLAGS_1(fbrev, TCG_CALL_NO_RWG_SE, i32, i32)
+DEF_HELPER_FLAGS_1(fbrev_32, TCG_CALL_NO_RWG_SE, i32, i32)
+DEF_HELPER_FLAGS_1(fbrev_64, TCG_CALL_NO_RWG_SE, i64, i64)
 DEF_HELPER_3(sfrecipa, i64, env, f32, f32)
 DEF_HELPER_2(sfinvsqrta, i64, env, f32)
 DEF_HELPER_4(vacsh_val, s64, env, s64, s64, s64)
diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h
index 3a64357090..2e2764ddc8 100644
--- a/target/hexagon/macros.h
+++ b/target/hexagon/macros.h
@@ -180,7 +180,16 @@
 #define MEM_STORE8(VA, DATA, SLOT) log_store64(env, VA, DATA, 8, SLOT)
 #endif
 
+#ifdef QEMU_GENERATE
+static inline void gen_cancel(uint32_t slot)
+{
+    tcg_gen_ori_tl(hex_slot_cancelled, hex_slot_cancelled, 1 << slot);
+}
+
+#define CANCEL gen_cancel(slot);
+#else
 #define CANCEL cancel_slot(env, slot)
+#endif
 
 #define LOAD_CANCEL(EA) do { CANCEL; } while (0)
 
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 722a115007..fc3844c8d1 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -341,6 +341,16 @@ uint32_t HELPER(fbrev)(uint32_t addr)
     return deposit32(addr, 0, 16, revbit16(addr));
 }
 
+uint32_t HELPER(fbrev_32)(uint32_t addr)
+{
+    return revbit32(addr);
+}
+
+uint64_t HELPER(fbrev_64)(uint64_t addr)
+{
+    return revbit64(addr);
+}
+
 static float32 build_float32(uint8_t sign, uint32_t exp, uint32_t mant)
 {
     return make_float32(
-- 
2.33.1



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v7 06/13] target/hexagon: expose next PC in DisasContext
  2021-12-17  9:01 [PATCH v7 00/13] target/hexagon: introduce idef-parser Anton Johansson via
                   ` (4 preceding siblings ...)
  2021-12-17  9:01 ` [PATCH v7 05/13] target/hexagon: introduce new helper functions Anton Johansson via
@ 2021-12-17  9:01 ` Anton Johansson via
  2021-12-17  9:01 ` [PATCH v7 07/13] target/hexagon: prepare input for the idef-parser Anton Johansson via
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Anton Johansson via @ 2021-12-17  9:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: ale, tsimpson, bcain, babush, nizzo, richard.henderson

From: Paolo Montesel <babush@rev.ng>

Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Paolo Montesel <babush@rev.ng>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Taylor Simpson <tsimpson@quicinc.com>
---
 target/hexagon/translate.c | 3 ++-
 target/hexagon/translate.h | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index b6f541ecb2..d4d4bcf3b2 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -741,11 +741,12 @@ static void decode_and_translate_packet(CPUHexagonState *env, DisasContext *ctx)
     if (decode_packet(nwords, words, &pkt, false) > 0) {
         HEX_DEBUG_PRINT_PKT(&pkt);
         gen_start_packet(ctx, &pkt);
+        ctx->npc = ctx->base.pc_next + pkt.encod_pkt_size_in_bytes;
         for (i = 0; i < pkt.num_insns; i++) {
             gen_insn(env, ctx, &pkt.insn[i], &pkt);
         }
         gen_commit_packet(env, ctx, &pkt);
-        ctx->base.pc_next += pkt.encod_pkt_size_in_bytes;
+        ctx->base.pc_next = ctx->npc;
     } else {
         gen_exception_end_tb(ctx, HEX_EXCP_INVALID_PACKET);
     }
diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h
index fccfb94340..0eb96b9621 100644
--- a/target/hexagon/translate.h
+++ b/target/hexagon/translate.h
@@ -52,6 +52,7 @@ typedef struct DisasContext {
     bool qreg_is_predicated[NUM_QREGS];
     int qreg_log_idx;
     bool pre_commit;
+    uint32_t npc;
 } DisasContext;
 
 static inline void ctx_log_reg_write(DisasContext *ctx, int rnum)
-- 
2.33.1



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v7 07/13] target/hexagon: prepare input for the idef-parser
  2021-12-17  9:01 [PATCH v7 00/13] target/hexagon: introduce idef-parser Anton Johansson via
                   ` (5 preceding siblings ...)
  2021-12-17  9:01 ` [PATCH v7 06/13] target/hexagon: expose next PC in DisasContext Anton Johansson via
@ 2021-12-17  9:01 ` Anton Johansson via
  2021-12-22 21:53   ` Taylor Simpson
  2021-12-23  1:53   ` Taylor Simpson
  2021-12-17  9:01 ` [PATCH v7 08/13] target/hexagon: import flex/bison to docker files Anton Johansson via
                   ` (5 subsequent siblings)
  12 siblings, 2 replies; 24+ messages in thread
From: Anton Johansson via @ 2021-12-17  9:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: ale, tsimpson, bcain, babush, nizzo, richard.henderson

From: Alessandro Di Federico <ale@rev.ng>

Introduce infrastructure necessary to produce a file suitable for being
parsed by the idef-parser.

Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Anton Johansson <anjo@rev.ng>
---
 target/hexagon/gen_idef_parser_funcs.py | 123 +++++++++++++++++++++
 target/hexagon/idef-parser/macros.inc   | 140 ++++++++++++++++++++++++
 target/hexagon/idef-parser/prepare      |  24 ++++
 target/hexagon/meson.build              |  16 +++
 4 files changed, 303 insertions(+)
 create mode 100644 target/hexagon/gen_idef_parser_funcs.py
 create mode 100644 target/hexagon/idef-parser/macros.inc
 create mode 100755 target/hexagon/idef-parser/prepare

diff --git a/target/hexagon/gen_idef_parser_funcs.py b/target/hexagon/gen_idef_parser_funcs.py
new file mode 100644
index 0000000000..b35dfcde5c
--- /dev/null
+++ b/target/hexagon/gen_idef_parser_funcs.py
@@ -0,0 +1,123 @@
+#!/usr/bin/env python3
+
+##
+##  Copyright(c) 2019-2021 rev.ng Labs Srl. All Rights Reserved.
+##
+##  This program is free software; you can redistribute it and/or modify
+##  it under the terms of the GNU General Public License as published by
+##  the Free Software Foundation; either version 2 of the License, or
+##  (at your option) any later version.
+##
+##  This program is distributed in the hope that it will be useful,
+##  but WITHOUT ANY WARRANTY; without even the implied warranty of
+##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+##  GNU General Public License for more details.
+##
+##  You should have received a copy of the GNU General Public License
+##  along with this program; if not, see <http://www.gnu.org/licenses/>.
+##
+
+import sys
+import re
+import string
+from io import StringIO
+
+import hex_common
+
+##
+## Generate code to be fed to the idef_parser
+##
+## Consider A2_add:
+##
+##     Rd32=add(Rs32,Rt32), { RdV=RsV+RtV;}
+##
+## We produce:
+##
+##     A2_add(RdV, in RsV, in RtV) {
+##       { RdV=RsV+RtV;}
+##     }
+##
+## A2_add represents the instruction tag. Then we have a list of TCGv
+## that the code generated by the parser can expect in input. Some of
+## them are inputs ("in" prefix), while some others are outputs.
+##
+def main():
+    hex_common.read_semantics_file(sys.argv[1])
+    hex_common.read_attribs_file(sys.argv[2])
+    hex_common.calculate_attribs()
+    tagregs = hex_common.get_tagregs()
+    tagimms = hex_common.get_tagimms()
+
+    with open(sys.argv[3], 'w') as f:
+        f.write('#include "macros.inc"\n\n')
+
+        for tag in hex_common.tags:
+            ## Skip the priv instructions
+            if ( "A_PRIV" in hex_common.attribdict[tag] ) :
+                continue
+            ## Skip the guest instructions
+            if ( "A_GUEST" in hex_common.attribdict[tag] ) :
+                continue
+            ## Skip instructions using switch
+            if ( tag in {'S4_vrcrotate_acc', 'S4_vrcrotate'} ) :
+                continue
+            ## Skip trap instructions
+            if ( tag in {'J2_trap0', 'J2_trap1'} ) :
+                continue
+            ## Skip 128-bit instructions
+            if ( tag in {'A7_croundd_ri', 'A7_croundd_rr'} ) :
+                continue
+            if ( tag in {'M7_wcmpyrw', 'M7_wcmpyrwc',
+                         'M7_wcmpyiw', 'M7_wcmpyiwc',
+                         'M7_wcmpyrw_rnd', 'M7_wcmpyrwc_rnd',
+                         'M7_wcmpyiw_rnd', 'M7_wcmpyiwc_rnd'} ) :
+                continue
+            ## Skip interleave/deinterleave instructions
+            if ( tag in {'S2_interleave', 'S2_deinterleave'} ) :
+                continue
+            ## Skip other unsupported instructions
+            if ( tag.startswith('S2_cabacdecbin') ) :
+                continue
+            if ( tag.startswith('A5_ACS') ) :
+                continue
+            if ( tag.startswith('Y') ) :
+                continue
+            if ( tag.startswith('V6_') ) :
+                continue
+            if ( tag.startswith('F') ) :
+                continue
+            if ( tag.endswith('_locked') ) :
+                continue
+
+            regs = tagregs[tag]
+            imms = tagimms[tag]
+
+            arguments = []
+            if hex_common.need_ea(tag):
+                arguments.append("EA")
+
+            for regtype,regid,toss,numregs in regs:
+                prefix = "in " if hex_common.is_read(regid) else ""
+
+                is_pair = hex_common.is_pair(regid)
+                is_single_old = (hex_common.is_single(regid)
+                                 and hex_common.is_old_val(regtype, regid, tag))
+                is_single_new = (hex_common.is_single(regid)
+                                 and hex_common.is_new_val(regtype, regid, tag))
+
+                if is_pair or is_single_old:
+                    arguments.append("%s%s%sV" % (prefix, regtype, regid))
+                elif is_single_new:
+                    arguments.append("%s%s%sN" % (prefix, regtype, regid))
+                else:
+                    print("Bad register parse: ",regtype,regid,toss,numregs)
+
+            for immlett,bits,immshift in imms:
+                arguments.append(hex_common.imm_name(immlett))
+
+            f.write("%s(%s) {\n" % (tag, ", ".join(arguments)))
+            f.write("    %s\n" % hex_common.semdict[tag])
+            f.write("}\n\n")
+
+if __name__ == "__main__":
+    main()
diff --git a/target/hexagon/idef-parser/macros.inc b/target/hexagon/idef-parser/macros.inc
new file mode 100644
index 0000000000..d25da360e8
--- /dev/null
+++ b/target/hexagon/idef-parser/macros.inc
@@ -0,0 +1,140 @@
+/*
+ * Copyright(c) 2019-2021 rev.ng Labs Srl. 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/>.
+ */
+
+/* Copy rules */
+#define fLSBOLD(VAL) (fGETBIT(0, VAL))
+#define fSATH(VAL) fSATN(16, VAL)
+#define fSATUH(VAL) fSATUN(16, VAL)
+#define fVSATH(VAL) fVSATN(16, VAL)
+#define fVSATUH(VAL) fVSATUN(16, VAL)
+#define fSATUB(VAL) fSATUN(8, VAL)
+#define fSATB(VAL) fSATN(8, VAL)
+#define fVSATUB(VAL) fVSATUN(8, VAL)
+#define fVSATB(VAL) fVSATN(8, VAL)
+#define fCALL(A) fWRITE_LR(fREAD_NPC()); fWRITE_NPC(A);
+#define fCALLR(A) fWRITE_LR(fREAD_NPC()); fWRITE_NPC(A);
+#define fCAST2_8s(A) fSXTN(16, 64, A)
+#define fCAST2_8u(A) fZXTN(16, 64, A)
+#define fVSATW(A) fVSATN(32, fCAST8_8s(A))
+#define fSATW(A) fSATN(32, fCAST8_8s(A))
+#define fVSAT(A) fVSATN(32, A)
+#define fSAT(A) fSATN(32, A)
+
+/* Ease parsing */
+#define f8BITSOF(VAL) ((VAL) ? 0xff : 0x00)
+#define fREAD_GP() (Constant_extended ? (0) : GP)
+#define fCLIP(DST, SRC, U) (DST = fMIN((1 << U) - 1, fMAX(SRC, -(1 << U))))
+#define fBIDIR_ASHIFTL(SRC, SHAMT, REGSTYPE)                            \
+    ((SHAMT > 0) ?                                                      \
+     (fCAST##REGSTYPE##s(SRC) << SHAMT) :                               \
+     (fCAST##REGSTYPE##s(SRC) >> -SHAMT))
+
+#define fBIDIR_LSHIFTL(SRC, SHAMT, REGSTYPE)    \
+    ((SHAMT > 0) ?                              \
+     (fCAST##REGSTYPE##u(SRC) << SHAMT) :       \
+     (fCAST##REGSTYPE##u(SRC) >>> -SHAMT))
+
+#define fBIDIR_ASHIFTR(SRC, SHAMT, REGSTYPE)    \
+    ((SHAMT > 0) ?                              \
+     (fCAST##REGSTYPE##s(SRC) >> SHAMT) :       \
+     (fCAST##REGSTYPE##s(SRC) << -SHAMT))
+
+#define fBIDIR_SHIFTR(SRC, SHAMT, REGSTYPE) \
+    (((SHAMT) < 0) ? ((fCAST##REGSTYPE(SRC) << ((-(SHAMT)) - 1)) << 1)  \
+                   : (fCAST##REGSTYPE(SRC) >> (SHAMT)))
+
+#define fBIDIR_LSHIFTR(SRC, SHAMT, REGSTYPE)                            \
+    fBIDIR_SHIFTR(SRC, SHAMT, REGSTYPE##u)
+
+#define fSATVALN(N, VAL)                                                \
+    fSET_OVERFLOW(                                                      \
+        ((VAL) < 0) ? (-(1LL << ((N) - 1))) : ((1LL << ((N) - 1)) - 1)  \
+    )
+
+#define fSAT_ORIG_SHL(A, ORIG_REG)                                      \
+    (((fCAST4s((fSAT(A)) ^ (fCAST4s(ORIG_REG)))) < 0)                   \
+        ? fSATVALN(32, (fCAST4s(ORIG_REG)))                             \
+        : ((((ORIG_REG) > 0) && ((A) == 0)) ? fSATVALN(32, (ORIG_REG))  \
+                                            : fSAT(A)))
+
+#define fBIDIR_ASHIFTR_SAT(SRC, SHAMT, REGSTYPE)                        \
+    (((SHAMT) < 0) ? fSAT_ORIG_SHL((fCAST##REGSTYPE##s(SRC)             \
+                        << ((-(SHAMT)) - 1)) << 1, (SRC))               \
+                   : (fCAST##REGSTYPE##s(SRC) >> (SHAMT)))
+
+#define fBIDIR_ASHIFTL_SAT(SRC, SHAMT, REGSTYPE)                        \
+    (((SHAMT) < 0)                                                      \
+     ? ((fCAST##REGSTYPE##s(SRC) >> ((-(SHAMT)) - 1)) >> 1)             \
+     : fSAT_ORIG_SHL(fCAST##REGSTYPE##s(SRC) << (SHAMT), (SRC)))
+
+#define fEXTRACTU_BIDIR(INREG, WIDTH, OFFSET)                           \
+    (fZXTN(WIDTH, 32, fBIDIR_LSHIFTR((INREG), (OFFSET), 4_8)))
+
+/* Least significant bit operations */
+#define fLSBNEW0 fLSBNEW(P0N)
+#define fLSBNEW1 fLSBNEW(P1N)
+#define fLSBOLDNOT(VAL) fGETBIT(0, ~VAL)
+#define fLSBNEWNOT(PRED) (fLSBNEW(~PRED))
+#define fLSBNEW0NOT fLSBNEW(~P0N)
+#define fLSBNEW1NOT fLSBNEW(~P1N)
+
+/* Assignments */
+#define fPCALIGN(IMM) (IMM = IMM & ~3)
+#define fWRITE_LR(A) (LR = A)
+#define fWRITE_FP(A) (FP = A)
+#define fWRITE_SP(A) (SP = A)
+/*
+ * Note: There is a rule in the parser that matches `PC = ...` and emits
+ * a call to `gen_write_new_pc`. We need to call `gen_write_new_pc` to
+ * get the correct semantics when there are multiple stores in a packet.
+ */
+#define fBRANCH(LOC, TYPE) (PC = LOC)
+#define fJUMPR(REGNO, TARGET, TYPE) (PC = TARGET)
+#define fWRITE_LOOP_REGS0(START, COUNT) SA0 = START; (LC0 = COUNT)
+#define fWRITE_LOOP_REGS1(START, COUNT) SA1 = START; (LC1 = COUNT)
+#define fWRITE_LC0(VAL) (LC0 = VAL)
+#define fWRITE_LC1(VAL) (LC1 = VAL)
+#define fSET_LPCFG(VAL) (USR.LPCFG = VAL)
+#define fWRITE_P0(VAL) P0 = VAL;
+#define fWRITE_P1(VAL) P1 = VAL;
+#define fWRITE_P3(VAL) P3 = VAL;
+#define fEA_RI(REG, IMM) (EA = REG + IMM)
+#define fEA_RRs(REG, REG2, SCALE) (EA = REG + (REG2 << SCALE))
+#define fEA_IRs(IMM, REG, SCALE) (EA = IMM + (REG << SCALE))
+#define fEA_IMM(IMM) (EA = IMM)
+#define fEA_REG(REG) (EA = REG)
+#define fEA_BREVR(REG) (EA = fbrev(REG))
+#define fEA_GPI(IMM) (EA = fREAD_GP() + IMM)
+#define fPM_I(REG, IMM) (REG = REG + IMM)
+#define fPM_M(REG, MVAL) (REG = REG + MVAL)
+#define fWRITE_NPC(VAL) (PC = VAL)
+
+/* Unary operators */
+#define fROUND(A) (A + 0x8000)
+
+/* Binary operators */
+#define fSCALE(N, A) (A << N)
+#define fASHIFTR(SRC, SHAMT, REGSTYPE) (fCAST##REGSTYPE##s(SRC) >> SHAMT)
+#define fLSHIFTR(SRC, SHAMT, REGSTYPE) (SRC >>> SHAMT)
+#define fROTL(SRC, SHAMT, REGSTYPE) fROTL(SRC, SHAMT)
+#define fASHIFTL(SRC, SHAMT, REGSTYPE) (fCAST##REGSTYPE##s(SRC) << SHAMT)
+
+/* Include fHIDE macros which hide type declarations */
+#define fHIDE(A) A
+
+/* Purge non-relavant parts */
+#define fBRANCH_SPECULATE_STALL(A, B, C, D, E)
diff --git a/target/hexagon/idef-parser/prepare b/target/hexagon/idef-parser/prepare
new file mode 100755
index 0000000000..6377513dc5
--- /dev/null
+++ b/target/hexagon/idef-parser/prepare
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+#
+# Copyright(c) 2019-2021 rev.ng Labs Srl. 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/>.
+#
+
+set -e
+set -o pipefail
+
+# Run the preprocessor and drop comments
+cpp "$@"
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index b61243103f..236c3a3ffa 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -21,6 +21,7 @@ hex_common_py = 'hex_common.py'
 attribs_def = meson.current_source_dir() / 'attribs_def.h.inc'
 gen_tcg_h = meson.current_source_dir() / 'gen_tcg.h'
 gen_tcg_hvx_h = meson.current_source_dir() / 'gen_tcg_hvx.h'
+idef_parser_dir = meson.current_source_dir() / 'idef-parser'
 
 #
 #  Step 1
@@ -179,4 +180,19 @@ hexagon_ss.add(files(
     'mmvec/system_ext_mmvec.c',
 ))
 
+idef_parser_input_generated = custom_target(
+    'idef_parser_input.h.inc',
+    output: 'idef_parser_input.h.inc',
+    depends: [semantics_generated],
+    depend_files: [hex_common_py],
+    command: [python, files('gen_idef_parser_funcs.py'), semantics_generated, attribs_def, '@OUTPUT@'],
+)
+
+idef_parser_input_generated_prep = custom_target(
+    'idef_parser_input.preprocessed.h.inc',
+    output: 'idef_parser_input.preprocessed.h.inc',
+    input: idef_parser_input_generated,
+    command: [idef_parser_dir / 'prepare', '@INPUT@', '-I' + idef_parser_dir, '-o', '@OUTPUT@'],
+)
+
 target_arch += {'hexagon': hexagon_ss}
-- 
2.33.1



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v7 08/13] target/hexagon: import flex/bison to docker files
  2021-12-17  9:01 [PATCH v7 00/13] target/hexagon: introduce idef-parser Anton Johansson via
                   ` (6 preceding siblings ...)
  2021-12-17  9:01 ` [PATCH v7 07/13] target/hexagon: prepare input for the idef-parser Anton Johansson via
@ 2021-12-17  9:01 ` Anton Johansson via
  2021-12-17  9:01 ` [PATCH v7 09/13] target/hexagon: import lexer for idef-parser Anton Johansson via
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Anton Johansson via @ 2021-12-17  9:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: ale, tsimpson, bcain, babush, nizzo, richard.henderson

From: Paolo Montesel <babush@rev.ng>

Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Paolo Montesel <babush@rev.ng>
Signed-off-by: Anton Johansson <anjo@rev.ng>
---
 .gitlab-ci.d/windows.yml                             | 2 ++
 tests/docker/dockerfiles/alpine.docker               | 2 ++
 tests/docker/dockerfiles/centos8.docker              | 2 ++
 tests/docker/dockerfiles/debian-amd64.docker         | 2 ++
 tests/docker/dockerfiles/debian-native.docker        | 3 +++
 tests/docker/dockerfiles/debian-riscv64-cross.docker | 3 +++
 tests/docker/dockerfiles/debian-tricore-cross.docker | 2 ++
 tests/docker/dockerfiles/debian10.docker             | 3 +++
 tests/docker/dockerfiles/fedora-i386-cross.docker    | 3 +++
 tests/docker/dockerfiles/fedora-win32-cross.docker   | 3 +++
 tests/docker/dockerfiles/fedora-win64-cross.docker   | 3 +++
 tests/docker/dockerfiles/fedora.docker               | 2 ++
 tests/docker/dockerfiles/opensuse-leap.docker        | 2 ++
 tests/docker/dockerfiles/ubuntu.docker               | 3 +++
 tests/docker/dockerfiles/ubuntu1804.docker           | 2 ++
 tests/docker/dockerfiles/ubuntu2004.docker           | 2 ++
 16 files changed, 39 insertions(+)

diff --git a/.gitlab-ci.d/windows.yml b/.gitlab-ci.d/windows.yml
index 309f7e7fb8..2abfe4e91a 100644
--- a/.gitlab-ci.d/windows.yml
+++ b/.gitlab-ci.d/windows.yml
@@ -33,6 +33,7 @@ msys2-64bit:
   script:
   - .\msys64\usr\bin\bash -lc "pacman -Sy --noconfirm --needed
       diffutils git grep make sed
+      flex bison
       mingw-w64-x86_64-capstone
       mingw-w64-x86_64-curl
       mingw-w64-x86_64-cyrus-sasl
@@ -68,6 +69,7 @@ msys2-32bit:
   script:
   - .\msys64\usr\bin\bash -lc "pacman -Sy --noconfirm --needed
       diffutils git grep make sed
+      flex bison
       mingw-w64-i686-capstone
       mingw-w64-i686-curl
       mingw-w64-i686-cyrus-sasl
diff --git a/tests/docker/dockerfiles/alpine.docker b/tests/docker/dockerfiles/alpine.docker
index 7e6997e301..45db55ba55 100644
--- a/tests/docker/dockerfiles/alpine.docker
+++ b/tests/docker/dockerfiles/alpine.docker
@@ -9,9 +9,11 @@ ENV PACKAGES \
 	alsa-lib-dev \
 	bash \
 	binutils \
+	bison \
 	ccache \
 	coreutils \
 	curl-dev \
+	flex \
 	g++ \
 	gcc \
 	git \
diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker
index 7f135f8e8c..d93bbe3002 100644
--- a/tests/docker/dockerfiles/centos8.docker
+++ b/tests/docker/dockerfiles/centos8.docker
@@ -5,6 +5,7 @@ ENV PACKAGES \
     SDL2-devel \
     alsa-lib-devel \
     bc \
+    bison \
     brlapi-devel \
     bzip2 \
     bzip2-devel \
@@ -19,6 +20,7 @@ ENV PACKAGES \
     device-mapper-multipath-devel \
     diffutils \
     findutils \
+    flex \
     gcc \
     gcc-c++ \
     genisoimage \
diff --git a/tests/docker/dockerfiles/debian-amd64.docker b/tests/docker/dockerfiles/debian-amd64.docker
index ed546edcd6..805fd6f981 100644
--- a/tests/docker/dockerfiles/debian-amd64.docker
+++ b/tests/docker/dockerfiles/debian-amd64.docker
@@ -14,9 +14,11 @@ RUN apt update && \
 RUN apt update && \
     DEBIAN_FRONTEND=noninteractive eatmydata \
     apt install -y --no-install-recommends \
+        bison \
         cscope \
         genisoimage \
         exuberant-ctags \
+        flex \
         global \
         libbz2-dev \
         liblzo2-dev \
diff --git a/tests/docker/dockerfiles/debian-native.docker b/tests/docker/dockerfiles/debian-native.docker
index efd55cb6e0..02ccaf98fd 100644
--- a/tests/docker/dockerfiles/debian-native.docker
+++ b/tests/docker/dockerfiles/debian-native.docker
@@ -26,13 +26,16 @@ RUN apt update && \
 RUN apt update && \
     DEBIAN_FRONTEND=noninteractive eatmydata \
     apt install -y --no-install-recommends \
+        bison \
         cscope \
         genisoimage \
         exuberant-ctags \
+        flex \
         global \
         libbz2-dev \
         liblzo2-dev \
         libgcrypt20-dev \
+        libglib2.0-dev \
         libfdt-dev \
         librdmacm-dev \
         libsasl2-dev \
diff --git a/tests/docker/dockerfiles/debian-riscv64-cross.docker b/tests/docker/dockerfiles/debian-riscv64-cross.docker
index 594d97982c..f5553afc2e 100644
--- a/tests/docker/dockerfiles/debian-riscv64-cross.docker
+++ b/tests/docker/dockerfiles/debian-riscv64-cross.docker
@@ -17,12 +17,15 @@ RUN apt update && \
 # Install common build utilities
 RUN DEBIAN_FRONTEND=noninteractive eatmydata apt install -yy \
     bc \
+    bison \
     build-essential \
     ca-certificates \
     debian-ports-archive-keyring \
     dpkg-dev \
+    flex \
     gettext \
     git \
+    libglib2.0-dev \
     ninja-build \
     pkg-config \
     python3
diff --git a/tests/docker/dockerfiles/debian-tricore-cross.docker b/tests/docker/dockerfiles/debian-tricore-cross.docker
index d8df2c6117..9191aafc7f 100644
--- a/tests/docker/dockerfiles/debian-tricore-cross.docker
+++ b/tests/docker/dockerfiles/debian-tricore-cross.docker
@@ -16,9 +16,11 @@ MAINTAINER Philippe Mathieu-Daudé <f4bug@amsat.org>
 RUN apt update && \
     DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \
     DEBIAN_FRONTEND=noninteractive eatmydata apt install -yy \
+       bison \
        bzip2 \
        ca-certificates \
        ccache \
+       flex \
        g++ \
        gcc \
        git \
diff --git a/tests/docker/dockerfiles/debian10.docker b/tests/docker/dockerfiles/debian10.docker
index b414af1b9f..06b8d9d6b0 100644
--- a/tests/docker/dockerfiles/debian10.docker
+++ b/tests/docker/dockerfiles/debian10.docker
@@ -17,16 +17,19 @@ 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 \
         ccache \
         clang \
         dbus \
+        flex \
         gdb-multiarch \
         gettext \
         git \
         libffi-dev \
+        libglib2.0-dev \
         libncurses5-dev \
         ninja-build \
         pkg-config \
diff --git a/tests/docker/dockerfiles/fedora-i386-cross.docker b/tests/docker/dockerfiles/fedora-i386-cross.docker
index 13328e6081..ae009a203f 100644
--- a/tests/docker/dockerfiles/fedora-i386-cross.docker
+++ b/tests/docker/dockerfiles/fedora-i386-cross.docker
@@ -1,12 +1,15 @@
 FROM registry.fedoraproject.org/fedora:34
 
 ENV PACKAGES \
+    bison \
     bzip2 \
     ccache \
     diffutils \
     findutils \
+    flex \
     gcc \
     git \
+    glib2-devel \
     libffi-devel.i686 \
     libselinux-devel.i686 \
     libtasn1-devel.i686 \
diff --git a/tests/docker/dockerfiles/fedora-win32-cross.docker b/tests/docker/dockerfiles/fedora-win32-cross.docker
index aad39dd97f..9ae8eda39f 100644
--- a/tests/docker/dockerfiles/fedora-win32-cross.docker
+++ b/tests/docker/dockerfiles/fedora-win32-cross.docker
@@ -2,14 +2,17 @@ FROM registry.fedoraproject.org/fedora:33
 
 # Please keep this list sorted alphabetically
 ENV PACKAGES \
+    bison \
     bc \
     bzip2 \
     ccache \
     diffutils \
     findutils \
+    flex \
     gcc \
     gettext \
     git \
+    glib2-devel \
     hostname \
     make \
     meson \
diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker
index 9a224a619b..c59a130d00 100644
--- a/tests/docker/dockerfiles/fedora-win64-cross.docker
+++ b/tests/docker/dockerfiles/fedora-win64-cross.docker
@@ -2,13 +2,16 @@ FROM registry.fedoraproject.org/fedora:33
 
 # Please keep this list sorted alphabetically
 ENV PACKAGES \
+    bison \
     bc \
     bzip2 \
     ccache \
     diffutils \
     findutils \
+    flex \
     gcc \
     gettext \
+    glib2-devel \
     git \
     hostname \
     make \
diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker
index c6fd7e1113..b19ef01bf7 100644
--- a/tests/docker/dockerfiles/fedora.docker
+++ b/tests/docker/dockerfiles/fedora.docker
@@ -2,6 +2,7 @@ FROM registry.fedoraproject.org/fedora:33
 
 # Please keep this list sorted alphabetically
 ENV PACKAGES \
+    bison \
     SDL2-devel \
     SDL2_image-devel \
     alsa-lib-devel \
@@ -20,6 +21,7 @@ ENV PACKAGES \
     device-mapper-multipath-devel \
     diffutils \
     findutils \
+    flex \
     gcc \
     gcc-c++ \
     gcovr \
diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker
index 3bbdb67f4f..b868ca7198 100644
--- a/tests/docker/dockerfiles/opensuse-leap.docker
+++ b/tests/docker/dockerfiles/opensuse-leap.docker
@@ -5,6 +5,7 @@ ENV PACKAGES \
     Mesa-devel \
     alsa-lib-devel \
     bc \
+    bison \
     brlapi-devel \
     bzip2 \
     ca-certificates \
@@ -15,6 +16,7 @@ ENV PACKAGES \
     dbus-1 \
     diffutils \
     findutils \
+    flex \
     gcc \
     gcc-c++ \
     gcovr \
diff --git a/tests/docker/dockerfiles/ubuntu.docker b/tests/docker/dockerfiles/ubuntu.docker
index f0e0180d21..5667ef592c 100644
--- a/tests/docker/dockerfiles/ubuntu.docker
+++ b/tests/docker/dockerfiles/ubuntu.docker
@@ -11,9 +11,11 @@
 
 FROM docker.io/library/ubuntu:20.04
 ENV PACKAGES \
+    bison \
     ccache \
     clang \
     dbus \
+    flex \
     gcc \
     gettext \
     git \
@@ -30,6 +32,7 @@ ENV PACKAGES \
     libfdt-dev \
     libffi-dev \
     libgbm-dev \
+    libglib2.0-dev \
     libgnutls28-dev \
     libgtk-3-dev \
     libibverbs-dev \
diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker
index 450fd06d0d..ce7d15c03e 100644
--- a/tests/docker/dockerfiles/ubuntu1804.docker
+++ b/tests/docker/dockerfiles/ubuntu1804.docker
@@ -1,6 +1,7 @@
 FROM docker.io/library/ubuntu:18.04
 ENV PACKAGES \
     bc \
+    bison \
     bsdmainutils \
     bzip2 \
     ca-certificates \
@@ -11,6 +12,7 @@ ENV PACKAGES \
     diffutils \
     exuberant-ctags \
     findutils \
+    flex \
     g++ \
     gcc \
     gcovr \
diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker
index 15a026be09..d39d4ea07f 100644
--- a/tests/docker/dockerfiles/ubuntu2004.docker
+++ b/tests/docker/dockerfiles/ubuntu2004.docker
@@ -1,5 +1,6 @@
 FROM docker.io/library/ubuntu:20.04
 ENV PACKAGES \
+    bison \
     bc \
     bsdmainutils \
     bzip2 \
@@ -11,6 +12,7 @@ ENV PACKAGES \
     diffutils \
     exuberant-ctags \
     findutils \
+    flex \
     g++ \
     gcc \
     gcovr \
-- 
2.33.1



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v7 09/13] target/hexagon: import lexer for idef-parser
  2021-12-17  9:01 [PATCH v7 00/13] target/hexagon: introduce idef-parser Anton Johansson via
                   ` (7 preceding siblings ...)
  2021-12-17  9:01 ` [PATCH v7 08/13] target/hexagon: import flex/bison to docker files Anton Johansson via
@ 2021-12-17  9:01 ` Anton Johansson via
  2021-12-21 18:48   ` Taylor Simpson
  2021-12-17  9:01 ` [PATCH v7 10/13] target/hexagon: import parser " Anton Johansson via
                   ` (3 subsequent siblings)
  12 siblings, 1 reply; 24+ messages in thread
From: Anton Johansson via @ 2021-12-17  9:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: ale, tsimpson, bcain, babush, nizzo, richard.henderson

From: Paolo Montesel <babush@rev.ng>

Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Paolo Montesel <babush@rev.ng>
Signed-off-by: Anton Johansson <anjo@rev.ng>
---
 target/hexagon/idef-parser/idef-parser.h   | 259 ++++++++++
 target/hexagon/idef-parser/idef-parser.lex | 571 +++++++++++++++++++++
 target/hexagon/meson.build                 |   4 +
 3 files changed, 834 insertions(+)
 create mode 100644 target/hexagon/idef-parser/idef-parser.h
 create mode 100644 target/hexagon/idef-parser/idef-parser.lex

diff --git a/target/hexagon/idef-parser/idef-parser.h b/target/hexagon/idef-parser/idef-parser.h
new file mode 100644
index 0000000000..d361ee7e53
--- /dev/null
+++ b/target/hexagon/idef-parser/idef-parser.h
@@ -0,0 +1,259 @@
+/*
+ * Copyright(c) 2019-2021 rev.ng Labs Srl. 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
+ * 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 IDEF_PARSER_H
+#define IDEF_PARSER_H
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <glib.h>
+
+#define TCGV_NAME_SIZE 7
+#define MAX_WRITTEN_REGS 32
+#define OFFSET_STR_LEN 32
+#define ALLOC_LIST_LEN 32
+#define ALLOC_NAME_SIZE 32
+#define INIT_LIST_LEN 32
+#define OUT_BUF_LEN (1024 * 1024)
+#define SIGNATURE_BUF_LEN (128 * 1024)
+#define HEADER_BUF_LEN (128 * 1024)
+
+/* Variadic macros to wrap the buffer printing functions */
+#define EMIT(c, ...)                                                 \
+    do {                                                             \
+        g_string_append_printf((c)->out_str, __VA_ARGS__);           \
+    } while (0)
+
+#define EMIT_SIG(c, ...)                                                       \
+    do {                                                                       \
+        g_string_append_printf((c)->signature_str, __VA_ARGS__);               \
+    } while (0)
+
+#define EMIT_HEAD(c, ...)                                                      \
+    do {                                                                       \
+        g_string_append_printf((c)->header_str, __VA_ARGS__);                  \
+    } while (0)
+
+/**
+ * Type of register, assigned to the HexReg.type field
+ */
+typedef enum { GENERAL_PURPOSE, CONTROL, MODIFIER, DOTNEW } HexRegType;
+
+typedef enum { UNKNOWN_SIGNEDNESS, SIGNED, UNSIGNED } HexSignedness;
+
+/**
+ * Semantic record of the REG tokens, identifying registers
+ */
+typedef struct HexReg {
+    uint8_t id;             /**< Identifier of the register                  */
+    HexRegType type;        /**< Type of the register                        */
+    unsigned bit_width;     /**< Bit width of the reg, 32 or 64 bits         */
+} HexReg;
+
+/**
+ * Data structure, identifying a TCGv temporary value
+ */
+typedef struct HexTmp {
+    int index;              /**< Index of the TCGv temporary value    */
+} HexTmp;
+
+/**
+ * Enum of the possible immediated, an immediate is a value which is known
+ * at tinycode generation time, e.g. an integer value, not a TCGv
+ */
+enum ImmUnionTag {
+    I,
+    VARIABLE,
+    VALUE,
+    QEMU_TMP,
+    IMM_PC,
+    IMM_NPC,
+    IMM_CONSTEXT,
+};
+
+/**
+ * Semantic record of the IMM token, identifying an immediate constant
+ */
+typedef struct HexImm {
+    union {
+        char id;            /**< Identifier of the immediate                 */
+        uint64_t value;     /**< Immediate value (for VALUE type immediates) */
+        uint64_t index;     /**< Index of the immediate (for int temp vars)  */
+    };
+    enum ImmUnionTag type;  /**< Type of the immediate                       */
+} HexImm;
+
+/**
+ * Semantic record of the PRED token, identifying a predicate
+ */
+typedef struct HexPred {
+    char id;                /**< Identifier of the predicate                 */
+} HexPred;
+
+/**
+ * Semantic record of the SAT token, identifying the saturate operator
+ */
+typedef struct HexSat {
+    bool set_overflow;       /**< Set-overflow feature for the sat operator  */
+    HexSignedness signedness;/**< Unsigned flag for the saturate operator    */
+} HexSat;
+
+/**
+ * Semantic record of the CAST token, identifying the cast operator
+ */
+typedef struct HexCast {
+    int bit_width;            /**< Bit width of the cast operator             */
+    HexSignedness signedness; /**< Unsigned flag for the cast operator        */
+} HexCast;
+
+/**
+ * Semantic record of the EXTRACT token, identifying the cast operator
+ */
+typedef struct HexExtract {
+    int bit_width;            /**< Bit width of the extract operator          */
+    int storage_bit_width;    /**< Actual bit width of the extract operator   */
+    HexSignedness signedness; /**< Unsigned flag for the extract operator     */
+} HexExtract;
+
+/**
+ * Semantic record of the MPY token, identifying the fMPY multiplication
+ * operator
+ */
+typedef struct HexMpy {
+    /**< Bit width of the first operand of fMPY op */
+    int first_bit_width;
+    /**< Bit width of the second operand of fMPY */
+    int second_bit_width;
+    /**< Signedness flag for the first operand of fMPY */
+    HexSignedness first_signedness;
+    /**< Signedness flag for second operand of fMPY */
+    HexSignedness second_signedness;
+} HexMpy;
+
+/**
+ * Semantic record of the VARID token, identifying declared variables
+ * of the input language
+ */
+typedef struct HexVar {
+    GString *name;          /**< Name of the VARID variable        */
+} HexVar;
+
+/**
+ * Data structure uniquely identifying a declared VARID variable, used for
+ * keeping track of declared variable, so that any variable is declared only
+ * once, and its properties are propagated through all the subsequent instances
+ * of that variable
+ */
+typedef struct Var {
+    GString *name;            /**< Name of the VARID variable       */
+    uint8_t bit_width;        /**< Bit width of the VARID variable  */
+    HexSignedness signedness; /**< Unsigned flag for the VARID var  */
+} Var;
+
+/**
+ * Enum of the possible rvalue types, used in the HexValue.type field
+ */
+typedef enum RvalueUnionTag {
+    REGISTER, REGISTER_ARG, TEMP, IMMEDIATE, PREDICATE, VARID
+} RvalueUnionTag;
+
+/**
+ * Semantic record of the rvalue token, identifying any numeric value,
+ * immediate or register based. The rvalue tokens are combined together
+ * through the use of several operators, to encode expressions
+ */
+typedef struct HexValue {
+    union {
+        HexReg reg;      /**< rvalue of register type                     */
+        HexTmp tmp;      /**< rvalue of temporary type                    */
+        HexImm imm;      /**< rvalue of immediate type                    */
+        HexPred pred;    /**< rvalue of predicate type                    */
+        HexVar var;      /**< rvalue of declared variable type            */
+    };
+    RvalueUnionTag type;      /**< Type of the rvalue                         */
+    unsigned bit_width;       /**< Bit width of the rvalue                    */
+    HexSignedness signedness; /**< Unsigned flag for the rvalue               */
+    bool is_dotnew;           /**< rvalue of predicate type is dotnew?        */
+    bool is_manual;           /**< Opt out of automatic freeing of params     */
+} HexValue;
+
+/**
+ * State of ternary operator
+ */
+typedef enum TernaryState { IN_LEFT, IN_RIGHT } TernaryState;
+
+/**
+ * Data structure used to handle side effects inside ternary operators
+ */
+typedef struct Ternary {
+    TernaryState state;
+    HexValue cond;
+} Ternary;
+
+/**
+ * Operator type, used for referencing the correct operator when calling the
+ * gen_bin_op() function, which in turn will generate the correct code to
+ * execute the operation between the two rvalues
+ */
+typedef enum OpType {
+    ADD_OP, SUB_OP, MUL_OP, ASL_OP, ASR_OP, LSR_OP, ANDB_OP, ORB_OP,
+    XORB_OP, ANDL_OP, MINI_OP, MAXI_OP, MOD_OP
+} OpType;
+
+/**
+ * Data structure including instruction specific information, to be cleared
+ * out after the compilation of each instruction
+ */
+typedef struct Inst {
+    GString *name;                /**< Name of the compiled instruction      */
+    char *code_begin;             /**< Beginning of instruction input code   */
+    char *code_end;               /**< End of instruction input code         */
+    int tmp_count;                /**< Index of the last declared TCGv temp  */
+    int qemu_tmp_count;           /**< Index of the last declared int temp   */
+    int if_count;                 /**< Index of the last declared if label   */
+    int error_count;              /**< Number of generated errors            */
+    HexValue *EA;                 /**< Effective Address (EA)                */
+    GArray *allocated;            /**< Allocated declaredVARID vars          */
+    GArray *init_list;            /**< List of initialized registers         */
+    GArray *strings;              /**< Strings allocated by the instruction  */
+} Inst;
+
+/**
+ * Data structure representing the whole translation context, which in a
+ * reentrant flex/bison parser just like ours is passed between the scanner
+ * and the parser, holding all the necessary information to perform the
+ * parsing, this data structure survives between the compilation of different
+ * instructions
+ *
+ */
+typedef struct Context {
+    void *scanner;                /**< Reentrant parser state pointer        */
+    char *input_buffer;           /**< Buffer containing the input code      */
+    GString *out_str;             /**< String containing the output code     */
+    GString *signature_str;       /**< String containing the signatures code */
+    GString *header_str;          /**< String containing the header code     */
+    FILE *defines_file;           /**< FILE * of the generated header        */
+    FILE *output_file;            /**< FILE * of the C output file           */
+    FILE *enabled_file;           /**< FILE * of the list of enabled inst    */
+    GArray *ternary;              /**< Array to track nesting of ternary ops */
+    int total_insn;               /**< Number of instructions in input file  */
+    int implemented_insn;         /**< Instruction compiled without errors   */
+    Inst inst;                    /**< Parsing data of the current inst      */
+} Context;
+
+#endif /* IDEF_PARSER_H */
diff --git a/target/hexagon/idef-parser/idef-parser.lex b/target/hexagon/idef-parser/idef-parser.lex
new file mode 100644
index 0000000000..c7466c47f4
--- /dev/null
+++ b/target/hexagon/idef-parser/idef-parser.lex
@@ -0,0 +1,571 @@
+%option noyywrap noinput nounput
+%option 8bit reentrant bison-bridge
+%option warn nodefault
+%option bison-locations
+
+%{
+/*
+ * Copyright(c) 2019-2021 rev.ng Labs Srl. 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 <string.h>
+#include <stdbool.h>
+
+#include "hex_regs.h"
+
+#include "idef-parser.h"
+#include "idef-parser.tab.h"
+
+/* Keep track of scanner position for error message printout */
+#define YY_USER_ACTION yylloc->first_column = yylloc->last_column; \
+    for (int i = 0; yytext[i] != '\0'; i++) {   \
+        yylloc->last_column++;                  \
+    }
+
+/* Global Error Counter */
+int error_count;
+
+%}
+
+/* Definitions */
+DIGIT                    [0-9]
+LOWER_ID                 [a-z]
+UPPER_ID                 [A-Z]
+ID                       LOWER_ID|UPPER_ID
+INST_NAME                [A-Z]+[0-9]_([A-Za-z]|[0-9]|_)+
+HEX_DIGIT                [0-9a-fA-F]
+REG_ID_32                e|s|d|t|u|v|x|y
+REG_ID_64                ee|ss|dd|tt|uu|vv|xx|yy
+SYS_ID_32                s|d
+SYS_ID_64                ss|dd
+PRED_ID                  d|s|t|u|v|e|x|x
+IMM_ID                   r|s|S|u|U
+VAR_ID                   [a-zA-Z_][a-zA-Z0-9_]*
+SIGN_ID                  s|u
+STRING_LIT               \"(\\.|[^"\\])*\"
+
+/* Tokens */
+%%
+
+[ \t\f\v]+                { /* Ignore whitespaces. */ }
+[\n\r]+                   { /* Ignore newlines. */ }
+^#.*$                     { /* Ignore linemarkers. */ }
+
+{INST_NAME}               { yylval->string = g_string_new(yytext);
+                            return INAME; }
+"fFLOAT"                 |
+"fUNFLOAT"               |
+"fDOUBLE"                |
+"fUNDOUBLE"              |
+"0.0"                    |
+"0x1.0p52"               |
+"0x1.0p-52"              { return FAIL; }
+"in"                     { return IN; }
+"R"{REG_ID_32}"V" {
+                           yylval->rvalue.type = REGISTER_ARG;
+                           yylval->rvalue.reg.type = GENERAL_PURPOSE;
+                           yylval->rvalue.reg.id = yytext[1];
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.is_dotnew = false;
+                           yylval->rvalue.signedness = SIGNED;
+                           return REG; }
+"R"{REG_ID_32}"N" {
+                           yylval->rvalue.type = REGISTER_ARG;
+                           yylval->rvalue.reg.type = DOTNEW;
+                           yylval->rvalue.reg.id = yytext[1];
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.is_dotnew = true;
+                           yylval->rvalue.signedness = SIGNED;
+                           return REG; }
+"R"{REG_ID_64}"V" {
+                           yylval->rvalue.type = REGISTER_ARG;
+                           yylval->rvalue.reg.type = GENERAL_PURPOSE;
+                           yylval->rvalue.reg.id = yytext[1];
+                           yylval->rvalue.reg.bit_width = 64;
+                           yylval->rvalue.bit_width = 64;
+                           yylval->rvalue.is_dotnew = false;
+                           yylval->rvalue.signedness = SIGNED;
+                           return REG; }
+"R"{REG_ID_64}"N" {
+                           yylval->rvalue.type = REGISTER_ARG;
+                           yylval->rvalue.reg.type = DOTNEW;
+                           yylval->rvalue.reg.id = yytext[1];
+                           yylval->rvalue.reg.bit_width = 64;
+                           yylval->rvalue.bit_width = 64;
+                           yylval->rvalue.is_dotnew = true;
+                           yylval->rvalue.signedness = SIGNED;
+                           return REG; }
+"MuV" {
+                           yylval->rvalue.type = REGISTER_ARG;
+                           yylval->rvalue.reg.type = MODIFIER;
+                           yylval->rvalue.reg.id = 'u';
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.signedness = SIGNED;
+                           return REG; }
+"C"{REG_ID_32}"V" {
+                           yylval->rvalue.type = REGISTER_ARG;
+                           yylval->rvalue.reg.type = CONTROL;
+                           yylval->rvalue.reg.id = yytext[1];
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.is_dotnew = false;
+                           yylval->rvalue.signedness = SIGNED;
+                           return REG; }
+"C"{REG_ID_64}"V" {
+                           yylval->rvalue.type = REGISTER_ARG;
+                           yylval->rvalue.reg.type = CONTROL;
+                           yylval->rvalue.reg.id = yytext[1];
+                           yylval->rvalue.reg.bit_width = 64;
+                           yylval->rvalue.bit_width = 64;
+                           yylval->rvalue.is_dotnew = false;
+                           yylval->rvalue.signedness = SIGNED;
+                           return REG; }
+{IMM_ID}"iV" {
+                           yylval->rvalue.type = IMMEDIATE;
+                           yylval->rvalue.signedness = SIGNED;
+                           yylval->rvalue.imm.type = VARIABLE;
+                           yylval->rvalue.imm.id = yytext[0];
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.is_dotnew = false;
+                           return IMM; }
+"P"{PRED_ID}"V" {
+                           yylval->rvalue.type = PREDICATE;
+                           yylval->rvalue.pred.id = yytext[1];
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.is_dotnew = false;
+                           yylval->rvalue.signedness = SIGNED;
+                           return PRED; }
+"P"{PRED_ID}"N" {
+                           yylval->rvalue.type = PREDICATE;
+                           yylval->rvalue.pred.id = yytext[1];
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.is_dotnew = true;
+                           yylval->rvalue.signedness = SIGNED;
+                           return PRED; }
+"IV1DEAD()"              |
+"fPAUSE(uiV);"           { return ';'; }
+"+="                     { return INC; }
+"-="                     { return DEC; }
+"++"                     { return PLUSPLUS; }
+"&="                     { return ANDA; }
+"|="                     { return ORA; }
+"^="                     { return XORA; }
+"<<"                     { return ASL; }
+">>"                     { return ASR; }
+">>>"                    { return LSR; }
+"=="                     { return EQ; }
+"!="                     { return NEQ; }
+"<="                     { return LTE; }
+">="                     { return GTE; }
+"&&"                     { return ANDL; }
+"else"                   { return ELSE; }
+"for"                    { return FOR; }
+"fREAD_IREG"             { return ICIRC; }
+"fPART1"                 { return PART1; }
+"if"                     { return IF; }
+"fFRAME_SCRAMBLE"        { return FSCR; }
+"fFRAME_UNSCRAMBLE"      { return FSCR; }
+"fFRAMECHECK"            { return FCHK; }
+"Constant_extended"      { return CONSTEXT; }
+"fCL1_"{DIGIT}           { return LOCNT; }
+"fBREV_8"                { return BREV_8; }
+"fBREV_4"                { return BREV_4; }
+"fbrev"                  { return BREV; }
+"fSXTN"                  { return SXT; }
+"fZXTN"                  { return ZXT; }
+"fDF_MAX"                |
+"fSF_MAX"                |
+"fMAX"                   { return MAX; }
+"fDF_MIN"                |
+"fSF_MIN"                |
+"fMIN"                   { return MIN; }
+"fABS"                   { return ABS; }
+"fRNDN"                  { return ROUND; }
+"fCRND"                  { return CROUND; }
+"fCRNDN"                 { return CROUND; }
+"fPM_CIRI"               { return CIRCADD; }
+"fPM_CIRR"               { return CIRCADD; }
+"fCOUNTONES_"{DIGIT}     { return COUNTONES; }
+"fSATN"                  { yylval->sat.set_overflow = true;
+                           yylval->sat.signedness = SIGNED;
+                           return SAT; }
+"fVSATN"                 { yylval->sat.set_overflow = false;
+                           yylval->sat.signedness = SIGNED;
+                           return SAT; }
+"fSATUN"                 { yylval->sat.set_overflow = false;
+                           yylval->sat.signedness = UNSIGNED;
+                           return SAT; }
+"fCONSTLL"               { yylval->cast.bit_width = 64;
+                           yylval->cast.signedness = SIGNED;
+                           return CAST; }
+"fCONSTULL"              { yylval->cast.bit_width = 64;
+                           yylval->cast.signedness = UNSIGNED;
+                           return CAST; }
+"fSE32_64"               { yylval->cast.bit_width = 64;
+                           yylval->cast.signedness = SIGNED;
+                           return CAST; }
+"fCAST4_4u"              { yylval->cast.bit_width = 32;
+                           yylval->cast.signedness = UNSIGNED;
+                           return CAST; }
+"fCAST4_8s"              { yylval->cast.bit_width = 64;
+                           yylval->cast.signedness = SIGNED;
+                           return CAST; }
+"fCAST4_8u"              { return CAST4_8U; }
+"fCAST4u"                { yylval->cast.bit_width = 32;
+                           yylval->cast.signedness = UNSIGNED;
+                           return CAST; }
+"fNEWREG"                |
+"fCAST4_4s"              |
+"fCAST4s"                { yylval->cast.bit_width = 32;
+                           yylval->cast.signedness = SIGNED;
+                           return CAST; }
+"fCAST8_8s"              { yylval->cast.bit_width = 64;
+                           yylval->cast.signedness = SIGNED;
+                           return CAST; }
+"fCAST8_8u"              { yylval->cast.bit_width = 64;
+                           yylval->cast.signedness = UNSIGNED;
+                           return CAST; }
+"fCAST8u"                { yylval->cast.bit_width = 64;
+                           yylval->cast.signedness = UNSIGNED;
+                           return CAST; }
+"fCAST8_8s"              |
+"fCAST8s"                { yylval->cast.bit_width = 64;
+                           yylval->cast.signedness = SIGNED;
+                           return CAST; }
+"fGETBIT"                { yylval->extract.bit_width = 1;
+                           yylval->extract.storage_bit_width = 1;
+                           yylval->extract.signedness = UNSIGNED;
+                           return EXTRACT; }
+"fGETBYTE"               { yylval->extract.bit_width = 8;
+                           yylval->extract.storage_bit_width = 8;
+                           yylval->extract.signedness = SIGNED;
+                           return EXTRACT; }
+"fGETUBYTE"              { yylval->extract.bit_width = 8;
+                           yylval->extract.storage_bit_width = 8;
+                           yylval->extract.signedness = UNSIGNED;
+                           return EXTRACT; }
+"fGETHALF"               { yylval->extract.bit_width = 16;
+                           yylval->extract.storage_bit_width = 16;
+                           yylval->extract.signedness = SIGNED;
+                           return EXTRACT; }
+"fGETUHALF"              { yylval->extract.bit_width = 16;
+                           yylval->extract.storage_bit_width = 16;
+                           yylval->extract.signedness = UNSIGNED;
+                           return EXTRACT; }
+"fGETWORD"               { yylval->extract.bit_width = 32;
+                           yylval->extract.storage_bit_width = 64;
+                           yylval->extract.signedness = SIGNED;
+                           return EXTRACT; }
+"fGETUWORD"              { yylval->extract.bit_width = 32;
+                           yylval->extract.storage_bit_width = 64;
+                           yylval->extract.signedness = UNSIGNED;
+                           return EXTRACT; }
+"fEXTRACTU_BITS"         { return EXTBITS; }
+"fEXTRACTU_RANGE"        { return EXTRANGE; }
+"fSETBIT"                { yylval->cast.bit_width = 1;
+                           yylval->cast.signedness = SIGNED;
+                           return DEPOSIT; }
+"fSETBYTE"               { yylval->cast.bit_width = 8;
+                           yylval->cast.signedness = SIGNED;
+                           return DEPOSIT; }
+"fSETHALF"               { yylval->cast.bit_width = 16;
+                           yylval->cast.signedness = SIGNED;
+                           return SETHALF; }
+"fSETWORD"               { yylval->cast.bit_width = 32;
+                           yylval->cast.signedness = SIGNED;
+                           return DEPOSIT; }
+"fINSERT_BITS"           { return INSBITS; }
+"fSETBITS"               { return SETBITS; }
+"fMPY8UU"                { yylval->mpy.first_bit_width = 8;
+                           yylval->mpy.second_bit_width = 8;
+                           yylval->mpy.first_signedness = UNSIGNED;
+                           yylval->mpy.second_signedness = UNSIGNED;
+                           return MPY; }
+"fMPY8US"                { yylval->mpy.first_bit_width = 8;
+                           yylval->mpy.second_bit_width = 8;
+                           yylval->mpy.first_signedness = UNSIGNED;
+                           yylval->mpy.second_signedness = SIGNED;
+                           return MPY; }
+"fMPY8SU"                { yylval->mpy.first_bit_width = 8;
+                           yylval->mpy.second_bit_width = 8;
+                           yylval->mpy.first_signedness = SIGNED;
+                           yylval->mpy.second_signedness = UNSIGNED;
+                           return MPY; }
+"fMPY8SS"                { yylval->mpy.first_bit_width = 8;
+                           yylval->mpy.second_bit_width = 8;
+                           yylval->mpy.first_signedness = SIGNED;
+                           yylval->mpy.second_signedness = SIGNED;
+                           return MPY; }
+"fMPY16UU"               { yylval->mpy.first_bit_width = 16;
+                           yylval->mpy.second_bit_width = 16;
+                           yylval->mpy.first_signedness = UNSIGNED;
+                           yylval->mpy.second_signedness = UNSIGNED;
+                           return MPY; }
+"fMPY16US"               { yylval->mpy.first_bit_width = 16;
+                           yylval->mpy.second_bit_width = 16;
+                           yylval->mpy.first_signedness = UNSIGNED;
+                           yylval->mpy.second_signedness = SIGNED;
+                           return MPY; }
+"fMPY16SU"               { yylval->mpy.first_bit_width = 16;
+                           yylval->mpy.second_bit_width = 16;
+                           yylval->mpy.first_signedness = SIGNED;
+                           yylval->mpy.second_signedness = UNSIGNED;
+                           return MPY; }
+"fMPY16SS"               { yylval->mpy.first_bit_width = 16;
+                           yylval->mpy.second_bit_width = 16;
+                           yylval->mpy.first_signedness = SIGNED;
+                           yylval->mpy.second_signedness = SIGNED;
+                           return MPY; }
+"fMPY32UU"               { yylval->mpy.first_bit_width = 32;
+                           yylval->mpy.second_bit_width = 32;
+                           yylval->mpy.first_signedness = UNSIGNED;
+                           yylval->mpy.second_signedness = UNSIGNED;
+                           return MPY; }
+"fMPY32US"               { yylval->mpy.first_bit_width = 32;
+                           yylval->mpy.second_bit_width = 32;
+                           yylval->mpy.first_signedness = UNSIGNED;
+                           yylval->mpy.second_signedness = SIGNED;
+                           return MPY; }
+"fMPY32SU"               { yylval->mpy.first_bit_width = 32;
+                           yylval->mpy.second_bit_width = 32;
+                           yylval->mpy.first_signedness = SIGNED;
+                           yylval->mpy.second_signedness = UNSIGNED;
+                           return MPY; }
+"fSFMPY"                 |
+"fMPY32SS"               { yylval->mpy.first_bit_width = 32;
+                           yylval->mpy.second_bit_width = 32;
+                           yylval->mpy.first_signedness = SIGNED;
+                           yylval->mpy.second_signedness = SIGNED;
+                           return MPY; }
+"fMPY3216SS"             { yylval->mpy.first_bit_width = 32;
+                           yylval->mpy.second_bit_width = 16;
+                           yylval->mpy.first_signedness = SIGNED;
+                           yylval->mpy.second_signedness = SIGNED;
+                           return MPY; }
+"fMPY3216SU"             { yylval->mpy.first_bit_width = 32;
+                           yylval->mpy.second_bit_width = 16;
+                           yylval->mpy.first_signedness = SIGNED;
+                           yylval->mpy.second_signedness = UNSIGNED;
+                           return MPY; }
+"fNEWREG_ST"             |
+"fIMMEXT"                |
+"fMUST_IMMEXT"           |
+"fPASS"                  |
+"fECHO"                  { return IDENTITY; }
+"(size8"[us]"_t)"        { yylval->cast.bit_width = 64;
+                           if (yytext[6] == 'u') {
+                               yylval->cast.signedness = UNSIGNED;
+                           } else {
+                               yylval->cast.signedness = SIGNED;
+                           }
+                           return CAST; }
+"(int)"                  { yylval->cast.bit_width = 32;
+                           yylval->cast.signedness = SIGNED;
+                           return CAST; }
+"(unsigned int)"         { yylval->cast.bit_width = 32;
+                           yylval->cast.signedness = UNSIGNED;
+                           return CAST; }
+"fREAD_PC()"             |
+"PC"                     { return PC; }
+"fREAD_NPC()"            |
+"NPC"                    { return NPC; }
+"fGET_LPCFG"             |
+"USR.LPCFG"              { return LPCFG; }
+"LOAD_CANCEL(EA)"        |
+"STORE_CANCEL(EA)"       |
+"CANCEL"                 { return CANCEL; }
+"N"{LOWER_ID}            { yylval->rvalue.type = REGISTER_ARG;
+                           yylval->rvalue.reg.type = GENERAL_PURPOSE;
+                           yylval->rvalue.reg.id = yytext[1];
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.signedness = UNSIGNED;
+                           return REG; }
+"N"{LOWER_ID}"N"         { yylval->rvalue.type = REGISTER_ARG;
+                           yylval->rvalue.reg.type = DOTNEW;
+                           yylval->rvalue.reg.id = yytext[1];
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.signedness = UNSIGNED;
+                           return REG; }
+"fREAD_SP()"             |
+"SP"                     { yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = GENERAL_PURPOSE;
+                           yylval->rvalue.reg.id = HEX_REG_SP;
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.signedness = UNSIGNED;
+                           return REG; }
+"fREAD_FP()"             |
+"FP"                     { yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = GENERAL_PURPOSE;
+                           yylval->rvalue.reg.id = HEX_REG_FP;
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.signedness = UNSIGNED;
+                           return REG; }
+"fREAD_LR()"             |
+"LR"                     { yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = GENERAL_PURPOSE;
+                           yylval->rvalue.reg.id = HEX_REG_LR;
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.signedness = UNSIGNED;
+                           return REG; }
+"fREAD_GP()"             |
+"GP"                     { yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = CONTROL;
+                           yylval->rvalue.reg.id = HEX_REG_GP;
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.signedness = UNSIGNED;
+                           return REG; }
+"fREAD_LC"[01]           { yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = CONTROL;
+                           yylval->rvalue.reg.id = HEX_REG_LC0
+                                                 + (yytext[8] - '0') * 2;
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.signedness = UNSIGNED;
+                           return REG; }
+"LC"[01]                 { yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = CONTROL;
+                           yylval->rvalue.reg.id = HEX_REG_LC0
+                                                 + (yytext[2] - '0') * 2;
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.signedness = UNSIGNED;
+                           return REG; }
+"fREAD_SA"[01]           { yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = CONTROL;
+                           yylval->rvalue.reg.id = HEX_REG_SA0
+                                                 + (yytext[8] - '0') * 2;
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.signedness = UNSIGNED;
+                           return REG; }
+"SA"[01]                 { yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = CONTROL;
+                           yylval->rvalue.reg.id = HEX_REG_SA0
+                                                 + (yytext[2] - '0') * 2;
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.signedness = UNSIGNED;
+                           return REG; }
+"MuN"                    { return MUN; }
+"fREAD_P0()"             { yylval->rvalue.type = PREDICATE;
+                           yylval->rvalue.pred.id = '0';
+                           yylval->rvalue.bit_width = 32;
+                           return PRED; }
+[pP]{DIGIT}              { yylval->rvalue.type = PREDICATE;
+                           yylval->rvalue.pred.id = yytext[1];
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.is_dotnew = false;
+                           return PRED; }
+[pP]{DIGIT}[nN]          { yylval->rvalue.type = PREDICATE;
+                           yylval->rvalue.pred.id = yytext[1];
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.is_dotnew = true;
+                           return PRED; }
+"fLSBNEW"                { return LSBNEW; }
+"N"                      { yylval->rvalue.type = IMMEDIATE;
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.imm.type = VARIABLE;
+                           yylval->rvalue.imm.id = 'N';
+                           return IMM; }
+"i"                      { yylval->rvalue.type = IMMEDIATE;
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.signedness = SIGNED;
+                           yylval->rvalue.imm.type = I;
+                           return IMM; }
+{SIGN_ID}                { if (yytext[0] == 'u') {
+                               yylval->signedness = UNSIGNED;
+                           } else {
+                               yylval->signedness = SIGNED;
+                           }
+                           return SIGN;
+                         }
+"fSF_BIAS()"             { yylval->rvalue.type = IMMEDIATE;
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.signedness = SIGNED;
+                           yylval->rvalue.imm.type = VALUE;
+                           yylval->rvalue.imm.value = 127;
+                           return IMM; }
+"0x"{HEX_DIGIT}+         |
+{DIGIT}+                 { yylval->rvalue.type = IMMEDIATE;
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.signedness = SIGNED;
+                           yylval->rvalue.imm.type = VALUE;
+                           yylval->rvalue.imm.value = strtoull(yytext, NULL, 0);
+                           return IMM; }
+"0x"{HEX_DIGIT}+"LL"     |
+{DIGIT}+"LL"             { yylval->rvalue.type = IMMEDIATE;
+                           yylval->rvalue.bit_width = 64;
+                           yylval->rvalue.signedness = SIGNED;
+                           yylval->rvalue.imm.type = VALUE;
+                           yylval->rvalue.imm.value = strtoull(yytext, NULL, 0);
+                           return IMM; }
+"0x"{HEX_DIGIT}+"ULL"    |
+{DIGIT}+"ULL"            { yylval->rvalue.type = IMMEDIATE;
+                           yylval->rvalue.bit_width = 64;
+                           yylval->rvalue.signedness = UNSIGNED;
+                           yylval->rvalue.imm.type = VALUE;
+                           yylval->rvalue.imm.value = strtoull(yytext, NULL, 0);
+                           return IMM; }
+"fLOAD"                  { return LOAD; }
+"fSTORE"                 { return STORE; }
+"fROTL"                  { return ROTL; }
+"fSET_OVERFLOW"          { return SETOVF; }
+"fCARRY_FROM_ADD"        { return CARRY_FROM_ADD; }
+"fADDSAT64"              { return ADDSAT64; }
+"size"[1248][us]"_t"     { /* Handles "size_t" variants of int types */
+                           const unsigned int bits_per_byte = 8;
+                           const unsigned int bytes = yytext[4] - '0';
+                           yylval->rvalue.bit_width = bits_per_byte * bytes;
+                           if (yytext[5] == 'u') {
+                               yylval->rvalue.signedness = UNSIGNED;
+                           } else {
+                               yylval->rvalue.signedness = SIGNED;
+                           }
+                           return TYPE_SIZE_T; }
+"size16"[us]"_t"         { /* Handles "size_t" variants of int types */
+                           yylval->rvalue.bit_width = 128;
+                           if (yytext[6] == 'u') {
+                               yylval->rvalue.signedness = UNSIGNED;
+                           } else {
+                               yylval->rvalue.signedness = SIGNED;
+                           }
+                           return TYPE_SIZE_T; }
+"signed"                 { return TYPE_SIGNED; }
+"unsigned"               { return TYPE_UNSIGNED; }
+"long"                   { return TYPE_LONG; }
+"int"                    { return TYPE_INT; }
+"const"                  { /* Emit no token */ }
+{VAR_ID}                 { /* Variable name, we adopt the C names convention */
+                           yylval->rvalue.type = VARID;
+                           yylval->rvalue.var.name = g_string_new(yytext);
+                           /* Default to an unknown signedness and 0 width. */
+                           yylval->rvalue.bit_width = 0;
+                           yylval->rvalue.signedness = UNKNOWN_SIGNEDNESS;
+                           return VAR; }
+"fatal("{STRING_LIT}")"  { /* Emit no token */ }
+"fHINTJR(RsV)"           { /* Emit no token */ }
+.                        { return yytext[0]; }
+
+%%
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index 236c3a3ffa..077951d8d3 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -195,4 +195,8 @@ idef_parser_input_generated_prep = custom_target(
     command: [idef_parser_dir / 'prepare', '@INPUT@', '-I' + idef_parser_dir, '-o', '@OUTPUT@'],
 )
 
+flex = generator(find_program('flex'),
+                 output: ['@BASENAME@.yy.c', '@BASENAME@.yy.h'],
+                 arguments: ['-o', '@OUTPUT0@', '--header-file=@OUTPUT1@', '@INPUT@'])
+
 target_arch += {'hexagon': hexagon_ss}
-- 
2.33.1



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v7 10/13] target/hexagon: import parser for idef-parser
  2021-12-17  9:01 [PATCH v7 00/13] target/hexagon: introduce idef-parser Anton Johansson via
                   ` (8 preceding siblings ...)
  2021-12-17  9:01 ` [PATCH v7 09/13] target/hexagon: import lexer for idef-parser Anton Johansson via
@ 2021-12-17  9:01 ` Anton Johansson via
  2021-12-17  9:01 ` [PATCH v7 11/13] target/hexagon: call idef-parser functions Anton Johansson via
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Anton Johansson via @ 2021-12-17  9:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: ale, tsimpson, bcain, babush, nizzo, richard.henderson

Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Paolo Montesel <babush@rev.ng>
Signed-off-by: Anton Johansson <anjo@rev.ng>
---
 target/hexagon/idef-parser/idef-parser.y    | 1064 ++++++++
 target/hexagon/idef-parser/parser-helpers.c | 2548 +++++++++++++++++++
 target/hexagon/idef-parser/parser-helpers.h |  379 +++
 target/hexagon/meson.build                  |   27 +-
 4 files changed, 4017 insertions(+), 1 deletion(-)
 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

diff --git a/target/hexagon/idef-parser/idef-parser.y b/target/hexagon/idef-parser/idef-parser.y
new file mode 100644
index 0000000000..5c3ab3bd07
--- /dev/null
+++ b/target/hexagon/idef-parser/idef-parser.y
@@ -0,0 +1,1064 @@
+%{
+/*
+ * Copyright(c) 2019-2021 rev.ng Labs Srl. 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}
+
+%define parse.error verbose
+%define parse.lac full
+%define api.pure full
+
+%locations
+
+%union {
+    GString *string;
+    HexValue rvalue;
+    HexSat sat;
+    HexCast cast;
+    HexExtract extract;
+    HexMpy mpy;
+    HexSignedness signedness;
+    int index;
+}
+
+/* Tokens */
+%start input
+
+%expect 1
+
+%token IN INAME VAR
+%token ABS CROUND ROUND CIRCADD COUNTONES INC DEC ANDA ORA XORA PLUSPLUS ASL
+%token ASR LSR EQ NEQ LTE GTE MIN MAX ANDL FOR ICIRC IF MUN FSCR FCHK SXT
+%token ZXT CONSTEXT LOCNT BREV SIGN LOAD STORE PC NPC LPCFG
+%token CANCEL IDENTITY PART1 BREV_4 BREV_8 ROTL INSBITS SETBITS EXTBITS EXTRANGE
+%token CAST4_8U SETOVF FAIL CARRY_FROM_ADD ADDSAT64 LSBNEW
+%token TYPE_SIZE_T TYPE_INT TYPE_SIGNED TYPE_UNSIGNED TYPE_LONG
+
+%token <rvalue> REG IMM PRED
+%token <index> ELSE
+%token <mpy> MPY
+%token <sat> SAT
+%token <cast> CAST DEPOSIT SETHALF
+%token <extract> EXTRACT
+%type <string> INAME
+%type <rvalue> rvalue lvalue VAR assign_statement var var_decl var_type
+%type <rvalue> FAIL
+%type <rvalue> TYPE_SIGNED TYPE_UNSIGNED TYPE_INT TYPE_LONG TYPE_SIZE_T
+%type <index> if_stmt IF
+%type <signedness> SIGN
+
+/* Operator Precedences */
+%left MIN MAX
+%left '('
+%left ','
+%left '='
+%right CIRCADD
+%right INC DEC ANDA ORA XORA
+%left '?' ':'
+%left ANDL
+%left '|'
+%left '^' ANDOR
+%left '&'
+%left EQ NEQ
+%left '<' '>' LTE GTE
+%left ASL ASR LSR
+%right ABS
+%left '-' '+'
+%left '*' '/' '%' MPY
+%right '~' '!'
+%left '['
+%right CAST
+%right LOCNT BREV
+
+/* Bison Grammar */
+%%
+
+/* Input file containing the description of each hexagon instruction */
+input : instructions
+      {
+          YYACCEPT;
+      }
+      ;
+
+instructions : instruction instructions
+             | %empty
+             ;
+
+instruction : INAME
+              {
+                  gen_inst(c, $1);
+              }
+              arguments
+              {
+                  EMIT_SIG(c, ")");
+                  EMIT_HEAD(c, "{\n");
+
+                  /*
+                   * The effective address EA is the only variable passed to
+                   * function which needs to be "created".
+                   */
+                  if (c->inst.EA) {
+                      gen_varid_allocate(c, &@1, c->inst.EA, 32, SIGNED);
+                  }
+              }
+              code
+              {
+                  gen_inst_code(c, &@1);
+              }
+            | error /* Recover gracefully after instruction compilation error */
+              {
+                  free_instruction(c);
+              }
+            ;
+
+arguments : '(' ')'
+          | '(' argument_list ')';
+
+argument_list : argument_decl ',' argument_list
+              | argument_decl
+              ;
+
+var : VAR
+      {
+          track_string(c, $1.var.name);
+          $$ = $1;
+      }
+    ;
+
+/*
+ * Here the integer types are defined from valid combinations of
+ * "signed", "unsigned", "int", and "long" tokens.  The "signed"
+ * and "unsigned" tokens are here assumed to always be placed
+ * first in the type declaration, which is not the case in
+ * normal C. Similarly, "int" is assumed to be placed in the type.
+ */
+type_int : TYPE_INT
+         | TYPE_SIGNED
+         | TYPE_SIGNED TYPE_INT;
+type_uint : TYPE_UNSIGNED
+          | TYPE_UNSIGNED TYPE_INT;
+type_long : TYPE_LONG
+          | TYPE_LONG TYPE_INT
+          | TYPE_SIGNED TYPE_LONG
+          | TYPE_SIGNED TYPE_LONG TYPE_INT;
+type_ulong : TYPE_UNSIGNED TYPE_LONG
+           | TYPE_UNSIGNED TYPE_LONG TYPE_INT;
+type_longlong : TYPE_LONG TYPE_LONG
+              | TYPE_LONG TYPE_LONG TYPE_INT
+              | TYPE_SIGNED TYPE_LONG TYPE_LONG
+              | TYPE_SIGNED TYPE_LONG TYPE_LONG TYPE_INT;
+type_ulonglong : TYPE_UNSIGNED TYPE_LONG TYPE_LONG
+               | TYPE_UNSIGNED TYPE_LONG TYPE_LONG TYPE_INT;
+
+/*
+ * Here the various valid int types defined above specify
+ * their `signedness` and `bit_width`. The LP64 convention
+ * is assumed where longs are 64-bit, long longs are then
+ * assumed to also be 64-bit.abvove
+ */
+var_type : TYPE_SIZE_T
+           {
+              yyassert(c, &@1, $1.bit_width <= 64,
+                       "Variables with size > 64-bit are not supported!");
+              $$ = $1;
+           }
+         | type_int
+           {
+              $$.signedness = SIGNED;
+              $$.bit_width  = 32;
+           }
+         | type_uint
+           {
+              $$.signedness = UNSIGNED;
+              $$.bit_width  = 32;
+           }
+         | type_long
+           {
+              $$.signedness = SIGNED;
+              $$.bit_width  = 64;
+           }
+         | type_ulong
+           {
+              $$.signedness = UNSIGNED;
+              $$.bit_width  = 64;
+           }
+         | type_longlong
+           {
+              $$.signedness = SIGNED;
+              $$.bit_width  = 64;
+           }
+         | type_ulonglong
+           {
+              $$.signedness = UNSIGNED;
+              $$.bit_width  = 64;
+           }
+         ;
+
+/* Rule to capture declarations of VARs */
+var_decl : var_type IMM
+           {
+              /*
+               * Rule to capture "int i;" declarations since "i" is special
+               * and assumed to be always be IMM. Moreover, "i" is only
+               * assumed to be used in for-loops.
+               *
+               * Therefore we want to NOP these declarations.
+               */
+              yyassert(c, &@2, $2.imm.type == I,
+                       "Variable declaration with immedaties only allowed"
+                       " for the loop induction variable \"i\"");
+              $$ = $2;
+           }
+         | var_type var
+           {
+              /*
+               * Allocate new variable, this checks that it hasn't aldready
+               * been declared.
+               */
+              gen_varid_allocate(c, &@1, &$2, $1.bit_width, $1.signedness);
+              /* Copy var for variable name */
+              $$ = $2;
+              /* Copy type info from var_type */
+              $$.signedness = $1.signedness;
+              $$.bit_width  = $1.bit_width;
+           }
+         ;
+
+/* Return the modified registers list */
+code : '{' statements '}'
+       {
+           c->inst.code_begin = c->input_buffer + @2.first_column - 1;
+           c->inst.code_end = c->input_buffer + @2.last_column - 1;
+       }
+     | '{'
+       {
+           /* Nop */
+       }
+       '}'
+     ;
+
+argument_decl : REG
+                {
+                    emit_arg(c, &@1, &$1);
+                    /* Enqueue register into initialization list */
+                    g_array_append_val(c->inst.init_list, $1);
+                }
+              | PRED
+                {
+                    emit_arg(c, &@1, &$1);
+                    /* Enqueue predicate into initialization list */
+                    g_array_append_val(c->inst.init_list, $1);
+                }
+              | IN REG
+                {
+                    emit_arg(c, &@2, &$2);
+                }
+              | IN PRED
+                {
+                    emit_arg(c, &@2, &$2);
+                }
+              | IMM
+                {
+                    EMIT_SIG(c, ", int %ciV", $1.imm.id);
+                }
+              | var
+                {
+                    yyassert(c, &@1, !strcmp($1.var.name->str, "EA"),
+                             "Unknown argument variable!");
+                    /* The instruction take EA, so set it */
+                    c->inst.EA = &$1;
+                }
+              ;
+
+code_block : '{' statements '}'
+           | '{' '}'
+           ;
+
+/* A list of one or more statements */
+statements : statements statement
+           | statement
+           ;
+
+/* Statements can be assignment (rvalue ';'), control or memory statements */
+statement : control_statement
+          | var_decl ';'
+          | rvalue ';'
+            {
+                gen_rvalue_free(c, &@1, &$1);
+            }
+          | code_block
+          | ';'
+          ;
+
+assign_statement : lvalue '=' rvalue
+                   {
+                       @1.last_column = @3.last_column;
+                       gen_assign(c, &@1, &$1, &$3);
+                       $$ = $1;
+                   }
+                 | var_decl '=' rvalue
+                   {
+                       @1.last_column = @3.last_column;
+                       gen_assign(c, &@1, &$1, &$3);
+                       $$ = $1;
+                   }
+                 | lvalue INC rvalue
+                   {
+                       @1.last_column = @3.last_column;
+                       HexValue tmp = gen_bin_op(c, &@1, ADD_OP, &$1, &$3);
+                       gen_assign(c, &@1, &$1, &tmp);
+                       $$ = $1;
+                   }
+                 | lvalue DEC rvalue
+                   {
+                       @1.last_column = @3.last_column;
+                       HexValue tmp = gen_bin_op(c, &@1, SUB_OP, &$1, &$3);
+                       gen_assign(c, &@1, &$1, &tmp);
+                       $$ = $1;
+                   }
+                 | lvalue ANDA rvalue
+                   {
+                       @1.last_column = @3.last_column;
+                       HexValue tmp = gen_bin_op(c, &@1, ANDB_OP, &$1, &$3);
+                       gen_assign(c, &@1, &$1, &tmp);
+                       $$ = $1;
+                   }
+                 | lvalue ORA rvalue
+                   {
+                       @1.last_column = @3.last_column;
+                       HexValue tmp = gen_bin_op(c, &@1, ORB_OP, &$1, &$3);
+                       gen_assign(c, &@1, &$1, &tmp);
+                       $$ = $1;
+                   }
+                 | lvalue XORA rvalue
+                   {
+                       @1.last_column = @3.last_column;
+                       HexValue tmp = gen_bin_op(c, &@1, XORB_OP, &$1, &$3);
+                       gen_assign(c, &@1, &$1, &tmp);
+                       $$ = $1;
+                   }
+                 | PRED '=' rvalue
+                   {
+                       @1.last_column = @3.last_column;
+                       gen_pred_assign(c, &@1, &$1, &$3);
+                   }
+                 | IMM '=' rvalue
+                   {
+                       @1.last_column = @3.last_column;
+                       yyassert(c, &@1, $3.type == IMMEDIATE,
+                                "Cannot assign non-immediate to immediate!");
+                       yyassert(c, &@1, $1.imm.type == VARIABLE,
+                                "Cannot assign to non-variable!");
+                       /* Assign to the function argument */
+                       OUT(c, &@1, &$1, " = ", &$3, ";\n");
+                       $$ = $1;
+                   }
+                 | PC '=' rvalue
+                   {
+                       @1.last_column = @3.last_column;
+                       yyassert(c, &@1, c->ternary->len == 0,
+                                "Assignment side-effect not modeled!");
+                       $3 = gen_rvalue_truncate(c, &@1, &$3);
+                       $3 = rvalue_materialize(c, &@1, &$3);
+                       OUT(c, &@1, "gen_write_new_pc(", &$3, ");\n");
+                       gen_rvalue_free(c, &@1, &$3); /* Free temporary value */
+                   }
+                 | LOAD '(' IMM ',' IMM ',' SIGN ',' var ',' lvalue ')'
+                   {
+                       @1.last_column = @12.last_column;
+                       yyassert(c, &@1, c->ternary->len == 0,
+                                "Assignment side-effect not modeled!");
+                       yyassert(c, &@1, $3.imm.value == 1,
+                                "LOAD of arrays not supported!");
+                       gen_load(c, &@1, &$5, $7, &$9, &$11);
+                   }
+                 | STORE '(' IMM ',' IMM ',' var ',' rvalue ')'
+                   /* Store primitive */
+                   {
+                       @1.last_column = @10.last_column;
+                       yyassert(c, &@1, c->ternary->len == 0,
+                                "Assignment side-effect not modeled!");
+                       yyassert(c, &@1, $3.imm.value == 1,
+                                "STORE of arrays not supported!");
+                       gen_store(c, &@1, &$5, &$7, &$9);
+                   }
+                 | LPCFG '=' rvalue
+                   {
+                       @1.last_column = @3.last_column;
+                       yyassert(c, &@1, c->ternary->len == 0,
+                                "Assignment side-effect not modeled!");
+                       $3 = gen_rvalue_truncate(c, &@1, &$3);
+                       $3 = rvalue_materialize(c, &@1, &$3);
+                       OUT(c, &@1, "SET_USR_FIELD(USR_LPCFG, ", &$3, ");\n");
+                       gen_rvalue_free(c, &@1, &$3);
+                   }
+                 | DEPOSIT '(' rvalue ',' rvalue ',' rvalue ')'
+                   {
+                       @1.last_column = @8.last_column;
+                       yyassert(c, &@1, c->ternary->len == 0,
+                                "Assignment side-effect not modeled!");
+                       gen_deposit_op(c, &@1, &$5, &$7, &$3, &$1);
+                   }
+                 | SETHALF '(' rvalue ',' lvalue ',' rvalue ')'
+                   {
+                       @1.last_column = @8.last_column;
+                       yyassert(c, &@1, c->ternary->len == 0,
+                                "Assignment side-effect not modeled!");
+                       gen_sethalf(c, &@1, &$1, &$3, &$5, &$7);
+                   }
+                 | SETBITS '(' rvalue ',' rvalue ',' rvalue ',' rvalue ')'
+                   {
+                       @1.last_column = @10.last_column;
+                       yyassert(c, &@1, c->ternary->len == 0,
+                                "Assignment side-effect not modeled!");
+                       gen_setbits(c, &@1, &$3, &$5, &$7, &$9);
+                   }
+                 | INSBITS '(' lvalue ',' rvalue ',' rvalue ',' rvalue ')'
+                   {
+                       @1.last_column = @10.last_column;
+                       yyassert(c, &@1, c->ternary->len == 0,
+                                "Assignment side-effect not modeled!");
+                       gen_rdeposit_op(c, &@1, &$3, &$9, &$7, &$5);
+                   }
+                 | IDENTITY '(' rvalue ')'
+                   {
+                       @1.last_column = @4.last_column;
+                       $$ = $3;
+                   }
+                 ;
+
+control_statement : frame_check
+                  | cancel_statement
+                  | if_statement
+                  | for_statement
+                  | fpart1_statement
+                  ;
+
+frame_check : FCHK '(' rvalue ',' rvalue ')' ';'
+              {
+                  gen_rvalue_free(c, &@1, &$3);
+                  gen_rvalue_free(c, &@1, &$5);
+              }
+            ;
+
+cancel_statement : CANCEL
+                   {
+                       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;
+                   $2 = gen_if_else(c, &@1, $1);
+               }
+               statement
+               {
+                   OUT(c, &@1, "gen_set_label(if_label_", &$2, ");\n");
+               }
+             ;
+
+for_statement : FOR '(' IMM '=' IMM ';' IMM '<' IMM ';' IMM PLUSPLUS ')'
+                {
+                    yyassert(c, &@3,
+                             $3.imm.type == I &&
+                             $7.imm.type == I &&
+                             $11.imm.type == I,
+                             "Loop induction variable must be \"i\"");
+                    @1.last_column = @13.last_column;
+                    OUT(c, &@1, "for (int ", &$3, " = ", &$5, "; ",
+                        &$7, " < ", &$9);
+                    OUT(c, &@1, "; ", &$11, "++) {\n");
+                }
+                code_block
+                {
+                    OUT(c, &@1, "}\n");
+                }
+              | FOR '(' IMM '=' IMM ';' IMM '<' IMM ';' IMM INC IMM ')'
+                {
+                    yyassert(c, &@3,
+                             $3.imm.type == I &&
+                             $7.imm.type == I &&
+                             $11.imm.type == I,
+                             "Loop induction variable must be \"i\"");
+                    @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");
+                   }
+                   '(' statements ')'
+                   {
+                       @1.last_column = @3.last_column;
+                       OUT(c, &@1, "return; }\n");
+                   }
+                 ;
+
+if_stmt : IF '(' rvalue ')'
+          {
+              @1.last_column = @3.last_column;
+              $1 = gen_if_cond(c, &@1, &$3);
+          }
+          statement
+          {
+              $$ = $1;
+          }
+        ;
+
+rvalue : FAIL
+         {
+             yyassert(c, &@1, false, "Encountered a FAIL token as rvalue.\n");
+         }
+       | assign_statement
+       | REG
+         {
+             if ($1.type == REGISTER_ARG) {
+                 $$ = gen_read_reg(c, &@1, &$1);
+             } else {
+                 $$ = $1;
+             }
+         }
+       | IMM
+         {
+             $$ = $1;
+         }
+       | PRED
+         {
+             $$ = gen_rvalue_pred(c, &@1, &$1);
+         }
+       | PC
+         {
+             /* Read PC from the CR */
+             HexValue rvalue;
+             memset(&rvalue, 0, sizeof(HexValue));
+             rvalue.type = IMMEDIATE;
+             rvalue.imm.type = IMM_PC;
+             rvalue.bit_width = 32;
+             rvalue.signedness = UNSIGNED;
+             $$ = rvalue;
+         }
+       | NPC
+         {
+             /*
+              * NPC is only read from CALLs, so we can hardcode it
+              * at translation time
+              */
+             HexValue rvalue;
+             memset(&rvalue, 0, sizeof(HexValue));
+             rvalue.type = IMMEDIATE;
+             rvalue.imm.type = IMM_NPC;
+             rvalue.bit_width = 32;
+             rvalue.signedness = UNSIGNED;
+             $$ = rvalue;
+         }
+       | CONSTEXT
+         {
+             HexValue rvalue;
+             memset(&rvalue, 0, sizeof(HexValue));
+             rvalue.type = IMMEDIATE;
+             rvalue.imm.type = IMM_CONSTEXT;
+             rvalue.signedness = UNSIGNED;
+             rvalue.is_dotnew = false;
+             rvalue.is_manual = false;
+             $$ = rvalue;
+         }
+       | var
+         {
+             $$ = gen_rvalue_var(c, &@1, &$1);
+         }
+       | MPY '(' rvalue ',' rvalue ')'
+         {
+             @1.last_column = @6.last_column;
+             $$ = gen_rvalue_mpy(c, &@1, &$1, &$3, &$5);
+         }
+       | rvalue '+' rvalue
+         {
+             @1.last_column = @3.last_column;
+             $$ = gen_bin_op(c, &@1, ADD_OP, &$1, &$3);
+         }
+       | rvalue '-' rvalue
+         {
+             @1.last_column = @3.last_column;
+             $$ = gen_bin_op(c, &@1, SUB_OP, &$1, &$3);
+         }
+       | rvalue '*' rvalue
+         {
+             @1.last_column = @3.last_column;
+             $$ = gen_bin_op(c, &@1, MUL_OP, &$1, &$3);
+         }
+       | rvalue '%' 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;
+             assert_signedness(c, &@1, $1.signedness);
+             if ($1.signedness == UNSIGNED) {
+                 $$ = gen_bin_op(c, &@1, LSR_OP, &$1, &$3);
+             } else if ($1.signedness == SIGNED) {
+                 $$ = gen_bin_op(c, &@1, ASR_OP, &$1, &$3);
+             }
+         }
+       | rvalue LSR rvalue
+         {
+             @1.last_column = @3.last_column;
+             $$ = gen_bin_op(c, &@1, LSR_OP, &$1, &$3);
+         }
+       | rvalue '&' rvalue
+         {
+             @1.last_column = @3.last_column;
+             $$ = gen_bin_op(c, &@1, ANDB_OP, &$1, &$3);
+         }
+       | rvalue '|' rvalue
+         {
+             @1.last_column = @3.last_column;
+             $$ = gen_bin_op(c, &@1, ORB_OP, &$1, &$3);
+         }
+       | rvalue '^' rvalue
+         {
+             @1.last_column = @3.last_column;
+             $$ = gen_bin_op(c, &@1, XORB_OP, &$1, &$3);
+         }
+       | rvalue ANDL rvalue
+         {
+             @1.last_column = @3.last_column;
+             $$ = gen_bin_op(c, &@1, ANDL_OP, &$1, &$3);
+         }
+       | MIN '(' rvalue ',' rvalue ')'
+         {
+             @1.last_column = @3.last_column;
+             $$ = gen_bin_op(c, &@1, MINI_OP, &$3, &$5);
+         }
+       | MAX '(' rvalue ',' rvalue ')'
+         {
+             @1.last_column = @3.last_column;
+             $$ = gen_bin_op(c, &@1, MAXI_OP, &$3, &$5);
+         }
+       | '~' rvalue
+         {
+             @1.last_column = @2.last_column;
+             $$ = gen_rvalue_not(c, &@1, &$2);
+         }
+       | '!' rvalue
+         {
+             @1.last_column = @2.last_column;
+             $$ = gen_rvalue_notl(c, &@1, &$2);
+         }
+       | SAT '(' IMM ',' rvalue ')'
+         {
+             @1.last_column = @6.last_column;
+             $$ = gen_rvalue_sat(c, &@1, &$1, &$3, &$5);
+         }
+       | CAST rvalue
+         {
+             @1.last_column = @2.last_column;
+             /* Assign target signedness */
+             $2.signedness = $1.signedness;
+             $$ = gen_cast_op(c, &@1, &$2, $1.bit_width, $1.signedness);
+         }
+       | rvalue EQ rvalue
+         {
+             @1.last_column = @3.last_column;
+             $$ = gen_bin_cmp(c, &@1, TCG_COND_EQ, &$1, &$3);
+         }
+       | rvalue NEQ rvalue
+         {
+             @1.last_column = @3.last_column;
+             $$ = gen_bin_cmp(c, &@1, TCG_COND_NE, &$1, &$3);
+         }
+       | rvalue '<' rvalue
+         {
+             @1.last_column = @3.last_column;
+
+             assert_signedness(c, &@1, $1.signedness);
+             assert_signedness(c, &@1, $3.signedness);
+             if ($1.signedness == UNSIGNED || $3.signedness == UNSIGNED) {
+                 $$ = gen_bin_cmp(c, &@1, TCG_COND_LTU, &$1, &$3);
+             } else {
+                 $$ = gen_bin_cmp(c, &@1, TCG_COND_LT, &$1, &$3);
+             }
+         }
+       | rvalue '>' rvalue
+         {
+             @1.last_column = @3.last_column;
+
+             assert_signedness(c, &@1, $1.signedness);
+             assert_signedness(c, &@1, $3.signedness);
+             if ($1.signedness == UNSIGNED || $3.signedness == UNSIGNED) {
+                 $$ = gen_bin_cmp(c, &@1, TCG_COND_GTU, &$1, &$3);
+             } else {
+                 $$ = gen_bin_cmp(c, &@1, TCG_COND_GT, &$1, &$3);
+             }
+         }
+       | rvalue LTE rvalue
+         {
+             @1.last_column = @3.last_column;
+
+             assert_signedness(c, &@1, $1.signedness);
+             assert_signedness(c, &@1, $3.signedness);
+             if ($1.signedness == UNSIGNED || $3.signedness == UNSIGNED) {
+                 $$ = gen_bin_cmp(c, &@1, TCG_COND_LEU, &$1, &$3);
+             } else {
+                 $$ = gen_bin_cmp(c, &@1, TCG_COND_LE, &$1, &$3);
+             }
+         }
+       | rvalue GTE rvalue
+         {
+             @1.last_column = @3.last_column;
+
+             assert_signedness(c, &@1, $1.signedness);
+             assert_signedness(c, &@1, $3.signedness);
+             if ($1.signedness == UNSIGNED || $3.signedness == UNSIGNED) {
+                 $$ = gen_bin_cmp(c, &@1, TCG_COND_GEU, &$1, &$3);
+             } else {
+                 $$ = gen_bin_cmp(c, &@1, TCG_COND_GE, &$1, &$3);
+             }
+         }
+       | rvalue '?'
+         {
+             $1.is_manual = true;
+             Ternary t = { 0 };
+             t.state = IN_LEFT;
+             t.cond = $1;
+             g_array_append_val(c->ternary, t);
+         }
+         rvalue ':'
+         {
+             Ternary *t = &g_array_index(c->ternary, Ternary,
+                                         c->ternary->len - 1);
+             t->state = IN_RIGHT;
+         }
+         rvalue
+         {
+             @1.last_column = @5.last_column;
+             $$ = gen_rvalue_ternary(c, &@1, &$1, &$4, &$7);
+         }
+       | FSCR '(' rvalue ')'
+         {
+             @1.last_column = @4.last_column;
+             $$ = gen_rvalue_fscr(c, &@1, &$3);
+         }
+       | SXT '(' rvalue ',' IMM ',' rvalue ')'
+         {
+             @1.last_column = @8.last_column;
+             yyassert(c, &@1, $5.type == IMMEDIATE &&
+                      $5.imm.type == VALUE,
+                      "SXT expects immediate values\n");
+             $$ = gen_extend_op(c, &@1, &$3, $5.imm.value, &$7, SIGNED);
+         }
+       | ZXT '(' rvalue ',' IMM ',' rvalue ')'
+         {
+             @1.last_column = @8.last_column;
+             yyassert(c, &@1, $5.type == IMMEDIATE &&
+                      $5.imm.type == VALUE,
+                      "ZXT expects immediate values\n");
+             $$ = gen_extend_op(c, &@1, &$3, $5.imm.value, &$7, UNSIGNED);
+         }
+       | '(' rvalue ')'
+         {
+             $$ = $2;
+         }
+       | ABS rvalue
+         {
+             @1.last_column = @2.last_column;
+             $$ = gen_rvalue_abs(c, &@1, &$2);
+         }
+       | CROUND '(' rvalue ',' rvalue ')'
+         {
+             @1.last_column = @6.last_column;
+             $$ = gen_convround_n(c, &@1, &$3, &$5);
+         }
+       | CROUND '(' rvalue ')'
+         {
+             @1.last_column = @4.last_column;
+             $$ = gen_convround(c, &@1, &$3);
+         }
+       | ROUND '(' rvalue ',' rvalue ')'
+         {
+             @1.last_column = @6.last_column;
+             $$ = gen_round(c, &@1, &$3, &$5);
+         }
+       | '-' rvalue
+         {
+             @1.last_column = @2.last_column;
+             $$ = gen_rvalue_neg(c, &@1, &$2);
+         }
+       | ICIRC '(' rvalue ')' ASL IMM
+         {
+             @1.last_column = @6.last_column;
+             $$ = gen_tmp(c, &@1, 32, UNSIGNED);
+             OUT(c, &@1, "gen_read_ireg(", &$$, ", ", &$3, ", ", &$6, ");\n");
+             gen_rvalue_free(c, &@1, &$3);
+         }
+       | CIRCADD '(' rvalue ',' rvalue ',' rvalue ')'
+         {
+             @1.last_column = @8.last_column;
+             gen_circ_op(c, &@1, &$3, &$5, &$7);
+         }
+       | LOCNT '(' rvalue ')'
+         {
+             @1.last_column = @4.last_column;
+             /* Leading ones count */
+             $$ = gen_locnt_op(c, &@1, &$3);
+         }
+       | COUNTONES '(' rvalue ')'
+         {
+             @1.last_column = @4.last_column;
+             /* Ones count */
+             $$ = gen_ctpop_op(c, &@1, &$3);
+         }
+       | LPCFG
+         {
+             $$ = gen_tmp_value(c, &@1, "0", 32, UNSIGNED);
+             OUT(c, &@1, "GET_USR_FIELD(USR_LPCFG, ", &$$, ");\n");
+         }
+       | EXTRACT '(' rvalue ',' rvalue ')'
+         {
+             @1.last_column = @6.last_column;
+             $$ = gen_extract_op(c, &@1, &$5, &$3, &$1);
+         }
+       | EXTBITS '(' rvalue ',' rvalue ',' rvalue ')'
+         {
+             @1.last_column = @8.last_column;
+             yyassert(c, &@1, $5.type == IMMEDIATE &&
+                      $5.imm.type == VALUE &&
+                      $7.type == IMMEDIATE &&
+                      $7.imm.type == VALUE,
+                      "Range extract needs immediate values!\n");
+             $$ = gen_rextract_op(c, &@1, &$3, $7.imm.value, $5.imm.value);
+         }
+       | EXTRANGE '(' rvalue ',' rvalue ',' rvalue ')'
+         {
+             @1.last_column = @8.last_column;
+             yyassert(c, &@1, $5.type == IMMEDIATE &&
+                      $5.imm.type == VALUE &&
+                      $7.type == IMMEDIATE &&
+                      $7.imm.type == VALUE,
+                      "Range extract needs immediate values!\n");
+             $$ = gen_rextract_op(c,
+                                  &@1,
+                                  &$3,
+                                  $7.imm.value,
+                                  $5.imm.value - $7.imm.value + 1);
+         }
+       | CAST4_8U '(' rvalue ')'
+         {
+             @1.last_column = @4.last_column;
+             $$ = gen_rvalue_truncate(c, &@1, &$3);
+             $$.signedness = UNSIGNED;
+             $$ = rvalue_materialize(c, &@1, &$$);
+             $$ = gen_rvalue_extend(c, &@1, &$$);
+         }
+       | BREV '(' rvalue ')'
+         {
+             @1.last_column = @4.last_column;
+             $$ = gen_rvalue_brev(c, &@1, &$3);
+         }
+       | BREV_4 '(' rvalue ')'
+         {
+             @1.last_column = @4.last_column;
+             $$ = gen_fbrev_4(c, &@1, &$3);
+         }
+       | BREV_8 '(' rvalue ')'
+         {
+             @1.last_column = @4.last_column;
+             $$ = gen_fbrev_8(c, &@1, &$3);
+         }
+       | ROTL '(' rvalue ',' rvalue ')'
+         {
+             @1.last_column = @6.last_column;
+             $$ = gen_rotl(c, &@1, &$3, &$5);
+         }
+       | SETOVF '(' ')'
+         {
+             @1.last_column = @3.last_column;
+             HexValue ovfl = gen_imm_value(c, &@1, 1, 32, UNSIGNED);
+             gen_set_overflow(c, &@1, &ovfl);
+         }
+       | SETOVF '(' rvalue ')'
+         {
+             /* Convenience fSET_OVERFLOW with pass-through */
+             @1.last_column = @3.last_column;
+             HexValue ovfl = gen_imm_value(c, &@1, 1, 32, UNSIGNED);
+             gen_set_overflow(c, &@1, &ovfl);
+             $$ = $3;
+         }
+       | ADDSAT64 '(' rvalue ',' rvalue ',' rvalue ')'
+         {
+             @1.last_column = @8.last_column;
+             gen_addsat64(c, &@1, &$3, &$5, &$7);
+         }
+       | CARRY_FROM_ADD '(' rvalue ',' rvalue ',' rvalue ')'
+         {
+             @1.last_column = @8.last_column;
+             $$ = gen_carry_from_add(c, &@1, &$3, &$5, &$7);
+         }
+       | LSBNEW '(' rvalue ')'
+         {
+             @1.last_column = @4.last_column;
+             HexValue one = gen_imm_value(c, &@1, 1, 32, UNSIGNED);
+             $$ = gen_bin_op(c, &@1, ANDB_OP, &$3, &one);
+         }
+       ;
+
+lvalue : FAIL
+         {
+             @1.last_column = @1.last_column;
+             yyassert(c, &@1, false, "Encountered a FAIL token as lvalue.\n");
+         }
+       | REG
+         {
+             $$ = $1;
+         }
+       | var
+         {
+             $$ = $1;
+         }
+       ;
+
+%%
+
+int main(int argc, char **argv)
+{
+    if (argc != 5) {
+        fprintf(stderr,
+                "Semantics: Hexagon ISA to tinycode generator compiler\n\n");
+        fprintf(stderr,
+                "Usage: ./semantics IDEFS EMITTER_C EMITTER_H "
+                "ENABLED_INSTRUCTIONS_LIST\n");
+        return 1;
+    }
+
+    enum {
+        ARG_INDEX_ARGV0 = 0,
+        ARG_INDEX_IDEFS,
+        ARG_INDEX_EMITTER_C,
+        ARG_INDEX_EMITTER_H,
+        ARG_INDEX_ENABLED_INSTRUCTIONS_LIST
+    };
+
+    FILE *enabled_file = fopen(argv[ARG_INDEX_ENABLED_INSTRUCTIONS_LIST], "w");
+
+    FILE *output_file = fopen(argv[ARG_INDEX_EMITTER_C], "w");
+    fputs("#include \"qemu/osdep.h\"\n", output_file);
+    fputs("#include \"qemu/log.h\"\n", output_file);
+    fputs("#include \"cpu.h\"\n", output_file);
+    fputs("#include \"internal.h\"\n", output_file);
+    fputs("#include \"tcg/tcg-op.h\"\n", output_file);
+    fputs("#include \"insn.h\"\n", output_file);
+    fputs("#include \"opcodes.h\"\n", output_file);
+    fputs("#include \"translate.h\"\n", output_file);
+    fputs("#define QEMU_GENERATE\n", output_file);
+    fputs("#include \"genptr.h\"\n", output_file);
+    fputs("#include \"tcg/tcg.h\"\n", output_file);
+    fputs("#include \"macros.h\"\n", output_file);
+    fprintf(output_file, "#include \"%s\"\n", argv[ARG_INDEX_EMITTER_H]);
+
+    FILE *defines_file = fopen(argv[ARG_INDEX_EMITTER_H], "w");
+    assert(defines_file != NULL);
+    fputs("#ifndef HEX_EMITTER_H\n", defines_file);
+    fputs("#define HEX_EMITTER_H\n", defines_file);
+    fputs("\n", defines_file);
+    fputs("#include \"insn.h\"\n\n", defines_file);
+
+    /* Parser input file */
+    Context context = { 0 };
+    context.defines_file = defines_file;
+    context.output_file = output_file;
+    context.enabled_file = enabled_file;
+    /* Initialize buffers */
+    context.out_str = g_string_new(NULL);
+    context.signature_str = g_string_new(NULL);
+    context.header_str = g_string_new(NULL);
+    context.ternary = g_array_new(FALSE, TRUE, sizeof(Ternary));
+    /* Read input file */
+    FILE *input_file = fopen(argv[ARG_INDEX_IDEFS], "r");
+    fseek(input_file, 0L, SEEK_END);
+    long input_size = ftell(input_file);
+    context.input_buffer = (char *) calloc(input_size + 1, sizeof(char));
+    fseek(input_file, 0L, SEEK_SET);
+    size_t read_chars = fread(context.input_buffer,
+                              sizeof(char),
+                              input_size,
+                              input_file);
+    if (read_chars != (size_t) input_size) {
+        fprintf(stderr, "Error: an error occurred while reading input file!\n");
+        return -1;
+    }
+    yylex_init(&context.scanner);
+    YY_BUFFER_STATE buffer;
+    buffer = yy_scan_string(context.input_buffer, context.scanner);
+    /* Start the parsing procedure */
+    yyparse(context.scanner, &context);
+    if (context.implemented_insn != context.total_insn) {
+        fprintf(stderr,
+                "Warning: %d/%d meta instructions have been implemented!\n",
+                context.implemented_insn,
+                context.total_insn);
+    }
+    fputs("#endif " START_COMMENT " HEX_EMITTER_h " END_COMMENT "\n",
+          defines_file);
+    /* Cleanup */
+    yy_delete_buffer(buffer, context.scanner);
+    yylex_destroy(context.scanner);
+    free(context.input_buffer);
+    g_string_free(context.out_str, TRUE);
+    g_string_free(context.signature_str, TRUE);
+    g_string_free(context.header_str, TRUE);
+    g_array_free(context.ternary, TRUE);
+    fclose(output_file);
+    fclose(input_file);
+    fclose(defines_file);
+    fclose(enabled_file);
+
+    return 0;
+}
diff --git a/target/hexagon/idef-parser/parser-helpers.c b/target/hexagon/idef-parser/parser-helpers.c
new file mode 100644
index 0000000000..b00a680d4a
--- /dev/null
+++ b/target/hexagon/idef-parser/parser-helpers.c
@@ -0,0 +1,2548 @@
+/*
+ * Copyright(c) 2019-2021 rev.ng Labs Srl. 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"
+
+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->str, 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->pred.id >= '0' && value->pred.id <= '3';
+}
+
+bool is_inside_ternary(Context *c)
+{
+    return c->ternary->len > 0;
+}
+
+/* Print functions */
+void str_print(Context *c, YYLTYPE *locp, const char *string)
+{
+    (void) locp;
+    EMIT(c, "%s", string);
+}
+
+void uint8_print(Context *c, YYLTYPE *locp, uint8_t *num)
+{
+    (void) locp;
+    EMIT(c, "%u", *num);
+}
+
+void uint64_print(Context *c, YYLTYPE *locp, uint64_t *num)
+{
+    (void) locp;
+    EMIT(c, "%" PRIu64, *num);
+}
+
+void int_print(Context *c, YYLTYPE *locp, int *num)
+{
+    (void) locp;
+    EMIT(c, "%d", *num);
+}
+
+void uint_print(Context *c, YYLTYPE *locp, unsigned *num)
+{
+    (void) locp;
+    EMIT(c, "%u", *num);
+}
+
+void tmp_print(Context *c, YYLTYPE *locp, HexTmp *tmp)
+{
+    (void) locp;
+    EMIT(c, "tmp_%d", tmp->index);
+}
+
+void pred_print(Context *c, YYLTYPE *locp, HexPred *pred, bool is_dotnew)
+{
+    (void) locp;
+    char suffix = is_dotnew ? 'N' : 'V';
+    EMIT(c, "P%c%c", pred->id, suffix);
+}
+
+void reg_compose(Context *c, YYLTYPE *locp, HexReg *reg, char reg_id[5])
+{
+    memset(reg_id, 0, 5 * sizeof(char));
+    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:
+        reg_id[0] = 'N';
+        reg_id[1] = reg->id;
+        reg_id[2] = 'N';
+        return;
+    }
+    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");
+    }
+}
+
+static void reg_arg_print(Context *c, YYLTYPE *locp, HexReg *reg)
+{
+    char reg_id[5];
+    reg_compose(c, locp, reg, reg_id);
+    EMIT(c, "%s", reg_id);
+}
+
+void reg_print(Context *c, YYLTYPE *locp, HexReg *reg)
+{
+    (void) locp;
+    EMIT(c, "hex_gpr[%u]", 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, "ctx->base.pc_next");
+        break;
+    case IMM_NPC:
+        EMIT(c, "ctx->npc");
+        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)
+{
+    (void) locp;
+    EMIT(c, "%s", var->name->str);
+}
+
+void rvalue_print(Context *c, YYLTYPE *locp, void *pointer)
+{
+  HexValue *rvalue = (HexValue *) pointer;
+  switch (rvalue->type) {
+  case REGISTER:
+      reg_print(c, locp, &rvalue->reg);
+      break;
+  case REGISTER_ARG:
+      reg_arg_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:
+      pred_print(c, locp, &rvalue->pred, rvalue->is_dotnew);
+      break;
+  default:
+      yyassert(c, locp, false, "Cannot print this expression!");
+  }
+}
+
+void out_assert(Context *c, YYLTYPE *locp,
+                void *dummy __attribute__((unused))) {
+    abort();
+    yyassert(c, locp, false, "Unhandled print type!");
+}
+
+/* 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_str->str, sizeof(char), c->signature_str->len,
+           c->output_file);
+    fwrite(c->header_str->str, sizeof(char), c->header_str->len,
+           c->output_file);
+    fwrite(c->out_str->str, sizeof(char), c->out_str->len,
+           c->output_file);
+
+    fwrite(c->signature_str->str, sizeof(char), c->signature_str->len,
+           c->defines_file);
+    fprintf(c->defines_file, ";\n");
+}
+
+static HexValue get_ternary_cond(Context *c, YYLTYPE *locp)
+{
+    yyassert(c, locp, is_inside_ternary(c), "unexisting condition");
+    Ternary *t = &g_array_index(c->ternary, Ternary, 0);
+    HexValue cond = t->cond;
+    if (t->state == IN_RIGHT) {
+        cond = gen_rvalue_notl(c, locp, &cond);
+    }
+    for (unsigned i = 1; i < c->ternary->len; ++i) {
+        Ternary *right = &g_array_index(c->ternary, Ternary, i);
+        HexValue other = right->cond;
+        /* Invert condition if we are on the right side */
+        if (right->state == IN_RIGHT) {
+            other = gen_rvalue_notl(c, locp, &other);
+        }
+        cond = gen_bin_op(c, locp, ANDL_OP, &cond, &other);
+    }
+    return cond;
+}
+
+/* Temporary values creation */
+HexValue gen_tmp(Context *c,
+                 YYLTYPE *locp,
+                 unsigned bit_width,
+                 HexSignedness signedness)
+{
+    HexValue rvalue;
+    memset(&rvalue, 0, sizeof(HexValue));
+    rvalue.type = TEMP;
+    assert(bit_width == 32 || bit_width == 64);
+    rvalue.bit_width = bit_width;
+    rvalue.signedness = signedness;
+    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_temp_new_i", &bit_width, "();\n");
+    c->inst.tmp_count++;
+    return rvalue;
+}
+
+HexValue gen_tmp_value(Context *c,
+                       YYLTYPE *locp,
+                       const char *value,
+                       unsigned bit_width,
+                       HexSignedness signedness)
+{
+    HexValue rvalue;
+    memset(&rvalue, 0, sizeof(HexValue));
+    rvalue.type = TEMP;
+    rvalue.bit_width = bit_width;
+    rvalue.signedness = signedness;
+    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;
+}
+
+static void gen_c_int_type(Context *c, YYLTYPE *locp, unsigned bit_width,
+                           HexSignedness signedness)
+{
+    const char *signstr = (signedness == UNSIGNED) ? "u" : "";
+    OUT(c, locp, signstr, "int", &bit_width, "_t");
+}
+
+static HexValue gen_tmp_value_from_imm(Context *c,
+                                       YYLTYPE *locp,
+                                       HexValue *value)
+{
+    assert(value->type == IMMEDIATE);
+    HexValue rvalue;
+    memset(&rvalue, 0, sizeof(HexValue));
+    rvalue.type = TEMP;
+    rvalue.bit_width = value->bit_width;
+    rvalue.signedness = value->signedness;
+    rvalue.is_dotnew = false;
+    rvalue.is_manual = false;
+    rvalue.tmp.index = c->inst.tmp_count;
+    /*
+     * Here we output the call to `tcg_const_i<width>` in
+     * order to create the temporary value. Note, that we
+     * add a cast
+     *
+     *   `tcg_const_i<width>`((int<width>_t) ...)`
+     *
+     * This cast is required to avoid implicit integer
+     * conversion warnings since all immediates are
+     * output as `((int64_t) 123ULL)`, even if the
+     * integer is 32-bit.
+     */
+    OUT(c, locp, "TCGv_i", &rvalue.bit_width, " tmp_", &c->inst.tmp_count);
+    OUT(c, locp, " = tcg_const_i", &rvalue.bit_width,
+        "((int", &rvalue.bit_width, "_t) (", value, "));\n");
+
+    c->inst.tmp_count++;
+    return rvalue;
+}
+
+HexValue gen_imm_value(Context *c __attribute__((unused)),
+                       YYLTYPE *locp,
+                       int value,
+                       unsigned bit_width,
+                       HexSignedness signedness)
+{
+    (void) locp;
+    HexValue rvalue;
+    memset(&rvalue, 0, sizeof(HexValue));
+    rvalue.type = IMMEDIATE;
+    rvalue.bit_width = bit_width;
+    rvalue.signedness = signedness;
+    rvalue.is_dotnew = false;
+    rvalue.is_manual = false;
+    rvalue.imm.type = VALUE;
+    rvalue.imm.value = value;
+    return rvalue;
+}
+
+HexValue gen_imm_qemu_tmp(Context *c, YYLTYPE *locp, unsigned bit_width,
+                          HexSignedness signedness)
+{
+    (void) locp;
+    HexValue rvalue;
+    memset(&rvalue, 0, sizeof(HexValue));
+    rvalue.type = IMMEDIATE;
+    rvalue.is_dotnew = false;
+    rvalue.is_manual = false;
+    rvalue.bit_width = bit_width;
+    rvalue.signedness = signedness;
+    rvalue.imm.type = QEMU_TMP;
+    rvalue.imm.index = c->inst.qemu_tmp_count++;
+    return rvalue;
+}
+
+void gen_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 gen_rvalue_free_manual(Context *c, YYLTYPE *locp, HexValue *rvalue)
+{
+    rvalue->is_manual = false;
+    gen_rvalue_free(c, locp, rvalue);
+}
+
+HexValue rvalue_materialize(Context *c, YYLTYPE *locp, HexValue *rvalue)
+{
+    if (rvalue->type == IMMEDIATE) {
+        HexValue res = gen_tmp_value_from_imm(c, locp, rvalue);
+        gen_rvalue_free(c, locp, rvalue);
+        return res;
+    }
+    return *rvalue;
+}
+
+HexValue gen_rvalue_extend(Context *c, YYLTYPE *locp, HexValue *rvalue)
+{
+    if (rvalue->bit_width > 32) {
+        return *rvalue;
+    }
+
+    if (rvalue->type == IMMEDIATE) {
+        HexValue res = gen_imm_qemu_tmp(c, locp, 64, rvalue->signedness);
+        bool is_unsigned = (rvalue->signedness == UNSIGNED);
+        const char *sign_suffix = is_unsigned ? "u" : "";
+        gen_c_int_type(c, locp, 64, rvalue->signedness);
+        OUT(c, locp, " ", &res, " = ");
+        OUT(c, locp, "(", sign_suffix, "int64_t) ");
+        OUT(c, locp, "(", sign_suffix, "int32_t) ");
+        OUT(c, locp, rvalue, ";\n");
+        return res;
+    } else {
+        HexValue res = gen_tmp(c, locp, 64, rvalue->signedness);
+        assert_signedness(c, locp, rvalue->signedness);
+        bool is_unsigned = (rvalue->signedness == UNSIGNED);
+        const char *sign_suffix = is_unsigned ? "u" : "";
+        OUT(c, locp, "tcg_gen_ext", sign_suffix,
+            "_i32_i64(", &res, ", ", rvalue, ");\n");
+        gen_rvalue_free(c, locp, rvalue);
+        return res;
+    }
+}
+
+HexValue gen_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, rvalue->signedness);
+            OUT(c, locp, "tcg_gen_trunc_i64_tl(", &res, ", ", rvalue, ");\n");
+            gen_rvalue_free(c, locp, rvalue);
+            return res;
+        }
+    }
+    return *rvalue;
+}
+
+/*
+ * Attempts to lookup the `Var` struct associated with the given `varid`.
+ * The `dst` argument is populated with the found name, bit_width, and
+ * signedness, given that `dst` is non-NULL. Returns true if the lookup
+ * succeeded and false otherwise.
+ */
+static bool try_find_variable(Context *c, YYLTYPE *locp,
+                              HexValue *dst,
+                              HexValue *varid)
+{
+    yyassert(c, locp, varid, "varid to lookup is NULL");
+    yyassert(c, locp, varid->type == VARID,
+             "Can only lookup variables by varid");
+    for (unsigned i = 0; i < c->inst.allocated->len; i++) {
+        Var *curr = &g_array_index(c->inst.allocated, Var, i);
+        if (g_string_equal(varid->var.name, curr->name)) {
+            if (dst) {
+                dst->var.name = curr->name;
+                dst->bit_width = curr->bit_width;
+                dst->signedness = curr->signedness;
+            }
+            return true;
+        }
+    }
+    return false;
+}
+
+/* Calls `try_find_variable` and asserts succcess. */
+static void find_variable(Context *c, YYLTYPE *locp,
+                          HexValue *dst,
+                          HexValue *varid)
+{
+    bool found = try_find_variable(c, locp, dst, varid);
+    yyassert(c, locp, found, "Use of undeclared variable!\n");
+}
+
+void gen_varid_allocate(Context *c,
+                        YYLTYPE *locp,
+                        HexValue *varid,
+                        unsigned bit_width,
+                        HexSignedness signedness)
+{
+    assert_signedness(c, locp, signedness);
+    bool found = try_find_variable(c, locp, NULL, varid);
+    yyassert(c, locp, !found, "Redeclaration of variables not allowed!");
+
+    const char *bit_suffix = (bit_width == 64) ? "i64" : "i32";
+    EMIT_HEAD(c, "TCGv_%s %s", bit_suffix, varid->var.name->str);
+    EMIT_HEAD(c, " = tcg_temp_local_new_%s();\n", bit_suffix);
+    /* `varid` only carries name information */
+    Var new_var = {
+        .name = varid->var.name,
+        .bit_width = bit_width,
+        .signedness = signedness,
+    };
+    g_array_append_val(c->inst.allocated, new_var);
+}
+
+enum OpTypes {
+    IMM_IMM = 0,
+    IMM_REG = 1,
+    REG_IMM = 2,
+    REG_REG = 3,
+};
+
+HexValue gen_bin_cmp(Context *c,
+                     YYLTYPE *locp,
+                     TCGCond type,
+                     HexValue *op1,
+                     HexValue *op2)
+{
+    HexValue op1_m = *op1;
+    HexValue op2_m = *op2;
+    enum OpTypes op_types = (op1_m.type != IMMEDIATE) << 1
+                            | (op2_m.type != IMMEDIATE);
+
+    bool op_is64bit = op1_m.bit_width == 64 || op2_m.bit_width == 64;
+
+    /* Extend to 64-bits, if required */
+    if (op_is64bit) {
+        op1_m = gen_rvalue_extend(c, locp, &op1_m);
+        op2_m = gen_rvalue_extend(c, locp, &op2_m);
+    }
+
+    const char *bit_suffix = op_is64bit ? "i64" : "i32";
+    int bit_width = (op_is64bit) ? 64 : 32;
+    HexValue res = gen_tmp(c, locp, bit_width, UNSIGNED);
+
+    switch (op_types) {
+    case IMM_IMM:
+        OUT(c, locp, "tcg_gen_movi_", bit_suffix,
+            "(", &res, ", ", &op1_m, " == ", &op2_m, ");\n");
+        break;
+    case IMM_REG:
+    {
+        HexValue swp = op2_m;
+        op2_m = op1_m;
+        op1_m = swp;
+        /* Swap comparison direction */
+        type = tcg_swap_cond(type);
+    }
+    /* fallthrough */
+    case REG_IMM:
+        OUT(c, locp, "tcg_gen_setcondi_", bit_suffix, "(");
+        OUT(c, locp, cond_to_str(type), ", ", &res, ", ", &op1_m, ", ", &op2_m,
+            ");\n");
+        break;
+    case REG_REG:
+        OUT(c, locp, "tcg_gen_setcond_", bit_suffix, "(");
+        OUT(c, locp, cond_to_str(type), ", ", &res, ", ", &op1_m, ", ", &op2_m,
+            ");\n");
+        break;
+    default:
+        fprintf(stderr, "Error in evalutating immediateness!");
+        abort();
+    }
+
+    /* Free operands */
+    gen_rvalue_free(c, locp, &op1_m);
+    gen_rvalue_free(c, locp, &op2_m);
+
+    return res;
+}
+
+static void gen_simple_op(Context *c, YYLTYPE *locp, unsigned bit_width,
+                          const char *bit_suffix, HexValue *res,
+                          enum OpTypes op_types,
+                          HexValue *op1,
+                          HexValue *op2,
+                          const char *imm_imm,
+                          const char *imm_reg,
+                          const char *reg_imm,
+                          const char *reg_reg
+                          ) {
+    switch (op_types) {
+    case IMM_IMM: {
+        HexSignedness signedness = (op1->signedness == UNSIGNED
+                                    && op2->signedness == UNSIGNED)
+                                    ? UNSIGNED : SIGNED;
+        gen_c_int_type(c, locp, bit_width, signedness);
+        OUT(c, locp, " ", res,
+            " = ", op1, imm_imm, op2, ";\n");
+    } break;
+    case IMM_REG:
+        OUT(c, locp, imm_reg, bit_suffix,
+            "(", res, ", ", op2, ", ", op1, ");\n");
+        break;
+    case REG_IMM:
+        OUT(c, locp, reg_imm, bit_suffix,
+            "(", res, ", ", op1, ", ", op2, ");\n");
+        break;
+    case REG_REG:
+        OUT(c, locp, reg_reg, bit_suffix,
+            "(", res, ", ", op1, ", ", op2, ");\n");
+        break;
+    }
+    gen_rvalue_free(c, locp, op1);
+    gen_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: {
+        HexSignedness signedness = (op1->signedness == UNSIGNED
+                                    && op2->signedness == UNSIGNED)
+                                    ? UNSIGNED : SIGNED;
+        gen_c_int_type(c, locp, bit_width, signedness);
+        OUT(c, locp, " ", 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;
+    }
+    gen_rvalue_free(c, locp, op1);
+    gen_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, HexValue *op2)
+{
+    HexValue op1_m = *op1;
+    HexValue op2_m = *op2;
+    switch (op_types) {
+    case IMM_IMM: {
+        HexSignedness signedness = (op1->signedness == UNSIGNED
+                                    && op2->signedness == UNSIGNED)
+                                    ? UNSIGNED : SIGNED;
+        gen_c_int_type(c, locp, bit_width, signedness);
+        OUT(c, locp, " ", res,
+            " = ", op1, " << ", op2, ";\n");
+    } break;
+    case REG_IMM: {
+        OUT(c, locp, "if (", op2, " >= ", &bit_width, ") {\n");
+        OUT(c, locp, "tcg_gen_movi_", bit_suffix, "(", res, ", 0);\n");
+        OUT(c, locp, "} else {\n");
+        OUT(c, locp, "tcg_gen_shli_", bit_suffix,
+                "(", res, ", ", op1, ", ", op2, ");\n");
+        OUT(c, locp, "}\n");
+    } break;
+    case IMM_REG:
+        op1_m.bit_width = bit_width;
+        op1_m = rvalue_materialize(c, locp, &op1_m);
+        /* fallthrough */
+    case REG_REG: {
+        OUT(c, locp, "tcg_gen_shl_", bit_suffix,
+            "(", res, ", ", &op1_m, ", ", op2, ");\n");
+    } break;
+    }
+    if (op_types == IMM_REG || op_types == REG_REG) {
+        /*
+         * Handle left shift by 64/32 which hexagon-sim expects to clear out
+         * register
+         */
+        HexValue edge = gen_imm_value(c, locp, bit_width, bit_width, UNSIGNED);
+        edge = rvalue_materialize(c, locp, &edge);
+        HexValue zero = gen_tmp_value(c, locp, "0", bit_width, UNSIGNED);
+        if (op_is64bit) {
+            op2_m = gen_rvalue_extend(c, locp, &op2_m);
+        }
+        op1_m = rvalue_materialize(c, locp, &op1_m);
+        op2_m = rvalue_materialize(c, locp, &op2_m);
+        OUT(c, locp, "tcg_gen_movcond_i", &bit_width);
+        OUT(c, locp, "(TCG_COND_GEU, ", res, ", ", &op2_m, ", ", &edge);
+        OUT(c, locp, ", ", &zero, ", ", res, ");\n");
+        gen_rvalue_free(c, locp, &edge);
+        gen_rvalue_free(c, locp, &zero);
+    }
+    gen_rvalue_free(c, locp, &op1_m);
+    gen_rvalue_free(c, locp, &op2_m);
+}
+
+static void gen_asr_op(Context *c, YYLTYPE *locp, unsigned bit_width,
+                       bool op_is64bit, const char *bit_suffix,
+                       HexValue *res, enum OpTypes op_types,
+                       HexValue *op1, HexValue *op2)
+{
+    HexValue op1_m = *op1;
+    HexValue op2_m = *op2;
+    switch (op_types) {
+    case IMM_IMM: {
+        HexSignedness signedness = (op1->signedness == UNSIGNED
+                                    && op2->signedness == UNSIGNED)
+                                    ? UNSIGNED : SIGNED;
+        gen_c_int_type(c, locp, bit_width, signedness);
+        OUT(c, locp, " ", res,
+            " = ", op1, " >> ", op2, ";\n");
+    } break;
+    case REG_IMM: {
+        OUT(c, locp, "{\n");
+        HexSignedness signedness = (op1->signedness == UNSIGNED
+                                    && op2->signedness == UNSIGNED)
+                                    ? UNSIGNED : SIGNED;
+        gen_c_int_type(c, locp, bit_width, signedness);
+        OUT(c, locp, " shift = ", op2, ";\n");
+        OUT(c, locp, "if (", op2, " >= ", &bit_width, ") {\n");
+        OUT(c, locp, "    shift = ", &bit_width, " - 1;\n");
+        OUT(c, locp, "}\n");
+        OUT(c, locp, "tcg_gen_sari_", bit_suffix,
+            "(", res, ", ", op1, ", shift);\n}\n");
+    } break;
+    case IMM_REG:
+        op1_m = rvalue_materialize(c, locp, &op1_m);
+        /* Fallthrough */
+    case REG_REG:
+        OUT(c, locp, "tcg_gen_sar_", bit_suffix,
+            "(", res, ", ", &op1_m, ", ", op2, ");\n");
+        break;
+    }
+    if (op_types == IMM_REG ||  op_types == REG_REG) {
+        /* Handle right shift by values >= bit_width */
+        HexValue edge = gen_imm_value(c, locp, bit_width, bit_width, UNSIGNED);
+        edge = rvalue_materialize(c, locp, &edge);
+        HexValue tmp = gen_tmp(c, locp, bit_width, SIGNED);
+        HexValue zero = gen_tmp_value(c, locp, "0", bit_width, SIGNED);
+        if (op_is64bit) {
+            op2_m = gen_rvalue_extend(c, locp, &op2_m);
+        }
+        op1_m = rvalue_materialize(c, locp, &op1_m);
+        op2_m = rvalue_materialize(c, locp, &op2_m);
+
+        const char *offset = op_is64bit ? "63" : "31";
+        OUT(c, locp, "tcg_gen_extract_", bit_suffix, "(",
+            &tmp, ", ", &op1_m, ", ", offset, ", 1);\n");
+        OUT(c, locp, "tcg_gen_sub_", bit_suffix, "(",
+            &tmp, ", ", &zero, ", ", &tmp, ");\n");
+        OUT(c, locp, "tcg_gen_movcond_i", &bit_width);
+        OUT(c, locp, "(TCG_COND_GEU, ", res, ", ", &op2_m, ", ", &edge);
+        OUT(c, locp, ", ", &tmp, ", ", res, ");\n");
+        gen_rvalue_free(c, locp, &edge);
+        gen_rvalue_free(c, locp, &tmp);
+        gen_rvalue_free(c, locp, &zero);
+    }
+    gen_rvalue_free(c, locp, &op1_m);
+    gen_rvalue_free(c, locp, &op2_m);
+}
+
+static void gen_lsr_op(Context *c, YYLTYPE *locp, unsigned bit_width,
+                       bool op_is64bit, const char *bit_suffix,
+                       HexValue *res, enum OpTypes op_types,
+                       HexValue *op1, HexValue *op2)
+{
+    HexValue op1_m = *op1;
+    HexValue op2_m = *op2;
+    switch (op_types) {
+    case IMM_IMM: {
+        HexSignedness signedness = (op1->signedness == UNSIGNED
+                                    && op2->signedness == UNSIGNED)
+                                    ? UNSIGNED : SIGNED;
+        gen_c_int_type(c, locp, bit_width, signedness);
+        OUT(c, locp, ",  ",
+            res, " = ", op1, " >> ", op2, ";\n");
+    } break;
+    case REG_IMM:
+        OUT(c, locp, "if (", op2, " >= ", &bit_width, ") {\n");
+        OUT(c, locp, "tcg_gen_movi_", bit_suffix, "(", res, ", 0);\n");
+        OUT(c, locp, "} else {\n");
+        OUT(c, locp, "tcg_gen_shri_", bit_suffix,
+            "(", res, ", ", op1, ", ", op2, ");\n");
+        OUT(c, locp, "}\n");
+        break;
+    case IMM_REG:
+        op1_m = rvalue_materialize(c, locp, &op1_m);
+        /* Fallthrough */
+    case REG_REG:
+        OUT(c, locp, "tcg_gen_shr_", bit_suffix,
+            "(", res, ", ", &op1_m, ", ", op2, ");\n");
+        break;
+    }
+    if (op_types == IMM_REG ||  op_types == REG_REG) {
+        /* Handle right shift by values >= bit_width */
+        HexValue edge = gen_imm_value(c, locp, bit_width, bit_width, UNSIGNED);
+        edge = rvalue_materialize(c, locp, &edge);
+        HexValue zero = gen_tmp_value(c, locp, "0", bit_width, UNSIGNED);
+        if (op_is64bit) {
+            op2_m = gen_rvalue_extend(c, locp, &op2_m);
+        }
+        op1_m = rvalue_materialize(c, locp, &op1_m);
+        op2_m = rvalue_materialize(c, locp, &op2_m);
+        OUT(c, locp, "tcg_gen_movcond_i", &bit_width);
+        OUT(c, locp, "(TCG_COND_GEU, ", res, ", ", &op2_m, ", ", &edge);
+        OUT(c, locp, ", ", &zero, ", ", res, ");\n");
+        gen_rvalue_free(c, locp, &edge);
+        gen_rvalue_free(c, locp, &zero);
+    }
+    gen_rvalue_free(c, locp, &op1_m);
+    gen_rvalue_free(c, locp, &op2_m);
+}
+
+/*
+ * Note: This implementation of logical `and` does not mirror that in C.
+ * We do not short-circuit logical expressions!
+ */
+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;
+    memset(&zero, 0, sizeof(HexValue));
+    memset(&tmp1, 0, sizeof(HexValue));
+    memset(&tmp2, 0, sizeof(HexValue));
+    switch (op_types) {
+    case IMM_IMM: {
+        HexSignedness signedness = (op1->signedness == UNSIGNED
+                                    && op2->signedness == UNSIGNED)
+                                    ? UNSIGNED : SIGNED;
+        gen_c_int_type(c, locp, bit_width, signedness);
+        OUT(c, locp, " ",
+            res, " = ", op1, " && ", op2, ";\n");
+    } break;
+    case IMM_REG:
+        zero = gen_tmp_value(c, locp, "0", 32, UNSIGNED);
+        tmp2 = gen_bin_cmp(c, locp, TCG_COND_NE, op2, &zero);
+        OUT(c, locp, "tcg_gen_andi_", bit_suffix,
+            "(", res, ", ", op1, " != 0 , ", &tmp2, ");\n");
+        gen_rvalue_free(c, locp, &tmp2);
+        break;
+    case REG_IMM:
+        zero = gen_tmp_value(c, locp, "0", 32, UNSIGNED);
+        tmp1 = gen_bin_cmp(c, locp, TCG_COND_NE, op1, &zero);
+        OUT(c, locp, "tcg_gen_andi_", bit_suffix,
+            "(", res, ", ", &tmp1, ", ", op2, " != 0);\n");
+        gen_rvalue_free(c, locp, &tmp1);
+        break;
+    case REG_REG:
+        zero = gen_tmp_value(c, locp, "0", 32, UNSIGNED);
+        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");
+        gen_rvalue_free_manual(c, locp, &zero);
+        gen_rvalue_free(c, locp, &tmp1);
+        gen_rvalue_free(c, locp, &tmp2);
+        break;
+    }
+}
+
+static void gen_minmax_op(Context *c, YYLTYPE *locp, unsigned bit_width,
+                          HexValue *res, enum OpTypes op_types,
+                          HexValue *op1, HexValue *op2, bool minmax)
+{
+    HexValue op1_m = *op1;
+    HexValue op2_m = *op2;
+    const char *mm;
+    assert_signedness(c, locp, res->signedness);
+    bool is_unsigned = res->signedness == UNSIGNED;
+    if (minmax) {
+        /* Max */
+        mm = is_unsigned ? "tcg_gen_umax" : "tcg_gen_smax";
+    } else {
+        /* Min */
+        mm = is_unsigned ? "tcg_gen_umin" : "tcg_gen_smin";
+    }
+    switch (op_types) {
+    case IMM_IMM: {
+        const char *s = minmax ? " <= " : " >= ";
+        HexSignedness signedness = (op1->signedness == UNSIGNED
+                                    && op2->signedness == UNSIGNED)
+                                    ? UNSIGNED : SIGNED;
+        gen_c_int_type(c, locp, bit_width, signedness);
+        OUT(c, locp, " ", res, " = (", op1, s);
+        OUT(c, locp, op2, ") ? ", op1, " : ", op2, ";\n");
+    } break;
+    case IMM_REG:
+        op1_m.bit_width = bit_width;
+        op1_m = rvalue_materialize(c, locp, &op1_m);
+        OUT(c, locp, mm, "_i", &bit_width, "(");
+        OUT(c, locp, res, ", ", &op1_m, ", ", op2, ");\n");
+        break;
+    case REG_IMM:
+        op2_m.bit_width = bit_width;
+        op2_m = rvalue_materialize(c, locp, &op2_m);
+        /* Fallthrough */
+    case REG_REG:
+        OUT(c, locp, mm, "_i", &bit_width, "(");
+        OUT(c, locp, res, ", ", op1, ", ", &op2_m, ");\n");
+        break;
+    }
+    gen_rvalue_free(c, locp, &op1_m);
+    gen_rvalue_free(c, locp, &op2_m);
+}
+
+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: {
+        HexSignedness signedness = (op1->signedness == UNSIGNED
+                                    && op2->signedness == UNSIGNED)
+                                    ? UNSIGNED : SIGNED;
+        gen_c_int_type(c, locp, res->bit_width, signedness);
+        OUT(c, locp, " ", 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;
+    }
+    gen_rvalue_free(c, locp, op1);
+    gen_rvalue_free(c, locp, op2);
+}
+
+/* Code generation functions */
+HexValue gen_bin_op(Context *c,
+                    YYLTYPE *locp,
+                    OpType type,
+                    HexValue *op1,
+                    HexValue *op2)
+{
+    /* Replicate operands to avoid side effects */
+    HexValue op1_m = *op1;
+    HexValue op2_m = *op2;
+
+    /*
+     * If the operands are VARID's we need to look up the
+     * type information.
+     */
+    if (op1_m.type == VARID) {
+        find_variable(c, locp, &op1_m, &op1_m);
+    }
+    if (op2_m.type == VARID) {
+        find_variable(c, locp, &op2_m, &op2_m);
+    }
+
+    enum OpTypes op_types = (op1_m.type != IMMEDIATE) << 1
+                            | (op2_m.type != IMMEDIATE);
+
+    bool op_is64bit = op1_m.bit_width == 64 || op2_m.bit_width == 64;
+
+    /* Shift greater than 32 are 64 bits wide */
+    if (type == ASL_OP && op2_m.type == IMMEDIATE &&
+        op2_m.imm.type == VALUE && op2_m.imm.value >= 32) {
+        op_is64bit = true;
+    }
+
+    /* Extend to 64-bits, if required */
+    if (op_is64bit) {
+        op1_m = gen_rvalue_extend(c, locp, &op1_m);
+        op2_m = gen_rvalue_extend(c, locp, &op2_m);
+    }
+
+    HexValue res;
+    memset(&res, 0, sizeof(HexValue));
+    const char *bit_suffix = op_is64bit ? "i64" : "i32";
+    int bit_width = (op_is64bit) ? 64 : 32;
+    /* Handle signedness, if both unsigned -> result is unsigned, else signed */
+    assert_signedness(c, locp, op1_m.signedness);
+    assert_signedness(c, locp, op2_m.signedness);
+    HexSignedness signedness = (op1_m.signedness == UNSIGNED
+                                && op2_m.signedness == UNSIGNED)
+                                ? UNSIGNED : SIGNED;
+    if (op_types != IMM_IMM) {
+        res = gen_tmp(c, locp, bit_width, signedness);
+    } else {
+        res = gen_imm_qemu_tmp(c, locp, bit_width, signedness);
+    }
+
+    switch (type) {
+    case ADD_OP:
+        gen_simple_op(c, locp, bit_width, bit_suffix, &res,
+                      op_types, &op1_m, &op2_m,
+                      " + ",
+                      "tcg_gen_addi_",
+                      "tcg_gen_addi_",
+                      "tcg_gen_add_");
+        break;
+    case SUB_OP:
+        gen_sub_op(c, locp, bit_width, bit_suffix, &res, op_types,
+                   &op1_m, &op2_m);
+        break;
+    case MUL_OP:
+        gen_simple_op(c, locp, bit_width, bit_suffix, &res,
+                      op_types, &op1_m, &op2_m,
+                      " * ",
+                      "tcg_gen_muli_",
+                      "tcg_gen_muli_",
+                      "tcg_gen_mul_");
+        break;
+    case ASL_OP:
+        gen_asl_op(c, locp, bit_width, op_is64bit, bit_suffix, &res, op_types,
+                   &op1_m, &op2_m);
+        break;
+    case ASR_OP:
+        gen_asr_op(c, locp, bit_width, op_is64bit, bit_suffix, &res, op_types,
+                   &op1_m, &op2_m);
+        break;
+    case LSR_OP:
+        gen_lsr_op(c, locp, bit_width, op_is64bit, bit_suffix, &res, op_types,
+                   &op1_m, &op2_m);
+        break;
+    case ANDB_OP:
+        gen_simple_op(c, locp, bit_width, bit_suffix, &res,
+                      op_types, &op1_m, &op2_m,
+                      " & ",
+                      "tcg_gen_andi_",
+                      "tcg_gen_andi_",
+                      "tcg_gen_and_");
+        break;
+    case ORB_OP:
+        gen_simple_op(c, locp, bit_width, bit_suffix, &res,
+                      op_types, &op1_m, &op2_m,
+                      " | ",
+                      "tcg_gen_ori_",
+                      "tcg_gen_ori_",
+                      "tcg_gen_or_");
+        break;
+    case XORB_OP:
+        gen_simple_op(c, locp, bit_width, bit_suffix, &res,
+                      op_types, &op1_m, &op2_m,
+                      " ^ ",
+                      "tcg_gen_xori_",
+                      "tcg_gen_xori_",
+                      "tcg_gen_xor_");
+        break;
+    case ANDL_OP:
+        gen_andl_op(c, locp, bit_width, bit_suffix, &res, op_types, &op1_m,
+                    &op2_m);
+        break;
+    case MINI_OP:
+        gen_minmax_op(c, locp, bit_width, &res, op_types, &op1_m, &op2_m,
+                      false);
+        break;
+    case MAXI_OP:
+        gen_minmax_op(c, locp, bit_width, &res, op_types, &op1_m, &op2_m, true);
+        break;
+    case MOD_OP:
+        gen_mod_op(c, locp, &res, op_types, &op1_m, &op2_m);
+        break;
+    }
+    return res;
+}
+
+HexValue gen_cast_op(Context *c,
+                     YYLTYPE *locp,
+                     HexValue *src,
+                     unsigned target_width,
+                     HexSignedness signedness)
+{
+    if (src->bit_width == target_width) {
+        return *src;
+    } else if (src->type == IMMEDIATE) {
+        HexValue res = *src;
+        res.bit_width = target_width;
+        res.signedness = signedness;
+        return res;
+    } else {
+        HexValue res = gen_tmp(c, locp, target_width, signedness);
+        /* Truncate */
+        if (src->bit_width > target_width) {
+            OUT(c, locp, "tcg_gen_trunc_i64_tl(", &res, ", ", src, ");\n");
+        } else {
+            assert_signedness(c, locp, src->signedness);
+            if (src->signedness == UNSIGNED) {
+                /* Extend unsigned */
+                OUT(c, locp, "tcg_gen_extu_i32_i64(",
+                    &res, ", ", src, ");\n");
+            } else {
+                /* Extend signed */
+                OUT(c, locp, "tcg_gen_ext_i32_i64(",
+                    &res, ", ", src, ");\n");
+            }
+        }
+        gen_rvalue_free(c, locp, src);
+        return res;
+    }
+}
+
+
+/*
+ * Implements an extension when the `src_width` is an immediate.
+ * If the `value` to extend is also an immediate we use `extract/sextract`
+ * from QEMU `bitops.h`. If `value` is a TCGv then we rely on
+ * `tcg_gen_extract/tcg_gen_sextract`.
+ */
+static HexValue gen_extend_imm_width_op(Context *c,
+                                        YYLTYPE *locp,
+                                        HexValue *src_width,
+                                        unsigned dst_width,
+                                        HexValue *value,
+                                        HexSignedness signedness)
+{
+    assert(dst_width == 64 || dst_width == 32);
+    assert(src_width->type == IMMEDIATE);
+
+    if (src_width->imm.type == VALUE &&
+        src_width->imm.value == 0) {
+        /*
+         * We can bail out early if the source width is known to be zero
+         * at translation time.
+         */
+        HexValue res = gen_imm_value(c, locp, 0, dst_width, signedness);
+        return res;
+    }
+
+    const char *sign_prefix = (signedness == UNSIGNED) ? "" : "s";
+
+    /*
+     * If the source width is not an immediate value, we need to guard
+     * our extend op with if statements to handle the case where
+     * `src_width_m` is 0.
+     */
+    bool need_guarding = (src_width->imm.type != VALUE);
+
+    if (value->type == IMMEDIATE) {
+        /*
+         * If both the value and source width are immediates,
+         * we can perform the extension at translation time
+         * using QEMUs bitops.
+         */
+        HexValue res = gen_imm_qemu_tmp(c, locp, dst_width, signedness);
+        gen_c_int_type(c, locp, dst_width, signedness);
+        OUT(c, locp, " ", &res, " = 0;\n");
+        if (need_guarding) {
+            OUT(c, locp, "if (", src_width, " != 0) {\n");
+        }
+        OUT(c, locp, &res, " = ", sign_prefix, "extract", &dst_width);
+        OUT(c, locp, "(", value, ", 0, ", src_width, ");\n");
+        if (need_guarding) {
+            OUT(c, locp, "}\n");
+        }
+
+        gen_rvalue_free(c, locp, value);
+        return res;
+    } else {
+        /*
+         * If the source width is an immediate and the value to
+         * extend is a TCGv, then use tcg_gen_extract/tcg_gen_sextract
+         */
+        HexValue res = gen_tmp(c, locp, dst_width, signedness);
+
+        /*
+         * If the width is an immediate value we know it is non-zero
+         * at this point, otherwise we need an if-statement
+         */
+        if (need_guarding) {
+            OUT(c, locp, "if (", src_width, " != 0) {\n");
+        }
+        OUT(c, locp, "tcg_gen_", sign_prefix, "extract_i", &dst_width);
+        OUT(c, locp, "(", &res, ", ", value, ", 0, ", src_width,
+            ");\n");
+        if (need_guarding) {
+            OUT(c, locp, "} else {\n");
+            OUT(c, locp, "tcg_gen_movi_i", &dst_width, "(", &res,
+                ", 0);\n");
+            OUT(c, locp, "}\n");
+        }
+
+        gen_rvalue_free(c, locp, value);
+        return res;
+    }
+}
+
+/*
+ * Implements an extension when the `src_width` is given by
+ * a TCGv. Here we need to reimplement the behaviour of
+ * `tcg_gen_extract` and the like using shifts and masks.
+ */
+static HexValue gen_extend_tcg_width_op(Context *c,
+                                        YYLTYPE *locp,
+                                        HexValue *src_width,
+                                        unsigned dst_width,
+                                        HexValue *value,
+                                        HexSignedness signedness)
+{
+    assert(dst_width == 64 || dst_width == 32);
+    assert(src_width->type != IMMEDIATE);
+
+    HexValue src_width_m = rvalue_materialize(c, locp, src_width);
+
+    HexValue res = gen_tmp(c, locp, dst_width, signedness);
+    HexValue zero = gen_tmp_value(c, locp, "0", dst_width, UNSIGNED);
+    HexValue shift = gen_tmp(c, locp, dst_width, UNSIGNED);
+    OUT(c, locp, "tcg_gen_subfi_i", &dst_width);
+    OUT(c, locp, "(", &shift, ", ", &dst_width, ", ", &src_width_m, ");\n");
+    if (signedness == UNSIGNED) {
+        const char *mask_str = (dst_width == 32)
+            ? "0xffffffff"
+            : "0xffffffffffffffff";
+        HexValue mask = gen_tmp_value(c, locp, mask_str,
+                                      dst_width, UNSIGNED);
+        OUT(c, locp, "tcg_gen_shr_i", &dst_width, "(",
+            &mask, ", ", &mask, ", ", &shift, ");\n");
+        OUT(c, locp, "tcg_gen_and_i", &dst_width, "(",
+            &res, ", ", value, ", ", &mask, ");\n");
+        gen_rvalue_free(c, locp, &mask);
+    } else {
+        OUT(c, locp, "tcg_gen_shl_i", &dst_width, "(",
+            &res, ", ", value, ", ", &shift, ");\n");
+        OUT(c, locp, "tcg_gen_sar_i", &dst_width, "(",
+            &res, ", ", &res, ", ", &shift, ");\n");
+    }
+    OUT(c, locp, "tcg_gen_movcond_i", &dst_width, "(TCG_COND_EQ, ", &res,
+        ", ");
+    OUT(c, locp, &src_width_m, ", ", &zero, ", ", &zero, ", ", &res,
+        ");\n");
+
+    gen_rvalue_free(c, locp, &src_width_m);
+    gen_rvalue_free(c, locp, value);
+    gen_rvalue_free(c, locp, &shift);
+    gen_rvalue_free(c, locp, &zero);
+
+    return res;
+}
+
+HexValue gen_extend_op(Context *c,
+                       YYLTYPE *locp,
+                       HexValue *src_width,
+                       unsigned dst_width,
+                       HexValue *value,
+                       HexSignedness signedness)
+{
+    assert_signedness(c, locp, signedness);
+    unsigned bit_width = (dst_width = 64) ? 64 : 32;
+
+    HexValue value_m = *value;
+    if (value_m.bit_width < bit_width) {
+        value_m = gen_rvalue_extend(c, locp, &value_m);
+    } else if (value_m.bit_width > bit_width) {
+        value_m = gen_rvalue_truncate(c, locp, &value_m);
+    }
+
+    HexValue src_width_m = *src_width;
+    if (src_width_m.bit_width < bit_width) {
+        src_width_m = gen_rvalue_extend(c, locp, &src_width_m);
+    } else if (src_width_m.bit_width > bit_width) {
+        src_width_m = gen_rvalue_truncate(c, locp, &src_width_m);
+    }
+
+    if (src_width_m.type == IMMEDIATE) {
+        return gen_extend_imm_width_op(c, locp, &src_width_m, bit_width,
+                                       &value_m, signedness);
+    } else {
+        return gen_extend_tcg_width_op(c, locp, &src_width_m, bit_width,
+                                       &value_m, signedness);
+    }
+}
+
+/*
+ * Implements `rdeposit` for the special case where `width` is
+ * of immediate type. Here we rely on `tcg_gen_deposit_*` to
+ * perform the deposit.
+ */
+static void gen_rdeposit_imm_width_op(Context *c,
+                                       YYLTYPE *locp,
+                                       HexValue *dst,
+                                       HexValue *value,
+                                       HexValue *begin,
+                                       HexValue *width)
+{
+    /*
+     * If the width of the deposit op is known at translatin time
+     * we can rely on tcg_gen_deposit
+     */
+
+    /* If the width is known to be 0, just no-op */
+    if (width->imm.type == VALUE && width->imm.value == 0) {
+        return;
+    }
+
+    /*
+     * If the width is an immediate value we know it is non-zero
+     * at this point, otherwise we need an if-statement
+     */
+    if (width->imm.type != VALUE) {
+        OUT(c, locp, "if (", width, " > 0) {\n");
+    }
+    OUT(c, locp, "tcg_gen_deposit_i", &dst->bit_width, "(", dst, ", ");
+    OUT(c, locp, dst, ", ", value, ", ", &begin->imm.value, ", ",
+        width, ");\n");
+    if (width->imm.type != VALUE) {
+        OUT(c, locp, "}\n");
+    }
+}
+
+/*
+ * Implements `rdeposit` for the special case where `width`
+ * is of TCGv type. In this case we need to reimplement the behaviour
+ * of `tcg_gen_deposit*` using binary operations and masks/shifts.
+ */
+static void gen_rdeposit_tcg_width_op(Context *c,
+                                      YYLTYPE *locp,
+                                      HexValue *dst,
+                                      HexValue *value,
+                                      HexValue *begin,
+                                      HexValue *width)
+{
+    /*
+     * Otherwise if the width is not known, we fallback on reimplementing
+     * desposit in TCG.
+     */
+    HexValue value_m = *value;
+    if (value_m.bit_width < dst->bit_width) {
+        value_m = gen_rvalue_extend(c, locp, &value_m);
+    } else if (value_m.bit_width > dst->bit_width) {
+        value_m = gen_rvalue_truncate(c, locp, &value_m);
+    }
+    HexValue begin_m = *begin;
+    if (begin_m.bit_width < dst->bit_width) {
+        begin_m = gen_rvalue_extend(c, locp, &begin_m);
+    } else if (begin_m.bit_width > dst->bit_width) {
+        begin_m = gen_rvalue_truncate(c, locp, &begin_m);
+    }
+    HexValue width_orig = *width;
+    width_orig.is_manual = true;
+    HexValue width_m = width_orig;
+    if (width_m.bit_width < dst->bit_width) {
+        width_m = gen_rvalue_extend(c, locp, &width_orig);
+    } else if (width_m.bit_width > dst->bit_width) {
+        width_m = gen_rvalue_truncate(c, locp, &width_orig);
+    }
+    width_m = rvalue_materialize(c, locp, &width_m);
+
+    const char *mask_str = (dst->bit_width == 32)
+        ? "0xffffffffUL"
+        : "0xffffffffffffffffUL";
+    HexValue mask = gen_tmp_value(c, locp, mask_str, dst->bit_width,
+                                  UNSIGNED);
+    /*
+     * mask = 0xffffffffffffffff >> (64 - width)
+     * mask = mask << begin
+     * value = (value << begin) & mask
+     * res = dst & ~mask
+     * res = res | value
+     * dst = (width != 0) ? res : dst
+     */
+    mask.signedness = UNSIGNED;
+    const char *dst_width_str = (dst->bit_width == 32) ? "32" : "64";
+    HexValue k64 = gen_tmp_value(c, locp, dst_width_str, dst->bit_width,
+                                 UNSIGNED);
+    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_i", &dst->bit_width, "(", &mask, ", ",
+        &mask, ");\n");
+    mask.is_manual = false;
+    HexValue res = gen_bin_op(c, locp, ANDB_OP, dst, &mask);
+    res = gen_bin_op(c, locp, ORB_OP, &res, &value_m);
+
+    if (dst->bit_width != res.bit_width) {
+        res = gen_rvalue_truncate(c, locp, &res);
+    }
+
+    /* If the width is zero, then return the identity dst = dst */
+    HexValue zero = gen_tmp_value(c, locp, "0", res.bit_width, UNSIGNED);
+    OUT(c, locp, "tcg_gen_movcond_i", &res.bit_width, "(TCG_COND_NE, ",
+        dst);
+    OUT(c, locp, ", ", &width_orig, ", ", &zero, ", ", &res, ", ", dst,
+        ");\n");
+
+    gen_rvalue_free(c, locp, &zero);
+    gen_rvalue_free(c, locp, width);
+    gen_rvalue_free(c, locp, &res);
+}
+
+
+void gen_rdeposit_op(Context *c,
+                     YYLTYPE *locp,
+                     HexValue *dst,
+                     HexValue *value,
+                     HexValue *begin,
+                     HexValue *width)
+{
+    assert(dst->bit_width >= value->bit_width);
+    assert(begin->type == IMMEDIATE && begin->imm.type == VALUE);
+    assert(dst->type == REGISTER_ARG);
+    HexValue dst_m = *dst;
+    dst_m.is_manual = true;
+
+    if (width->type == IMMEDIATE) {
+        gen_rdeposit_imm_width_op(c, locp, &dst_m, value, begin, width);
+    } else {
+        gen_rdeposit_tcg_width_op(c, locp, &dst_m, value, begin, width);
+    }
+}
+
+void gen_deposit_op(Context *c,
+                    YYLTYPE *locp,
+                    HexValue *dst,
+                    HexValue *value,
+                    HexValue *index,
+                    HexCast *cast)
+{
+    yyassert(c, locp, index->type == IMMEDIATE,
+             "Deposit index must be immediate!\n");
+
+    /*
+     * Using tcg_gen_deposit_i**(dst, dst, ...) requires dst to be
+     * initialized.
+     */
+    gen_inst_init_args(c, locp);
+
+    HexValue value_m = *value;
+    int bit_width = (dst->bit_width == 64) ? 64 : 32;
+    int width = cast->bit_width;
+    /* If the destination value is 32, truncate the value, otherwise extend */
+    if (dst->bit_width != value->bit_width) {
+        if (bit_width == 32) {
+            value_m = gen_rvalue_truncate(c, locp, &value_m);
+        } else {
+            value_m = gen_rvalue_extend(c, locp, &value_m);
+        }
+    }
+    value_m = rvalue_materialize(c, locp, &value_m);
+    OUT(c, locp, "tcg_gen_deposit_i", &bit_width, "(", dst, ", ", dst, ", ");
+    OUT(c, locp, &value_m, ", ", index, " * ", &width, ", ", &width, ");\n");
+    gen_rvalue_free(c, locp, index);
+    gen_rvalue_free(c, locp, &value_m);
+}
+
+HexValue gen_rextract_op(Context *c,
+                         YYLTYPE *locp,
+                         HexValue *src,
+                         int begin,
+                         int width)
+{
+    int bit_width = (src->bit_width == 64) ? 64 : 32;
+    HexValue res = gen_tmp(c, locp, bit_width, UNSIGNED);
+    OUT(c, locp, "tcg_gen_extract_i", &bit_width, "(", &res);
+    OUT(c, locp, ", ", src, ", ", &begin, ", ", &width, ");\n");
+    gen_rvalue_free(c, locp, src);
+    return res;
+}
+
+HexValue gen_extract_op(Context *c,
+                        YYLTYPE *locp,
+                        HexValue *src,
+                        HexValue *index,
+                        HexExtract *extract)
+{
+    yyassert(c, locp, index->type == IMMEDIATE,
+             "Extract index must be immediate!\n");
+    int bit_width = (src->bit_width == 64) ? 64 : 32;
+    assert_signedness(c, locp, extract->signedness);
+    const char *sign_prefix = (extract->signedness == UNSIGNED) ? "" : "s";
+    int width = extract->bit_width;
+    HexValue res = gen_tmp(c, locp, bit_width, extract->signedness);
+    OUT(c, locp, "tcg_gen_", sign_prefix, "extract_i", &bit_width,
+        "(", &res, ", ", src);
+    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,
+                               extract->signedness);
+        if (extract->signedness == 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");
+        }
+        gen_rvalue_free(c, locp, &res);
+        res = tmp;
+    }
+
+    gen_rvalue_free(c, locp, src);
+    gen_rvalue_free(c, locp, index);
+    return res;
+}
+
+HexValue gen_read_reg(Context *c, YYLTYPE *locp, HexValue *reg)
+{
+    yyassert(c, locp, reg->type == REGISTER_ARG || reg->type == REGISTER,
+             "reg must be a register arg or register!");
+    if (reg->type == REGISTER) {
+        HexValue tmp = gen_tmp(c, locp, 32, reg->signedness);
+        OUT(c, locp, "gen_read_reg(", &tmp, ", ", &reg->reg.id, ");\n");
+        gen_rvalue_free(c, locp, reg);
+        return tmp;
+    }
+    return *reg;
+}
+
+void gen_write_reg(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 = gen_rvalue_truncate(c, locp, &value_m);
+    value_m = rvalue_materialize(c, locp, &value_m);
+    OUT(c,
+        locp,
+        "gen_log_reg_write(", &reg->reg.id, ", ",
+        &value_m, ");\n");
+    OUT(c,
+        locp,
+        "ctx_log_reg_write(ctx, ", &reg->reg.id,
+        ");\n");
+    gen_rvalue_free(c, locp, reg);
+    gen_rvalue_free(c, locp, &value_m);
+}
+
+void gen_assign(Context *c,
+                YYLTYPE *locp,
+                HexValue *dst,
+                HexValue *value)
+{
+    yyassert(c,
+             locp,
+             !is_inside_ternary(c)
+             || !(dst->type == REGISTER),
+             "register assign in ternary");
+
+    HexValue value_m = *value;
+    if (dst->type == REGISTER) {
+        gen_write_reg(c, locp, dst, &value_m);
+        return;
+    }
+
+    if (dst->type == VARID) {
+        find_variable(c, locp, dst, dst);
+    }
+
+    unsigned bit_width = dst->bit_width == 64 ? 64 : 32;
+    if (bit_width != value_m.bit_width) {
+        if (bit_width == 64) {
+            value_m = gen_rvalue_extend(c, locp, &value_m);
+        } else {
+            value_m = gen_rvalue_truncate(c, locp, &value_m);
+        }
+    }
+    if (is_inside_ternary(c)) {
+        value_m = rvalue_materialize(c, locp, &value_m);
+        HexValue cond = get_ternary_cond(c, locp);
+        if (cond.bit_width != bit_width) {
+            if (cond.bit_width == 64) {
+                cond = gen_rvalue_truncate(c, locp, &cond);
+            } else {
+                cond = gen_rvalue_extend(c, locp, &cond);
+            }
+        }
+        HexValue zero = gen_tmp_value(c, locp, "0", bit_width, UNSIGNED);
+        OUT(c, locp, "tcg_gen_movcond_i", &bit_width, "(TCG_COND_NE, ", dst);
+        OUT(c, locp, ", ", &cond, ", ", &zero, ", ");
+        OUT(c, locp, &value_m, ", ", dst, ");\n");
+        gen_rvalue_free(c, locp, &cond);
+        gen_rvalue_free(c, locp, &zero);
+    } else {
+        if (value_m.type == IMMEDIATE) {
+            OUT(c, locp, "tcg_gen_movi_i", &bit_width,
+                "(", dst, ", ", &value_m, ");\n");
+        } else {
+            OUT(c, locp, "tcg_gen_mov_i", &bit_width,
+                "(", dst, ", ", &value_m, ");\n");
+        }
+    }
+    gen_rvalue_free(c, locp, &value_m);
+}
+
+HexValue gen_convround(Context *c,
+                       YYLTYPE *locp,
+                       HexValue *src)
+{
+    HexValue src_m = *src;
+    src_m.is_manual = true;
+
+    unsigned bit_width = src_m.bit_width;
+    const char *size = (bit_width == 32) ? "32" : "64";
+    HexValue res = gen_tmp(c, locp, bit_width, src->signedness);
+    HexValue mask = gen_tmp_value(c, locp, "0x3", bit_width, UNSIGNED);
+    mask.is_manual = true;
+    HexValue and = gen_bin_op(c, locp, ANDB_OP, &src_m, &mask);
+    HexValue one = gen_tmp_value(c, locp, "1", bit_width, UNSIGNED);
+    HexValue src_p1 = gen_bin_op(c, locp, ADD_OP, &src_m, &one);
+
+    OUT(c, locp, "tcg_gen_movcond_i", size, "(TCG_COND_EQ, ", &res);
+    OUT(c, locp, ", ", &and, ", ", &mask, ", ");
+    OUT(c, locp, &src_p1, ", ", &src_m, ");\n");
+
+    /* Free src but use the original `is_manual` value */
+    gen_rvalue_free(c, locp, src);
+
+    /* Free the rest of the values */
+    gen_rvalue_free_manual(c, locp, &mask);
+    gen_rvalue_free(c, locp, &and);
+    gen_rvalue_free(c, locp, &src_p1);
+
+    return res;
+}
+
+static HexValue gen_convround_n_b(Context *c,
+                                  YYLTYPE *locp,
+                                  HexValue *a,
+                                  HexValue *n)
+{
+    assert(n->type != IMMEDIATE);
+    HexValue res = gen_tmp(c, locp, 64, UNSIGNED);
+    OUT(c, locp, "tcg_gen_ext_i32_i64(", &res, ", ", a, ");\n");
+
+    HexValue one = gen_tmp_value(c, locp, "1", 32, UNSIGNED);
+    HexValue tmp = gen_tmp(c, locp, 32, UNSIGNED);
+    HexValue tmp_64 = gen_tmp(c, locp, 64, UNSIGNED);
+
+    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");
+
+    gen_rvalue_free(c, locp, &one);
+    gen_rvalue_free(c, locp, &tmp);
+    gen_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, UNSIGNED);
+    OUT(c, locp, "tcg_gen_ext_i32_i64(", &res, ", ", a, ");\n");
+
+    HexValue one = gen_tmp_value(c, locp, "1", 32, UNSIGNED);
+    HexValue tmp = gen_tmp(c, locp, 32, UNSIGNED);
+    HexValue tmp_64 = gen_tmp(c, locp, 64, UNSIGNED);
+
+    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");
+
+    gen_rvalue_free(c, locp, &one);
+    gen_rvalue_free(c, locp, &tmp);
+    gen_rvalue_free(c, locp, &tmp_64);
+
+    return res;
+}
+
+HexValue gen_convround_n(Context *c,
+                         YYLTYPE *locp,
+                         HexValue *src,
+                         HexValue *pos)
+{
+    /* If input is 64 bit cast it to 32 */
+    HexValue src_casted = gen_cast_op(c, locp, src, 32,
+                                      src->signedness);
+    HexValue pos_casted = gen_cast_op(c, locp, pos, 32,
+                                          pos->signedness);
+
+    src_casted = rvalue_materialize(c, locp, &src_casted);
+    pos_casted = rvalue_materialize(c, locp, &pos_casted);
+
+    /*
+     * r1, r2, and r3 represent the results of three different branches.
+     *   - r1 picked if pos_casted == 0
+     *   - r2 picked if (src_casted & ((1 << (pos_casted - 1)) - 1)) == 0),
+     *     that is if bits 0, ..., pos_casted-1 are all 0.
+     *   - r3 picked otherwise.
+     */
+    HexValue r1 = gen_rvalue_extend(c, locp, &src_casted);
+    HexValue r2 = gen_convround_n_b(c, locp, &src_casted, &pos_casted);
+    HexValue r3 = gen_convround_n_c(c, locp, &src_casted, &pos_casted);
+
+    HexValue l_32 = gen_tmp_value(c, locp, "1", 32, UNSIGNED);
+
+    HexValue cond = gen_tmp(c, locp, 32, UNSIGNED);
+    HexValue cond_64 = gen_tmp(c, locp, 64, UNSIGNED);
+    HexValue mask = gen_tmp(c, locp, 32, UNSIGNED);
+    HexValue n_64 = gen_tmp(c, locp, 64, UNSIGNED);
+    HexValue res = gen_tmp(c, locp, 64, UNSIGNED);
+    HexValue zero = gen_tmp_value(c, locp, "0", 64, UNSIGNED);
+
+    /*
+     * Calculate the condition
+     *   (src_casted & ((1 << (pos_casted - 1)) - 1)) == 0),
+     * which checks if the bits 0,...,pos-1 are all 0.
+     */
+    OUT(c, locp, "tcg_gen_sub_i32(", &mask);
+    OUT(c, locp, ", ", &pos_casted, ", ", &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, ", ", &src_casted, ", ", &mask, ");\n");
+    OUT(c, locp, "tcg_gen_extu_i32_i64(", &cond_64, ", ", &cond, ");\n");
+
+    OUT(c, locp, "tcg_gen_ext_i32_i64(", &n_64, ", ", &pos_casted, ");\n");
+
+    /*
+     * if the bits 0, ..., pos_casted-1 are all 0, then pick r2 otherwise,
+     * pick r3.
+     */
+    OUT(c, locp, "tcg_gen_movcond_i64");
+    OUT(c, locp, "(TCG_COND_EQ, ", &res, ", ", &cond_64, ", ", &zero);
+    OUT(c, locp, ", ", &r2, ", ", &r3, ");\n");
+
+    /* Lastly, if the pos_casted == 0, then pick r1 */
+    OUT(c, locp, "tcg_gen_movcond_i64");
+    OUT(c, locp, "(TCG_COND_EQ, ", &res, ", ", &n_64, ", ", &zero);
+    OUT(c, locp, ", ", &r1, ", ", &res, ");\n");
+
+    /* Finally shift back val >>= n */
+    OUT(c, locp, "tcg_gen_shr_i64(", &res);
+    OUT(c, locp, ", ", &res, ", ", &n_64, ");\n");
+
+    gen_rvalue_free(c, locp, &src_casted);
+    gen_rvalue_free(c, locp, &pos_casted);
+
+    gen_rvalue_free(c, locp, &r1);
+    gen_rvalue_free(c, locp, &r2);
+    gen_rvalue_free(c, locp, &r3);
+
+    gen_rvalue_free(c, locp, &cond);
+    gen_rvalue_free(c, locp, &cond_64);
+    gen_rvalue_free(c, locp, &l_32);
+    gen_rvalue_free(c, locp, &mask);
+    gen_rvalue_free(c, locp, &n_64);
+    gen_rvalue_free(c, locp, &zero);
+
+    res = gen_rvalue_truncate(c, locp, &res);
+    return res;
+}
+
+HexValue gen_round(Context *c,
+                   YYLTYPE *locp,
+                   HexValue *src,
+                   HexValue *pos) {
+    yyassert(c, locp, src->bit_width <= 32,
+             "fRNDN not implemented for bit widths > 32!");
+
+    HexValue src_width = gen_imm_value(c, locp, src->bit_width, 32, UNSIGNED);
+    HexValue a = gen_extend_op(c, locp, &src_width, 64, src, SIGNED);
+    a = rvalue_materialize(c, locp, &a);
+
+    src_width = gen_imm_value(c, locp, 5, 32, UNSIGNED);
+    HexValue b = gen_extend_op(c, locp, &src_width, 64, pos, UNSIGNED);
+    b = rvalue_materialize(c, locp, &b);
+
+    /* Disable auto-free of values used more than once */
+    a.is_manual = true;
+    b.is_manual = true;
+
+    HexValue res = gen_tmp(c, locp, 64, src->signedness);
+
+    HexValue one = gen_tmp_value(c, locp, "1", 64, UNSIGNED);
+    HexValue n_m1 = gen_bin_op(c, locp, SUB_OP, &b, &one);
+    one = gen_tmp_value(c, locp, "1", 64, UNSIGNED);
+    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, UNSIGNED);
+    OUT(c, locp, "tcg_gen_movcond_i64");
+    OUT(c, locp, "(TCG_COND_EQ, ", &res, ", ", &b, ", ", &zero);
+    OUT(c, locp, ", ", &a, ", ", &sum, ");\n");
+
+    gen_rvalue_free_manual(c, locp, &a);
+    gen_rvalue_free_manual(c, locp, &b);
+    gen_rvalue_free(c, locp, &zero);
+    gen_rvalue_free(c, locp, &sum);
+
+    return res;
+}
+
+/* Circular addressing mode with auto-increment */
+void gen_circ_op(Context *c,
+                 YYLTYPE *locp,
+                 HexValue *addr,
+                 HexValue *increment,
+                 HexValue *modifier) {
+    HexValue increment_m = *increment;
+    increment_m = rvalue_materialize(c, locp, &increment_m);
+    HexValue cs = gen_tmp(c, locp, 32, UNSIGNED);
+    OUT(c, locp, "gen_read_reg(", &cs, ", HEX_REG_CS0 + MuN);\n");
+    OUT(c,
+        locp,
+        "gen_helper_fcircadd(",
+        addr,
+        ", ",
+        addr,
+        ", ",
+        &increment_m,
+        ", ",
+        modifier);
+    OUT(c, locp, ", ", &cs, ");\n");
+    gen_rvalue_free(c, locp, &increment_m);
+    gen_rvalue_free(c, locp, modifier);
+    gen_rvalue_free(c, locp, &cs);
+}
+
+HexValue gen_locnt_op(Context *c, YYLTYPE *locp, HexValue *src)
+{
+    HexValue src_m = *src;
+    src_m = rvalue_materialize(c, locp, &src_m);
+
+    const char *bit_suffix = src->bit_width == 64 ? "64" : "32";
+    HexValue res = gen_tmp(c, locp, src->bit_width == 64 ? 64 : 32,
+                           src->signedness);
+    res.type = TEMP;
+
+    OUT(c, locp, "tcg_gen_not_i", bit_suffix, "(",
+        &res, ", ", &src_m, ");\n");
+    OUT(c, locp, "tcg_gen_clzi_i", bit_suffix, "(", &res, ", ", &res, ", ");
+    OUT(c, locp, bit_suffix, ");\n");
+    gen_rvalue_free(c, locp, &src_m);
+    return res;
+}
+
+HexValue gen_ctpop_op(Context *c, YYLTYPE *locp, HexValue *src)
+{
+    HexValue src_m = *src;
+    src_m = rvalue_materialize(c, locp, &src_m);
+
+    const char *bit_suffix = src->bit_width == 64 ? "64" : "32";
+    HexValue res = gen_tmp(c, locp, src->bit_width == 64 ? 64 : 32,
+                           src->signedness);
+    res.type = TEMP;
+
+    OUT(c, locp, "tcg_gen_ctpop_i", bit_suffix,
+        "(", &res, ", ", &src_m, ");\n");
+    gen_rvalue_free(c, locp, &src_m);
+    return res;
+}
+
+HexValue gen_fbrev_4(Context *c, YYLTYPE *locp, HexValue *src)
+{
+    HexValue src_m = *src;
+    src_m = rvalue_materialize(c, locp, &src_m);
+    src_m = gen_rvalue_truncate(c, locp, &src_m);
+
+    HexValue res = gen_tmp(c, locp, 32, UNSIGNED);
+
+    OUT(c, locp, "{\n");
+    OUT(c, locp, "TCGTemp *ret = tcgv_i32_temp(", &res, ");\n");
+    OUT(c, locp, "TCGTemp *arg = tcgv_i32_temp(", &src_m, ");\n");
+    OUT(c, locp, "tcg_gen_callN(helper_fbrev_32, ret, 1, &arg);\n");
+    OUT(c, locp, "}\n");
+
+    gen_rvalue_free(c, locp, &src_m);
+
+    return res;
+}
+
+HexValue gen_fbrev_8(Context *c, YYLTYPE *locp, HexValue *src)
+{
+    HexValue src_m = *src;
+
+    src_m = gen_rvalue_extend(c, locp, &src_m);
+    src_m = rvalue_materialize(c, locp, &src_m);
+
+    HexValue res = gen_tmp(c, locp, 64, UNSIGNED);
+
+    OUT(c, locp, "{\n");
+    OUT(c, locp, "TCGTemp *ret = tcgv_i64_temp(", &res, ");\n");
+    OUT(c, locp, "TCGTemp *arg = tcgv_i64_temp(", &src_m, ");\n");
+    OUT(c, locp, "tcg_gen_callN(helper_fbrev_64, ret, 1, &arg);\n");
+    OUT(c, locp, "}\n");
+
+    gen_rvalue_free(c, locp, &src_m);
+
+    return res;
+}
+
+HexValue gen_rotl(Context *c, YYLTYPE *locp, HexValue *src, HexValue *width)
+{
+    HexValue amount = *width;
+    if (amount.bit_width < src->bit_width) {
+        amount = gen_rvalue_extend(c, locp, &amount);
+    } else {
+        amount = gen_rvalue_truncate(c, locp, &amount);
+    }
+    amount = rvalue_materialize(c, locp, &amount);
+    const char *suffix = src->bit_width == 64 ? "i64" : "i32";
+
+    HexValue res = gen_tmp(c, locp, src->bit_width, src->signedness);
+    OUT(c, locp, "tcg_gen_rotl_", suffix, "(",
+        &res, ", ", src, ", ", &amount, ");\n");
+    gen_rvalue_free(c, locp, src);
+    gen_rvalue_free(c, locp, &amount);
+
+    return res;
+}
+
+HexValue gen_carry_from_add(Context *c,
+                            YYLTYPE *locp,
+                            HexValue *op1,
+                            HexValue *op2,
+                            HexValue *op3)
+{
+    HexValue op1_m = rvalue_materialize(c, locp, op1);
+    HexValue op2_m = rvalue_materialize(c, locp, op2);
+    HexValue op3_m = rvalue_materialize(c, locp, op3);
+    op3_m = gen_rvalue_extend(c, locp, &op3_m);
+
+    HexValue zero = gen_tmp_value(c, locp, "0", 64, UNSIGNED);
+    HexValue res = gen_tmp(c, locp, 64, UNSIGNED);
+    HexValue cf = gen_tmp(c, locp, 64, UNSIGNED);
+    OUT(c, locp, "tcg_gen_add2_i64(", &res, ", ", &cf, ", ", &op1_m, ", ",
+        &zero);
+    OUT(c, locp, ", ", &op3_m, ", ", &zero, ");\n");
+    OUT(c, locp, "tcg_gen_add2_i64(", &res, ", ", &cf, ", ", &res, ", ", &cf);
+    OUT(c, locp, ", ", &op2_m, ", ", &zero, ");\n");
+
+    gen_rvalue_free(c, locp, &op1_m);
+    gen_rvalue_free(c, locp, &op2_m);
+    gen_rvalue_free(c, locp, &op3_m);
+    gen_rvalue_free(c, locp, &zero);
+    gen_rvalue_free(c, locp, &res);
+    return cf;
+}
+
+void gen_addsat64(Context *c,
+                  YYLTYPE *locp,
+                  HexValue *dst,
+                  HexValue *op1,
+                  HexValue *op2)
+{
+    HexValue op1_m = rvalue_materialize(c, locp, op1);
+    HexValue op2_m = rvalue_materialize(c, locp, op2);
+    OUT(c, locp, "gen_add_sat_i64(", dst, ", ", &op1_m, ", ", &op2_m, ");\n");
+}
+
+void gen_inst(Context *c, GString *iname)
+{
+    c->total_insn++;
+    c->inst.name = iname;
+    c->inst.allocated = g_array_new(FALSE, FALSE, sizeof(Var));
+    c->inst.init_list = g_array_new(FALSE, FALSE, sizeof(HexValue));
+    c->inst.strings = g_array_new(FALSE, FALSE, sizeof(GString *));
+    EMIT_SIG(c, "void emit_%s(DisasContext *ctx, Insn *insn, Packet *pkt",
+             c->inst.name->str);
+}
+
+
+/*
+ * Initialize declared but uninitialized registers, but only for
+ * non-conditional instructions
+ */
+void gen_inst_init_args(Context *c, YYLTYPE *locp)
+{
+    if (!c->inst.init_list) {
+        return;
+    }
+
+    for (unsigned i = 0; i < c->inst.init_list->len; i++) {
+        HexValue *val = &g_array_index(c->inst.init_list, HexValue, i);
+        if (val->type == REGISTER_ARG) {
+            char reg_id[5];
+            reg_compose(c, locp, &val->reg, reg_id);
+            EMIT_HEAD(c, "tcg_gen_movi_i%u(%s, 0);\n", val->bit_width, reg_id);
+        } else if (val->type == PREDICATE) {
+            char suffix = val->is_dotnew ? 'N' : 'V';
+            EMIT_HEAD(c, "tcg_gen_movi_i%u(P%c%c, 0);\n", val->bit_width,
+                      val->pred.id, suffix);
+        } else {
+            yyassert(c, locp, false, "Invalid arg type!");
+        }
+    }
+
+    /* Free argument init list once we have initialized everything */
+    g_array_free(c->inst.init_list, TRUE);
+    c->inst.init_list = NULL;
+}
+
+void gen_inst_code(Context *c, YYLTYPE *locp)
+{
+    if (c->inst.error_count != 0) {
+        fprintf(stderr,
+                "Parsing of instruction %s generated %d errors!\n",
+                c->inst.name->str,
+                c->inst.error_count);
+    } else {
+        free_variables(c, locp);
+        c->implemented_insn++;
+        fprintf(c->enabled_file, "%s\n", c->inst.name->str);
+        emit_footer(c);
+        commit(c);
+    }
+    free_instruction(c);
+}
+
+void gen_pred_assign(Context *c, YYLTYPE *locp, HexValue *left_pred,
+                     HexValue *right_pred)
+{
+    bool is_direct = is_direct_predicate(left_pred);
+    char pred_id[2] = " ";
+    pred_id[0] = left_pred->pred.id;
+    /* Extract predicate TCGv */
+    if (is_direct) {
+        *left_pred = gen_tmp_value(c, locp, "0", 32, UNSIGNED);
+    }
+    HexValue r = rvalue_materialize(c, locp, right_pred);
+    r = gen_rvalue_truncate(c, locp, &r);
+    /* Extract first 8 bits, and store new predicate value */
+    if (is_inside_ternary(c)) {
+        yyassert(c, locp, !is_direct, "direct pred assign inside ternary op");
+        HexValue tmp = gen_tmp(c, locp, r.bit_width, UNSIGNED);
+        HexValue cond = get_ternary_cond(c, locp);
+        HexValue zero = gen_tmp_value(c, locp, "0", r.bit_width, UNSIGNED);
+        OUT(c, locp, "tcg_gen_mov_i32(", &tmp, ", ", &r, ");\n");
+        OUT(c, locp, "tcg_gen_andi_i32(", &tmp, ", ", &tmp, ", 0xff);\n");
+        OUT(c, locp, "tcg_gen_movcond_i", &r.bit_width);
+        OUT(c, locp, "(TCG_COND_NE, ", left_pred, ", ", &cond, ", ", &zero);
+        OUT(c, locp, ", ", &tmp, ", ", left_pred, ");\n");
+        gen_rvalue_free(c, locp, &tmp);
+        gen_rvalue_free(c, locp, &cond);
+        gen_rvalue_free(c, locp, &zero);
+    } else {
+        OUT(c, locp, "tcg_gen_mov_i32(", left_pred, ", ", &r, ");\n");
+        OUT(c, locp, "tcg_gen_andi_i32(", left_pred, ", ", left_pred,
+            ", 0xff);\n");
+    }
+    if (is_direct) {
+        OUT(c, locp, "gen_log_pred_write(ctx, ", pred_id, ", ", left_pred,
+            ");\n");
+        OUT(c, locp, "ctx_log_pred_write(ctx, ", pred_id, ");\n");
+        gen_rvalue_free(c, locp, left_pred);
+    }
+    /* Free temporary value */
+    gen_rvalue_free(c, locp, &r);
+}
+
+void gen_load(Context *c, YYLTYPE *locp, HexValue *width,
+              HexSignedness signedness, HexValue *ea, HexValue *dst)
+{
+    /* Memop width is specified in the load macro */
+    assert_signedness(c, locp, signedness);
+    const char *sign_suffix = (width->imm.value > 4)
+                              ? ""
+                              : ((signedness == UNSIGNED) ? "u" : "s");
+    char size_suffix[4] = { 0 };
+    /* If dst is a variable, assert that is declared and load the type info */
+    if (dst->type == VARID) {
+        find_variable(c, locp, dst, dst);
+    }
+
+    snprintf(size_suffix, 4, "%" PRIu64, width->imm.value * 8);
+    /* Lookup the effective address EA */
+    find_variable(c, locp, ea, ea);
+    OUT(c, locp, "if (insn->slot == 0 && pkt->pkt_has_store_s1) {\n");
+    OUT(c, locp, "process_store(ctx, pkt, 1);\n");
+    OUT(c, locp, "}\n");
+    OUT(c, locp, "tcg_gen_qemu_ld", size_suffix, sign_suffix);
+    OUT(c, locp, "(");
+    if (dst->bit_width > width->imm.value * 8) {
+        /*
+         * Cast to the correct TCG type if necessary, to avoid implict cast
+         * warnings. This is needed when the width of the destination var is
+         * larger than the size of the requested load.
+         */
+        OUT(c, locp, "(TCGv) ");
+    }
+    OUT(c, locp, dst, ", ", ea, ", ctx->mem_idx);\n");
+    /* If the var in EA was truncated it is now a tmp HexValue, so free it. */
+    gen_rvalue_free(c, locp, ea);
+}
+
+void gen_store(Context *c, YYLTYPE *locp, HexValue *width, HexValue *ea,
+               HexValue *src)
+{
+    HexValue src_m = *src;
+    /* Memop width is specified in the store macro */
+    int mem_width = width->imm.value;
+    /* Lookup the effective address EA */
+    find_variable(c, locp, ea, ea);
+    src_m = rvalue_materialize(c, locp, &src_m);
+    OUT(c, locp, "gen_store", &mem_width, "(cpu_env, ", ea, ", ", &src_m);
+    OUT(c, locp, ", ctx, insn->slot);\n");
+    gen_rvalue_free(c, locp, &src_m);
+    /* If the var in ea was truncated it is now a tmp HexValue, so free it. */
+    gen_rvalue_free(c, locp, ea);
+}
+
+void gen_sethalf(Context *c, YYLTYPE *locp, HexCast *sh, HexValue *n,
+                 HexValue *dst, HexValue *value)
+{
+    yyassert(c, locp, n->type == IMMEDIATE,
+             "Deposit index must be immediate!\n");
+    if (dst->type == VARID) {
+        find_variable(c, locp, dst, dst);
+    }
+
+    gen_deposit_op(c, locp, dst, value, n, sh);
+}
+
+void gen_setbits(Context *c, YYLTYPE *locp, HexValue *hi, HexValue *lo,
+                 HexValue *dst, HexValue *value)
+{
+    yyassert(c, locp, hi->type == IMMEDIATE &&
+             hi->imm.type == VALUE &&
+             lo->type == IMMEDIATE &&
+             lo->imm.type == VALUE,
+             "Range deposit needs immediate values!\n");
+
+    *value = gen_rvalue_truncate(c, locp, value);
+    unsigned len = hi->imm.value + 1 - lo->imm.value;
+    HexValue tmp = gen_tmp(c, locp, 32, value->signedness);
+    /* Emit an `and` to ensure `value` is either 0 or 1. */
+    OUT(c, locp, "tcg_gen_andi_i32(", &tmp, ", ", value, ", 1);\n");
+    /* Use `neg` to map 0 -> 0 and 1 -> 0xffff... */
+    OUT(c, locp, "tcg_gen_neg_i32(", &tmp, ", ", &tmp, ");\n");
+    OUT(c, locp, "tcg_gen_deposit_i32(", dst, ", ", dst,
+        ", ", &tmp, ", ");
+    OUT(c, locp, lo, ", ", &len, ");\n");
+
+    gen_rvalue_free(c, locp, &tmp);
+    gen_rvalue_free(c, locp, hi);
+    gen_rvalue_free(c, locp, lo);
+    gen_rvalue_free(c, locp, value);
+}
+
+int gen_if_cond(Context *c, YYLTYPE *locp, HexValue *cond)
+{
+    /* Generate an end label, if false branch to that label */
+    OUT(c, locp, "TCGLabel *if_label_", &c->inst.if_count,
+        " = gen_new_label();\n");
+    *cond = rvalue_materialize(c, locp, cond);
+    const char *bit_suffix = (cond->bit_width == 64) ? "i64" : "i32";
+    OUT(c, locp, "tcg_gen_brcondi_", bit_suffix, "(TCG_COND_EQ, ", cond,
+        ", 0, if_label_", &c->inst.if_count, ");\n");
+    gen_rvalue_free(c, locp, cond);
+    return c->inst.if_count++;
+}
+
+int gen_if_else(Context *c, YYLTYPE *locp, int index)
+{
+    /* Generate label to jump if else is not verified */
+    OUT(c, locp, "TCGLabel *if_label_", &c->inst.if_count,
+        " = gen_new_label();\n");
+    int if_index = c->inst.if_count;
+    c->inst.if_count++;
+    /* Jump out of the else statement */
+    OUT(c, locp, "tcg_gen_br(if_label_", &if_index, ");\n");
+    /* Fix the else label */
+    OUT(c, locp, "gen_set_label(if_label_", &index, ");\n");
+    return if_index;
+}
+
+HexValue gen_rvalue_pred(Context *c, YYLTYPE *locp, HexValue *pred)
+{
+    /* Predicted instructions need to zero out result args */
+    gen_inst_init_args(c, locp);
+
+    if (is_direct_predicate(pred)) {
+        bool is_dotnew = pred->is_dotnew;
+        char predicate_id[2] = { pred->pred.id, '\0' };
+        char *pred_str = (char *) &predicate_id;
+        *pred = gen_tmp_value(c, locp, "0", 32, UNSIGNED);
+        if (is_dotnew) {
+            OUT(c, locp, "tcg_gen_mov_i32(", pred,
+                ", hex_new_pred_value[");
+            OUT(c, locp, pred_str, "]);\n");
+        } else {
+            OUT(c, locp, "gen_read_preg(", pred, ", ", pred_str, ");\n");
+        }
+    }
+
+    return *pred;
+}
+
+HexValue gen_rvalue_var(Context *c, YYLTYPE *locp, HexValue *var)
+{
+    find_variable(c, locp, var, var);
+    return *var;
+}
+
+HexValue gen_rvalue_mpy(Context *c, YYLTYPE *locp, HexMpy *mpy,
+                        HexValue *op1, HexValue *op2)
+{
+    assert_signedness(c, locp, mpy->first_signedness);
+    assert_signedness(c, locp, mpy->second_signedness);
+    *op1 = gen_cast_op(c, locp, op1, mpy->first_bit_width * 2,
+                     mpy->first_signedness);
+    /* Handle fMPTY3216.. */
+    if (mpy->first_bit_width == 32) {
+        *op2 = gen_cast_op(c, locp, op2, 64, mpy->second_signedness);
+    } else {
+        *op2 = gen_cast_op(c, locp, op2, mpy->second_bit_width * 2,
+                         mpy->second_signedness);
+    }
+    HexValue ret = gen_bin_op(c, locp, MUL_OP, op1, op2);
+    /* Handle special cases required by the language */
+    if (mpy->first_bit_width == 16 && mpy->second_bit_width == 16) {
+        HexValue src_width = gen_imm_value(c, locp, 32, 32, UNSIGNED);
+        assert_signedness(c, locp, mpy->first_signedness);
+        assert_signedness(c, locp, mpy->second_signedness);
+        bool is_unsigned = (mpy->first_signedness == UNSIGNED
+                            && mpy->second_signedness == UNSIGNED);
+        HexSignedness signedness = is_unsigned ? UNSIGNED : SIGNED;
+        ret = gen_extend_op(c, locp, &src_width, 64, &ret,
+                            signedness);
+    }
+    return ret;
+}
+
+static inline HexValue gen_rvalue_simple_unary(Context *c, YYLTYPE *locp,
+                                               HexValue *value,
+                                               const char *c_code,
+                                               const char *tcg_code)
+{
+    unsigned bit_width = (value->bit_width == 64) ? 64 : 32;
+    HexValue res;
+    memset(&res, 0, sizeof(HexValue));
+    if (value->type == IMMEDIATE) {
+        res = gen_imm_qemu_tmp(c, locp, bit_width, value->signedness);
+        gen_c_int_type(c, locp, value->bit_width, value->signedness);
+        OUT(c, locp, " ", &res, " = ", c_code, "(", value, ");\n");
+    } else {
+        res = gen_tmp(c, locp, bit_width, value->signedness);
+        OUT(c, locp, tcg_code, "_i", &bit_width, "(", &res, ", ", value,
+            ");\n");
+        gen_rvalue_free(c, locp, value);
+    }
+    return res;
+}
+
+
+HexValue gen_rvalue_not(Context *c, YYLTYPE *locp, HexValue *value)
+{
+    return gen_rvalue_simple_unary(c, locp, value, "~", "tcg_gen_not");
+}
+
+HexValue gen_rvalue_notl(Context *c, YYLTYPE *locp, HexValue *value)
+{
+    unsigned bit_width = (value->bit_width == 64) ? 64 : 32;
+    HexValue res;
+    memset(&res, 0, sizeof(HexValue));
+    if (value->type == IMMEDIATE) {
+        res = gen_imm_qemu_tmp(c, locp, bit_width, value->signedness);
+        gen_c_int_type(c, locp, value->bit_width, value->signedness);
+        OUT(c, locp, " ", &res, " = !", value, ";\n");
+    } else {
+        res = gen_tmp(c, locp, bit_width, value->signedness);
+        HexValue zero = gen_tmp_value(c, locp, "0", bit_width, UNSIGNED);
+        HexValue one = gen_tmp_value(c, locp, "0xff", bit_width, UNSIGNED);
+        OUT(c, locp, "tcg_gen_movcond_i", &bit_width);
+        OUT(c, locp, "(TCG_COND_EQ, ", &res, ", ", value, ", ", &zero);
+        OUT(c, locp, ", ", &one, ", ", &zero, ");\n");
+        gen_rvalue_free(c, locp, value);
+        gen_rvalue_free(c, locp, &zero);
+        gen_rvalue_free(c, locp, &one);
+    }
+    return res;
+}
+
+void gen_set_overflow(Context *c, YYLTYPE *locp, HexValue *value)
+{
+    HexValue value_m = *value;
+
+    HexValue ovfl = gen_tmp(c, locp, 32, UNSIGNED);
+    OUT(c, locp, "GET_USR_FIELD(USR_OVF, ", &ovfl, ");\n");
+
+    if (is_inside_ternary(c)) {
+        /* Inside ternary operator, need to take care of the side-effect */
+        HexValue cond = get_ternary_cond(c, locp);
+        value_m = rvalue_materialize(c, locp, &value_m);
+        bool is_64bit = cond.bit_width == 64;
+        unsigned bit_width = cond.bit_width;
+        if (is_64bit) {
+            ovfl = gen_rvalue_extend(c, locp, &ovfl);
+            value_m = gen_rvalue_extend(c, locp, &value_m);
+        }
+        HexValue tmp = gen_tmp_value(c, locp, "0", cond.bit_width, UNSIGNED);
+        OUT(c, locp, "tcg_gen_movcond_i", &bit_width,
+                     "(TCG_COND_NE, ", &tmp, ", ", &cond);
+        OUT(c, locp, ", ", &tmp, ", ", &value_m, ", ", &tmp, ");\n");
+        OUT(c, locp, "tcg_gen_or_i", &bit_width, "(",
+            &ovfl, ", ", &ovfl, ", ", &tmp, ");\n");
+        if (is_64bit) {
+            ovfl = gen_rvalue_truncate(c, locp, &ovfl);
+        }
+        gen_rvalue_free(c, locp, &tmp);
+        gen_rvalue_free(c, locp, &cond);
+    } else {
+        if (value_m.type == IMMEDIATE) {
+            OUT(c, locp, "tcg_gen_ori_i32(",
+                &ovfl, ", ", &ovfl, ", ", &value_m, ");\n");
+        } else {
+            OUT(c, locp, "tcg_gen_or_i32(",
+                &ovfl, ", ", &ovfl, ", ", &value_m, ");\n");
+        }
+    }
+
+    OUT(c, locp, "SET_USR_FIELD(USR_OVF, ", &ovfl, ");\n");
+
+    gen_rvalue_free(c, locp, &ovfl);
+    gen_rvalue_free(c, locp, &value_m);
+}
+
+HexValue gen_rvalue_sat(Context *c, YYLTYPE *locp, HexSat *sat,
+                        HexValue *width, HexValue *value)
+{
+    if (sat->set_overflow) {
+        yyassert(c, locp, width->imm.value < value->bit_width,
+                 "To compute overflow, source width must be greater than"
+                 "saturation width!");
+    }
+    assert_signedness(c, locp, sat->signedness);
+    HexValue res = gen_tmp(c, locp, value->bit_width, sat->signedness);
+    const char *bit_suffix = (value->bit_width == 64) ? "i64" : "i32";
+    const char *unsigned_str = (sat->signedness == UNSIGNED) ? "u" : "";
+    if (sat->set_overflow) {
+        HexValue ovfl = gen_tmp(c, locp, 32, sat->signedness);
+        OUT(c, locp, "gen_sat", unsigned_str, "_", bit_suffix, "_ovfl(");
+        OUT(c, locp, &ovfl, ", ", &res, ", ", value, ", ", &width->imm.value,
+            ");\n");
+        gen_set_overflow(c, locp, &ovfl);
+    } else {
+        OUT(c, locp, "gen_sat", unsigned_str, "_", bit_suffix, "(", &res, ", ");
+        OUT(c, locp, value, ", ", &width->imm.value, ");\n");
+    }
+    gen_rvalue_free(c, locp, value);
+    return res;
+}
+
+HexValue gen_rvalue_fscr(Context *c, YYLTYPE *locp, HexValue *value)
+{
+    HexValue key = gen_tmp(c, locp, 64, UNSIGNED);
+    HexValue res = gen_tmp(c, locp, 64, UNSIGNED);
+    *value = gen_rvalue_extend(c, locp, value);
+    HexValue frame_key = gen_tmp(c, locp, 32, UNSIGNED);
+    OUT(c, locp, "gen_read_reg(", &frame_key, ", HEX_REG_FRAMEKEY);\n");
+    OUT(c, locp, "tcg_gen_concat_i32_i64(",
+        &key, ", ", &frame_key, ", ", &frame_key, ");\n");
+    OUT(c, locp, "tcg_gen_xor_i64(", &res, ", ", value, ", ", &key, ");\n");
+    gen_rvalue_free(c, locp, &key);
+    gen_rvalue_free(c, locp, &frame_key);
+    gen_rvalue_free(c, locp, value);
+    return res;
+}
+
+HexValue gen_rvalue_abs(Context *c, YYLTYPE *locp, HexValue *value)
+{
+    return gen_rvalue_simple_unary(c, locp, value, "abs", "tcg_gen_abs");
+}
+
+HexValue gen_rvalue_neg(Context *c, YYLTYPE *locp, HexValue *value)
+{
+    return gen_rvalue_simple_unary(c, locp, value, "-", "tcg_gen_neg");
+}
+
+HexValue gen_rvalue_brev(Context *c, YYLTYPE *locp, HexValue *value)
+{
+    yyassert(c, locp, value->bit_width <= 32,
+             "fbrev not implemented for 64-bit integers!");
+    HexValue res = gen_tmp(c, locp, value->bit_width, value->signedness);
+    *value = rvalue_materialize(c, locp, value);
+    OUT(c, locp, "gen_helper_fbrev(", &res, ", ", value, ");\n");
+    gen_rvalue_free(c, locp, value);
+    return res;
+}
+
+HexValue gen_rvalue_ternary(Context *c, YYLTYPE *locp, HexValue *cond,
+                            HexValue *true_branch, HexValue *false_branch)
+{
+    bool is_64bit = (true_branch->bit_width == 64) ||
+                    (false_branch->bit_width == 64);
+    int bit_width = (is_64bit) ? 64 : 32;
+    if (is_64bit) {
+        *cond = gen_rvalue_extend(c, locp, cond);
+        *true_branch = gen_rvalue_extend(c, locp, true_branch);
+        *false_branch = gen_rvalue_extend(c, locp, false_branch);
+    } else {
+        *cond = gen_rvalue_truncate(c, locp, cond);
+    }
+    *cond = rvalue_materialize(c, locp, cond);
+    *true_branch = rvalue_materialize(c, locp, true_branch);
+    *false_branch = rvalue_materialize(c, locp, false_branch);
+    HexValue res = gen_tmp(c, locp, bit_width, UNSIGNED);
+    HexValue zero = gen_tmp_value(c, locp, "0", bit_width, UNSIGNED);
+
+    OUT(c, locp, "tcg_gen_movcond_i", &bit_width);
+    OUT(c, locp, "(TCG_COND_NE, ", &res, ", ", cond, ", ", &zero);
+    OUT(c, locp, ", ", true_branch, ", ", false_branch, ");\n");
+
+    assert(c->ternary->len > 0);
+    Ternary *ternary = &g_array_index(c->ternary, Ternary, c->ternary->len - 1);
+    gen_rvalue_free_manual(c, locp, &ternary->cond);
+    g_array_remove_index(c->ternary, c->ternary->len - 1);
+
+    gen_rvalue_free(c, locp, &zero);
+    gen_rvalue_free(c, locp, cond);
+    gen_rvalue_free(c, locp, true_branch);
+    gen_rvalue_free(c, locp, false_branch);
+    return res;
+}
+
+const char *cond_to_str(TCGCond cond)
+{
+    switch (cond) {
+    case TCG_COND_NEVER:
+        return "TCG_COND_NEVER";
+    case TCG_COND_ALWAYS:
+        return "TCG_COND_ALWAYS";
+    case TCG_COND_EQ:
+        return "TCG_COND_EQ";
+    case TCG_COND_NE:
+        return "TCG_COND_NE";
+    case TCG_COND_LT:
+        return "TCG_COND_LT";
+    case TCG_COND_GE:
+        return "TCG_COND_GE";
+    case TCG_COND_LE:
+        return "TCG_COND_LE";
+    case TCG_COND_GT:
+        return "TCG_COND_GT";
+    case TCG_COND_LTU:
+        return "TCG_COND_LTU";
+    case TCG_COND_GEU:
+        return "TCG_COND_GEU";
+    case TCG_COND_LEU:
+        return "TCG_COND_LEU";
+    case TCG_COND_GTU:
+        return "TCG_COND_GTU";
+    default:
+        abort();
+    }
+}
+
+void emit_arg(Context *c, YYLTYPE *locp, HexValue *arg)
+{
+    switch (arg->type) {
+    case REGISTER_ARG:
+        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];
+            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->pred.id, suffix);
+        }
+        break;
+    default:
+        {
+            fprintf(stderr, "emit_arg got unsupported argument!");
+            abort();
+        }
+    }
+}
+
+void emit_footer(Context *c)
+{
+    EMIT(c, "}\n");
+    EMIT(c, "\n");
+}
+
+void track_string(Context *c, GString *s)
+{
+    g_array_append_val(c->inst.strings, s);
+}
+
+void free_variables(Context *c, YYLTYPE *locp)
+{
+    for (unsigned i = 0; i < c->inst.allocated->len; ++i) {
+        Var *var = &g_array_index(c->inst.allocated, Var, i);
+        const char *suffix = var->bit_width == 64 ? "i64" : "i32";
+        OUT(c, locp, "tcg_temp_free_", suffix, "(", var->name->str, ");\n");
+    }
+}
+
+void free_instruction(Context *c)
+{
+    assert(c->ternary->len == 0);
+    /* Free the strings */
+    g_string_truncate(c->signature_str, 0);
+    g_string_truncate(c->out_str, 0);
+    g_string_truncate(c->header_str, 0);
+    /* Free strings allocated by the instruction */
+    for (unsigned i = 0; i < c->inst.strings->len; i++) {
+        g_string_free(g_array_index(c->inst.strings, GString*, i), TRUE);
+    }
+    g_array_free(c->inst.strings, TRUE);
+    /* Free INAME token value */
+    g_string_free(c->inst.name, TRUE);
+    /* Free variables and registers */
+    g_array_free(c->inst.allocated, TRUE);
+    /* Initialize instruction-specific portion of the context */
+    memset(&(c->inst), 0, sizeof(Inst));
+}
+
+void assert_signedness(Context *c,
+                       YYLTYPE *locp,
+                       HexSignedness signedness) {
+    yyassert(c,
+             locp,
+             signedness != UNKNOWN_SIGNEDNESS,
+             "Unspecified signedness");
+}
diff --git a/target/hexagon/idef-parser/parser-helpers.h b/target/hexagon/idef-parser/parser-helpers.h
new file mode 100644
index 0000000000..ab8d3da874
--- /dev/null
+++ b/target/hexagon/idef-parser/parser-helpers.h
@@ -0,0 +1,379 @@
+/*
+ * Copyright(c) 2019-2021 rev.ng Labs Srl. 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 "tcg/tcg-cond.h"
+
+#include "idef-parser.tab.h"
+#include "idef-parser.yy.h"
+#include "idef-parser.h"
+
+/* Decomment this to disable yyasserts */
+/* #define NDEBUG */
+
+#define ERR_LINE_CONTEXT 40
+
+#define START_COMMENT "/" "*"
+#define END_COMMENT "*" "/"
+
+void yyerror(YYLTYPE *locp,
+             yyscan_t scanner __attribute__((unused)),
+             Context *c,
+             const char *s);
+
+#ifndef NDEBUG
+#define yyassert(context, locp, condition, msg)              \
+    if (!(condition)) {                                      \
+        yyerror(locp, (context)->scanner, (context), (msg)); \
+    }
+#endif
+
+bool is_direct_predicate(HexValue *value);
+
+/**
+ * Print functions
+ */
+
+void str_print(Context *c, YYLTYPE *locp, const char *string);
+
+void uint8_print(Context *c, YYLTYPE *locp, uint8_t *num);
+
+void uint64_print(Context *c, YYLTYPE *locp, uint64_t *num);
+
+void int_print(Context *c, YYLTYPE *locp, int *num);
+
+void uint_print(Context *c, YYLTYPE *locp, unsigned *num);
+
+void tmp_print(Context *c, YYLTYPE *locp, HexTmp *tmp);
+
+void pred_print(Context *c, YYLTYPE *locp, HexPred *pred, bool is_dotnew);
+
+void reg_compose(Context *c, YYLTYPE *locp, HexReg *reg, char reg_id[5]);
+
+void reg_print(Context *c, YYLTYPE *locp, HexReg *reg);
+
+void imm_print(Context *c, YYLTYPE *locp, HexImm *imm);
+
+void var_print(Context *c, YYLTYPE *locp, HexVar *var);
+
+void rvalue_print(Context *c, YYLTYPE *locp, void *pointer);
+
+void out_assert(Context *c, YYLTYPE *locp, void *dummy);
+
+/**
+ * Copies output code buffer into stdout
+ */
+void commit(Context *c);
+
+#define OUT_IMPL(c, locp, x)                    \
+    _Generic(*x,                                \
+        char:      str_print,                   \
+        uint8_t:   uint8_print,                 \
+        uint64_t:  uint64_print,                \
+        int:       int_print,                   \
+        unsigned:  uint_print,                  \
+        HexValue:  rvalue_print,                \
+        default:   out_assert                   \
+    )(c, locp, x);
+
+/* FOREACH macro */
+#define FE_1(c, locp, WHAT, X) WHAT(c, locp, X)
+#define FE_2(c, locp, WHAT, X, ...) \
+    WHAT(c, locp, X)FE_1(c, locp, WHAT, __VA_ARGS__)
+#define FE_3(c, locp, WHAT, X, ...) \
+    WHAT(c, locp, X)FE_2(c, locp, WHAT, __VA_ARGS__)
+#define FE_4(c, locp, WHAT, X, ...) \
+    WHAT(c, locp, X)FE_3(c, locp, WHAT, __VA_ARGS__)
+#define FE_5(c, locp, WHAT, X, ...) \
+    WHAT(c, locp, X)FE_4(c, locp, WHAT, __VA_ARGS__)
+#define FE_6(c, locp, WHAT, X, ...) \
+    WHAT(c, locp, X)FE_5(c, locp, WHAT, __VA_ARGS__)
+#define FE_7(c, locp, WHAT, X, ...) \
+    WHAT(c, locp, X)FE_6(c, locp, WHAT, __VA_ARGS__)
+#define FE_8(c, locp, WHAT, X, ...) \
+    WHAT(c, locp, X)FE_7(c, locp, WHAT, __VA_ARGS__)
+#define FE_9(c, locp, WHAT, X, ...) \
+    WHAT(c, locp, X)FE_8(c, locp, WHAT, __VA_ARGS__)
+/* repeat as needed */
+
+#define GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, NAME, ...) NAME
+
+#define FOR_EACH(c, locp, action, ...)          \
+  do {                                          \
+    GET_MACRO(__VA_ARGS__,                      \
+              FE_9,                             \
+              FE_8,                             \
+              FE_7,                             \
+              FE_6,                             \
+              FE_5,                             \
+              FE_4,                             \
+              FE_3,                             \
+              FE_2,                             \
+              FE_1)(c, locp, action,            \
+                    __VA_ARGS__)                \
+  } while (0)
+
+#define OUT(c, locp, ...) FOR_EACH((c), (locp), OUT_IMPL, __VA_ARGS__)
+
+const char *cmp_swap(Context *c, YYLTYPE *locp, const char *type);
+
+/**
+ * Temporary values creation
+ */
+
+HexValue gen_tmp(Context *c,
+                 YYLTYPE *locp,
+                 unsigned bit_width,
+                 HexSignedness signedness);
+
+HexValue gen_tmp_value(Context *c,
+                       YYLTYPE *locp,
+                       const char *value,
+                       unsigned bit_width,
+                       HexSignedness signedness);
+
+HexValue gen_imm_value(Context *c __attribute__((unused)),
+                       YYLTYPE *locp,
+                       int value,
+                       unsigned bit_width,
+                       HexSignedness signedness);
+
+HexValue gen_imm_qemu_tmp(Context *c, YYLTYPE *locp, unsigned bit_width,
+                          HexSignedness signedness);
+
+void gen_rvalue_free(Context *c, YYLTYPE *locp, HexValue *rvalue);
+
+HexValue rvalue_materialize(Context *c, YYLTYPE *locp, HexValue *rvalue);
+
+HexValue gen_rvalue_extend(Context *c, YYLTYPE *locp, HexValue *rvalue);
+
+HexValue gen_rvalue_truncate(Context *c, YYLTYPE *locp, HexValue *rvalue);
+
+void gen_varid_allocate(Context *c,
+                        YYLTYPE *locp,
+                        HexValue *varid,
+                        unsigned bit_width,
+                        HexSignedness signedness);
+
+/**
+ * Code generation functions
+ */
+
+HexValue gen_bin_cmp(Context *c,
+                     YYLTYPE *locp,
+                     TCGCond type,
+                     HexValue *op1,
+                     HexValue *op2);
+
+HexValue gen_bin_op(Context *c,
+                    YYLTYPE *locp,
+                    OpType type,
+                    HexValue *op1,
+                    HexValue *op2);
+
+HexValue gen_cast_op(Context *c,
+                     YYLTYPE *locp,
+                     HexValue *src,
+                     unsigned target_width,
+                     HexSignedness signedness);
+
+/**
+ * gen_extend_op extends a region of src_width_ptr bits stored in a
+ * value_ptr to the size of dst_width. Note: src_width_ptr is a
+ * HexValue * to handle the special case where it is unknown at
+ * translation time.
+ */
+HexValue gen_extend_op(Context *c,
+                       YYLTYPE *locp,
+                       HexValue *src_width,
+                       unsigned dst_width,
+                       HexValue *value,
+                       HexSignedness signedness);
+
+void gen_rdeposit_op(Context *c,
+                     YYLTYPE *locp,
+                     HexValue *dst,
+                     HexValue *value,
+                     HexValue *begin,
+                     HexValue *width);
+
+void gen_deposit_op(Context *c,
+                    YYLTYPE *locp,
+                    HexValue *dst,
+                    HexValue *value,
+                    HexValue *index,
+                    HexCast *cast);
+
+HexValue gen_rextract_op(Context *c,
+                         YYLTYPE *locp,
+                         HexValue *src,
+                         int begin,
+                         int width);
+
+HexValue gen_extract_op(Context *c,
+                        YYLTYPE *locp,
+                        HexValue *src,
+                        HexValue *index,
+                        HexExtract *extract);
+
+HexValue gen_read_reg(Context *c, YYLTYPE *locp, HexValue *reg);
+
+void gen_write_reg(Context *c, YYLTYPE *locp, HexValue *reg, HexValue *value);
+
+void gen_assign(Context *c,
+                YYLTYPE *locp,
+                HexValue *dst,
+                HexValue *value);
+
+HexValue gen_convround(Context *c,
+                       YYLTYPE *locp,
+                       HexValue *src);
+
+HexValue gen_round(Context *c,
+                   YYLTYPE *locp,
+                   HexValue *src,
+                   HexValue *position);
+
+HexValue gen_convround_n(Context *c,
+                         YYLTYPE *locp,
+                         HexValue *src,
+                         HexValue *pos);
+
+/**
+ * Circular addressing mode with auto-increment
+ */
+void gen_circ_op(Context *c,
+                 YYLTYPE *locp,
+                 HexValue *addr,
+                 HexValue *increment,
+                 HexValue *modifier);
+
+HexValue gen_locnt_op(Context *c, YYLTYPE *locp, HexValue *src);
+
+HexValue gen_ctpop_op(Context *c, YYLTYPE *locp, HexValue *src);
+
+HexValue gen_fbrev_4(Context *c, YYLTYPE *locp, HexValue *src);
+
+HexValue gen_fbrev_8(Context *c, YYLTYPE *locp, HexValue *src);
+
+HexValue gen_rotl(Context *c, YYLTYPE *locp, HexValue *src, HexValue *n);
+
+HexValue gen_deinterleave(Context *c, YYLTYPE *locp, HexValue *mixed);
+
+HexValue gen_interleave(Context *c,
+                        YYLTYPE *locp,
+                        HexValue *odd,
+                        HexValue *even);
+
+HexValue gen_carry_from_add(Context *c,
+                            YYLTYPE *locp,
+                            HexValue *op1,
+                            HexValue *op2,
+                            HexValue *op3);
+
+void gen_addsat64(Context *c,
+                  YYLTYPE *locp,
+                  HexValue *dst,
+                  HexValue *op1,
+                  HexValue *op2);
+
+void gen_inst(Context *c, GString *iname);
+
+void gen_inst_init_args(Context *c, YYLTYPE *locp);
+
+void gen_inst_code(Context *c, YYLTYPE *locp);
+
+void gen_pred_assign(Context *c, YYLTYPE *locp, HexValue *left_pred,
+                     HexValue *right_pred);
+
+void gen_load(Context *c, YYLTYPE *locp, HexValue *size,
+              HexSignedness signedness, HexValue *ea, HexValue *dst);
+
+void gen_store(Context *c, YYLTYPE *locp, HexValue *size, HexValue *ea,
+               HexValue *src);
+
+void gen_sethalf(Context *c, YYLTYPE *locp, HexCast *sh, HexValue *n,
+                 HexValue *dst, HexValue *value);
+
+void gen_setbits(Context *c, YYLTYPE *locp, HexValue *hi, HexValue *lo,
+                 HexValue *dst, HexValue *value);
+
+int gen_if_cond(Context *c, YYLTYPE *locp, HexValue *cond);
+
+int gen_if_else(Context *c, YYLTYPE *locp, int index);
+
+HexValue gen_rvalue_pred(Context *c, YYLTYPE *locp, HexValue *pred);
+
+HexValue gen_rvalue_var(Context *c, YYLTYPE *locp, HexValue *var);
+
+HexValue gen_rvalue_mpy(Context *c, YYLTYPE *locp, HexMpy *mpy, HexValue *op1,
+                        HexValue *op2);
+
+HexValue gen_rvalue_not(Context *c, YYLTYPE *locp, HexValue *value);
+
+HexValue gen_rvalue_notl(Context *c, YYLTYPE *locp, HexValue *value);
+
+HexValue gen_rvalue_sat(Context *c, YYLTYPE *locp, HexSat *sat, HexValue *n,
+                        HexValue *value);
+
+HexValue gen_rvalue_ternary(Context *c, YYLTYPE *locp, HexValue *cond,
+                            HexValue *true_branch, HexValue *false_branch);
+
+HexValue gen_rvalue_fscr(Context *c, YYLTYPE *locp, HexValue *value);
+
+HexValue gen_rvalue_abs(Context *c, YYLTYPE *locp, HexValue *value);
+
+HexValue gen_rvalue_neg(Context *c, YYLTYPE *locp, HexValue *value);
+
+HexValue gen_rvalue_brev(Context *c, YYLTYPE *locp, HexValue *value);
+
+void gen_set_overflow(Context *c, YYLTYPE *locp, HexValue *value);
+
+HexValue gen_rvalue_ternary(Context *c, YYLTYPE *locp, HexValue *cond,
+                            HexValue *true_branch, HexValue *false_branch);
+
+const char *cond_to_str(TCGCond cond);
+
+void emit_header(Context *c);
+
+void emit_arg(Context *c, YYLTYPE *locp, HexValue *arg);
+
+void emit_footer(Context *c);
+
+void track_string(Context *c, GString *s);
+
+void free_variables(Context *c, YYLTYPE *locp);
+
+void free_instruction(Context *c);
+
+void assert_signedness(Context *c,
+                       YYLTYPE *locp,
+                       HexSignedness signedness);
+
+#endif /* PARSER_HELPERS_h */
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index 077951d8d3..96ffe497da 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -188,7 +188,7 @@ idef_parser_input_generated = custom_target(
     command: [python, files('gen_idef_parser_funcs.py'), semantics_generated, attribs_def, '@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,
@@ -199,4 +199,29 @@ 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@'])
+
+glib_dep = dependency('glib-2.0', native: true)
+
+idef_parser = executable('idef-parser',
+                         [flex.process(idef_parser_dir / 'idef-parser.lex'),
+                          bison.process(idef_parser_dir / 'idef-parser.y'),
+                          idef_parser_dir / 'parser-helpers.c'],
+                         include_directories: ['idef-parser', '../../include/'],
+                         dependencies: [glib_dep],
+                         c_args: ['-Wextra'],
+                         native: true)
+
+idef_generated_tcg = custom_target(
+    'idef-generated-tcg',
+    output: ['idef-generated-emitter.c',
+             'idef-generated-emitter.h.inc',
+             'idef-generated-enabled-instructions'],
+    input: preprocessed_idef_parser_input_generated,
+    depend_files: [hex_common_py],
+    command: [idef_parser, '@INPUT@', '@OUTPUT0@', '@OUTPUT1@', '@OUTPUT2@'],
+)
+
 target_arch += {'hexagon': hexagon_ss}
-- 
2.33.1



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v7 11/13] target/hexagon: call idef-parser functions
  2021-12-17  9:01 [PATCH v7 00/13] target/hexagon: introduce idef-parser Anton Johansson via
                   ` (9 preceding siblings ...)
  2021-12-17  9:01 ` [PATCH v7 10/13] target/hexagon: import parser " Anton Johansson via
@ 2021-12-17  9:01 ` Anton Johansson via
  2021-12-22 23:21   ` Taylor Simpson
  2021-12-17  9:01 ` [PATCH v7 12/13] target/hexagon: import additional tests Anton Johansson via
  2021-12-17  9:01 ` [PATCH v7 13/13] gitlab-ci: do not use qemu-project Docker registry Anton Johansson via
  12 siblings, 1 reply; 24+ messages in thread
From: Anton Johansson via @ 2021-12-17  9:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: ale, tsimpson, bcain, babush, nizzo, richard.henderson

From: Alessandro Di Federico <ale@rev.ng>

Extend gen_tcg_funcs.py in order to emit calls to the functions emitted
by the idef-parser, if available. An option is also added to fully
disable the output of the idef-parser, which is useful for debugging purposes.

Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Taylor Simpson <tsimpson@quicinc.com>
---
 meson_options.txt                   |  3 +
 target/hexagon/gen_helper_funcs.py  | 16 ++++-
 target/hexagon/gen_helper_protos.py | 16 ++++-
 target/hexagon/gen_tcg_funcs.py     | 39 +++++++++++-
 target/hexagon/hex_common.py        | 10 ++++
 target/hexagon/meson.build          | 92 +++++++++++++++++++----------
 6 files changed, 142 insertions(+), 34 deletions(-)

diff --git a/meson_options.txt b/meson_options.txt
index 4114bfcaa4..9374a8b838 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -206,3 +206,6 @@ option('fdt', type: 'combo', value: 'auto',
 
 option('selinux', type: 'feature', value: 'auto',
        description: 'SELinux support in qemu-nbd')
+
+option('hexagon_idef_parser_enabled', type : 'boolean', value : true,
+       description: 'Whether idef-parser should be used to automatically generate TCG code for the Hexagon frontend')
diff --git a/target/hexagon/gen_helper_funcs.py b/target/hexagon/gen_helper_funcs.py
index a446c45384..7942ffeb34 100755
--- a/target/hexagon/gen_helper_funcs.py
+++ b/target/hexagon/gen_helper_funcs.py
@@ -287,11 +287,23 @@ def main():
     hex_common.read_attribs_file(sys.argv[2])
     hex_common.read_overrides_file(sys.argv[3])
     hex_common.read_overrides_file(sys.argv[4])
+    ## Whether or not idef-parser is enabled is
+    ## determined by the number of arguments to
+    ## this script:
+    ##
+    ##   5 args. -> not enabled,
+    ##   6 args. -> idef-parser enabled.
+    ##
+    ## The 6:th arg. then holds a list of the successfully
+    ## parsed instructions.
+    if len(sys.argv) > 6:
+        hex_common.read_idef_parser_enabled_file(sys.argv[5])
     hex_common.calculate_attribs()
     tagregs = hex_common.get_tagregs()
     tagimms = hex_common.get_tagimms()
 
-    with open(sys.argv[5], 'w') as f:
+    output_file = sys.argv[-1]
+    with open(output_file, 'w') as f:
         for tag in hex_common.tags:
             ## Skip the priv instructions
             if ( "A_PRIV" in hex_common.attribdict[tag] ) :
@@ -308,6 +320,8 @@ def main():
                 continue
             if ( hex_common.skip_qemu_helper(tag) ):
                 continue
+            if ( hex_common.is_idef_parser_enabled(tag) ):
+                continue
 
             gen_helper_function(f, tag, tagregs, tagimms)
 
diff --git a/target/hexagon/gen_helper_protos.py b/target/hexagon/gen_helper_protos.py
index 3b4e993fd1..29f4b35b7d 100755
--- a/target/hexagon/gen_helper_protos.py
+++ b/target/hexagon/gen_helper_protos.py
@@ -136,11 +136,23 @@ def main():
     hex_common.read_attribs_file(sys.argv[2])
     hex_common.read_overrides_file(sys.argv[3])
     hex_common.read_overrides_file(sys.argv[4])
+    ## Whether or not idef-parser is enabled is
+    ## determined by the number of arguments to
+    ## this script:
+    ##
+    ##   5 args. -> not enabled,
+    ##   6 args. -> idef-parser enabled.
+    ##
+    ## The 6:th arg. then holds a list of the successfully
+    ## parsed instructions.
+    if len(sys.argv) > 6:
+        hex_common.read_idef_parser_enabled_file(sys.argv[5])
     hex_common.calculate_attribs()
     tagregs = hex_common.get_tagregs()
     tagimms = hex_common.get_tagimms()
 
-    with open(sys.argv[5], 'w') as f:
+    output_file = sys.argv[-1]
+    with open(output_file, 'w') as f:
         for tag in hex_common.tags:
             ## Skip the priv instructions
             if ( "A_PRIV" in hex_common.attribdict[tag] ) :
@@ -158,6 +170,8 @@ def main():
 
             if ( hex_common.skip_qemu_helper(tag) ):
                 continue
+            if ( hex_common.is_idef_parser_enabled(tag) ):
+                continue
 
             gen_helper_prototype(f, tag, tagregs, tagimms)
 
diff --git a/target/hexagon/gen_tcg_funcs.py b/target/hexagon/gen_tcg_funcs.py
index 1fd9de95d5..0ea89d1ed7 100755
--- a/target/hexagon/gen_tcg_funcs.py
+++ b/target/hexagon/gen_tcg_funcs.py
@@ -610,7 +610,29 @@ def gen_tcg_func(f, tag, regs, imms):
         if (hex_common.is_read(regid)):
             genptr_src_read_opn(f,regtype,regid,tag)
 
-    if ( hex_common.skip_qemu_helper(tag) ):
+    if hex_common.is_idef_parser_enabled(tag):
+        declared = []
+        ## Handle registers
+        for regtype,regid,toss,numregs in regs:
+            if (hex_common.is_pair(regid)
+                or (hex_common.is_single(regid)
+                    and hex_common.is_old_val(regtype, regid, tag))):
+                declared.append("%s%sV" % (regtype, regid))
+                if regtype == "M":
+                    declared.append("%s%sN" % (regtype, regid))
+            elif hex_common.is_new_val(regtype, regid, tag):
+                declared.append("%s%sN" % (regtype,regid))
+            else:
+                print("Bad register parse: ",regtype,regid,toss,numregs)
+
+        ## Handle immediates
+        for immlett,bits,immshift in imms:
+            declared.append(hex_common.imm_name(immlett))
+
+        arguments = ", ".join(["ctx", "insn", "pkt"] + declared)
+        f.write("    emit_%s(%s);\n" % (tag, arguments))
+
+    elif ( hex_common.skip_qemu_helper(tag) ):
         f.write("    fGEN_TCG_%s(%s);\n" % (tag, hex_common.semdict[tag]))
     else:
         ## Generate the call to the helper
@@ -677,12 +699,25 @@ def main():
     hex_common.read_overrides_file(sys.argv[3])
     hex_common.read_overrides_file(sys.argv[4])
     hex_common.calculate_attribs()
+    ## Whether or not idef-parser is enabled is
+    ## determined by the number of arguments to
+    ## this script:
+    ##
+    ##   5 args. -> not enabled,
+    ##   6 args. -> idef-parser enabled.
+    ##
+    ## The 6:th arg. then holds a list of the successfully
+    ## parsed instructions.
+    if len(sys.argv) > 6:
+        hex_common.read_idef_parser_enabled_file(sys.argv[5])
     tagregs = hex_common.get_tagregs()
     tagimms = hex_common.get_tagimms()
 
-    with open(sys.argv[5], 'w') as f:
+    output_file = sys.argv[-1]
+    with open(output_file, 'w') as f:
         f.write("#ifndef HEXAGON_TCG_FUNCS_H\n")
         f.write("#define HEXAGON_TCG_FUNCS_H\n\n")
+        f.write("#include \"idef-generated-emitter.h.inc\"\n\n")
 
         for tag in hex_common.tags:
             ## Skip the priv instructions
diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py
index c81aca8d2a..901041d557 100755
--- a/target/hexagon/hex_common.py
+++ b/target/hexagon/hex_common.py
@@ -28,6 +28,7 @@
 attribinfo = {}       # Register information and misc
 tags = []             # list of all tags
 overrides = {}        # tags with helper overrides
+idef_parser_enabled = {} # tags enabled for idef-parser
 
 # We should do this as a hash for performance,
 # but to keep order let's keep it as a list.
@@ -216,6 +217,9 @@ def is_tmp_result(tag):
 def is_new_result(tag):
     return ('A_CVI_NEW' in attribdict[tag])
 
+def is_idef_parser_enabled(tag):
+    return tag in idef_parser_enabled
+
 def imm_name(immlett):
     return "%siV" % immlett
 
@@ -247,3 +251,9 @@ def read_overrides_file(name):
             continue
         tag = overridere.findall(line)[0]
         overrides[tag] = True
+
+def read_idef_parser_enabled_file(name):
+    global idef_parser_enabled
+    with open(name, "r") as idef_parser_enabled_file:
+        lines = idef_parser_enabled_file.read().strip().split("\n")
+        idef_parser_enabled = set(lines)
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index 96ffe497da..a332cadeea 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -43,10 +43,7 @@ hexagon_ss.add(semantics_generated)
 # Step 2
 # We use Python scripts to generate the following files
 #     shortcode_generated.h.inc
-#     helper_protos_generated.h.inc
-#     tcg_funcs_generated.c.inc
 #     tcg_func_table_generated.c.inc
-#     helper_funcs_generated.c.inc
 #     printinsn_generated.h.inc
 #     op_regs_generated.h.inc
 #     op_attribs_generated.h.inc
@@ -61,24 +58,6 @@ shortcode_generated = custom_target(
 )
 hexagon_ss.add(shortcode_generated)
 
-helper_protos_generated = custom_target(
-    'helper_protos_generated.h.inc',
-    output: 'helper_protos_generated.h.inc',
-    depends: [semantics_generated],
-    depend_files: [hex_common_py, attribs_def, gen_tcg_h, gen_tcg_hvx_h],
-    command: [python, files('gen_helper_protos.py'), semantics_generated, attribs_def, gen_tcg_h, gen_tcg_hvx_h, '@OUTPUT@'],
-)
-hexagon_ss.add(helper_protos_generated)
-
-tcg_funcs_generated = custom_target(
-    'tcg_funcs_generated.c.inc',
-    output: 'tcg_funcs_generated.c.inc',
-    depends: [semantics_generated],
-    depend_files: [hex_common_py, attribs_def, gen_tcg_h, gen_tcg_hvx_h],
-    command: [python, files('gen_tcg_funcs.py'), semantics_generated, attribs_def, gen_tcg_h, gen_tcg_hvx_h, '@OUTPUT@'],
-)
-hexagon_ss.add(tcg_funcs_generated)
-
 tcg_func_table_generated = custom_target(
     'tcg_func_table_generated.c.inc',
     output: 'tcg_func_table_generated.c.inc',
@@ -88,15 +67,6 @@ tcg_func_table_generated = custom_target(
 )
 hexagon_ss.add(tcg_func_table_generated)
 
-helper_funcs_generated = custom_target(
-    'helper_funcs_generated.c.inc',
-    output: 'helper_funcs_generated.c.inc',
-    depends: [semantics_generated],
-    depend_files: [hex_common_py, attribs_def, gen_tcg_h, gen_tcg_hvx_h],
-    command: [python, files('gen_helper_funcs.py'), semantics_generated, attribs_def, gen_tcg_h, gen_tcg_hvx_h, '@OUTPUT@'],
-)
-hexagon_ss.add(helper_funcs_generated)
-
 printinsn_generated = custom_target(
     'printinsn_generated.h.inc',
     output: 'printinsn_generated.h.inc',
@@ -180,6 +150,8 @@ hexagon_ss.add(files(
     'mmvec/system_ext_mmvec.c',
 ))
 
+idef_parser_enabled = get_option('hexagon_idef_parser_enabled')
+
 idef_parser_input_generated = custom_target(
     'idef_parser_input.h.inc',
     output: 'idef_parser_input.h.inc',
@@ -224,4 +196,64 @@ idef_generated_tcg = custom_target(
     command: [idef_parser, '@INPUT@', '@OUTPUT0@', '@OUTPUT1@', '@OUTPUT2@'],
 )
 
+indent = find_program('indent', required: false)
+if indent.found()
+  idef_generated_tcg_c = custom_target('asd',
+                                       input: idef_generated_tcg[0],
+                                       output: 'idef-generated-emitter.indented.c',
+                                       command: [indent, '-linux', '@INPUT@', '-o', '@OUTPUT@'])
+else
+  idef_generated_tcg_c = custom_target('asd',
+                                       input: idef_generated_tcg[0],
+                                       output: 'idef-generated-emitter.indented.c',
+                                       command: ['cp', '@INPUT@', '@OUTPUT@'])
+endif
+
+idef_generated_list = idef_generated_tcg[2].full_path()
+
+hexagon_ss.add(idef_generated_tcg_c)
+
+#
+# Step 5
+# We use Python scripts to generate the following files
+#     helper_protos_generated.h.inc
+#     helper_funcs_generated.c.inc
+#     tcg_funcs_generated.c.inc
+#
+if idef_parser_enabled
+  helper_dep = [semantics_generated, idef_generated_tcg_c, idef_generated_tcg]
+  helper_in = [semantics_generated, attribs_def, gen_tcg_h, gen_tcg_hvx_h,
+               idef_generated_list]
+else
+  helper_dep = [semantics_generated]
+  helper_in = [semantics_generated, attribs_def, gen_tcg_h, gen_tcg_hvx_h]
+endif
+
+helper_protos_generated = custom_target(
+    'helper_protos_generated.h.inc',
+    output: 'helper_protos_generated.h.inc',
+    depends: helper_dep,
+    depend_files: [hex_common_py, attribs_def, gen_tcg_h, gen_tcg_hvx_h],
+    command: [python, files('gen_helper_protos.py'), helper_in, '@OUTPUT@'],
+)
+hexagon_ss.add(helper_protos_generated)
+
+helper_funcs_generated = custom_target(
+    'helper_funcs_generated.c.inc',
+    output: 'helper_funcs_generated.c.inc',
+    depends: helper_dep,
+    depend_files: [hex_common_py, attribs_def, gen_tcg_h, gen_tcg_hvx_h],
+    command: [python, files('gen_helper_funcs.py'), helper_in, '@OUTPUT@'],
+)
+hexagon_ss.add(helper_funcs_generated)
+
+tcg_funcs_generated = custom_target(
+    'tcg_funcs_generated.c.inc',
+    output: 'tcg_funcs_generated.c.inc',
+    depends: helper_dep,
+    depend_files: [hex_common_py, attribs_def, gen_tcg_h, gen_tcg_hvx_h],
+    command: [python, files('gen_tcg_funcs.py'), helper_in, '@OUTPUT@'],
+)
+hexagon_ss.add(tcg_funcs_generated)
+
 target_arch += {'hexagon': hexagon_ss}
-- 
2.33.1



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v7 12/13] target/hexagon: import additional tests
  2021-12-17  9:01 [PATCH v7 00/13] target/hexagon: introduce idef-parser Anton Johansson via
                   ` (10 preceding siblings ...)
  2021-12-17  9:01 ` [PATCH v7 11/13] target/hexagon: call idef-parser functions Anton Johansson via
@ 2021-12-17  9:01 ` Anton Johansson via
  2021-12-23 18:16   ` Taylor Simpson
  2021-12-17  9:01 ` [PATCH v7 13/13] gitlab-ci: do not use qemu-project Docker registry Anton Johansson via
  12 siblings, 1 reply; 24+ messages in thread
From: Anton Johansson via @ 2021-12-17  9:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: ale, tsimpson, bcain, babush, nizzo, richard.henderson

From: Niccolò Izzo <nizzo@rev.ng>

Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Niccolò Izzo <nizzo@rev.ng>
---
 tests/tcg/hexagon/Makefile.target  | 30 +++++++++++++-
 tests/tcg/hexagon/crt.S            | 26 ++++++++++++
 tests/tcg/hexagon/test_abs.S       | 20 ++++++++++
 tests/tcg/hexagon/test_bitcnt.S    | 42 ++++++++++++++++++++
 tests/tcg/hexagon/test_bitsplit.S  | 25 ++++++++++++
 tests/tcg/hexagon/test_call.S      | 60 ++++++++++++++++++++++++++++
 tests/tcg/hexagon/test_clobber.S   | 35 +++++++++++++++++
 tests/tcg/hexagon/test_cmp.S       | 34 ++++++++++++++++
 tests/tcg/hexagon/test_cmpy.S      | 31 +++++++++++++++
 tests/tcg/hexagon/test_dotnew.S    | 36 +++++++++++++++++
 tests/tcg/hexagon/test_ext.S       | 16 ++++++++
 tests/tcg/hexagon/test_fibonacci.S | 33 ++++++++++++++++
 tests/tcg/hexagon/test_hl.S        | 19 +++++++++
 tests/tcg/hexagon/test_hwloops.S   | 22 +++++++++++
 tests/tcg/hexagon/test_jmp.S       | 25 ++++++++++++
 tests/tcg/hexagon/test_lsr.S       | 39 ++++++++++++++++++
 tests/tcg/hexagon/test_mpyi.S      | 20 ++++++++++
 tests/tcg/hexagon/test_overflow.S  | 63 ++++++++++++++++++++++++++++++
 tests/tcg/hexagon/test_packet.S    | 26 ++++++++++++
 tests/tcg/hexagon/test_reorder.S   | 29 ++++++++++++++
 tests/tcg/hexagon/test_round.S     | 31 +++++++++++++++
 tests/tcg/hexagon/test_vavgw.S     | 33 ++++++++++++++++
 tests/tcg/hexagon/test_vcmpb.S     | 32 +++++++++++++++
 tests/tcg/hexagon/test_vcmpw.S     | 29 ++++++++++++++
 tests/tcg/hexagon/test_vcmpy.S     | 50 ++++++++++++++++++++++++
 tests/tcg/hexagon/test_vlsrw.S     | 23 +++++++++++
 tests/tcg/hexagon/test_vmaxh.S     | 37 ++++++++++++++++++
 tests/tcg/hexagon/test_vminh.S     | 37 ++++++++++++++++++
 tests/tcg/hexagon/test_vpmpyh.S    | 30 ++++++++++++++
 tests/tcg/hexagon/test_vspliceb.S  | 33 ++++++++++++++++
 30 files changed, 965 insertions(+), 1 deletion(-)
 create mode 100644 tests/tcg/hexagon/crt.S
 create mode 100644 tests/tcg/hexagon/test_abs.S
 create mode 100644 tests/tcg/hexagon/test_bitcnt.S
 create mode 100644 tests/tcg/hexagon/test_bitsplit.S
 create mode 100644 tests/tcg/hexagon/test_call.S
 create mode 100644 tests/tcg/hexagon/test_clobber.S
 create mode 100644 tests/tcg/hexagon/test_cmp.S
 create mode 100644 tests/tcg/hexagon/test_cmpy.S
 create mode 100644 tests/tcg/hexagon/test_dotnew.S
 create mode 100644 tests/tcg/hexagon/test_ext.S
 create mode 100644 tests/tcg/hexagon/test_fibonacci.S
 create mode 100644 tests/tcg/hexagon/test_hl.S
 create mode 100644 tests/tcg/hexagon/test_hwloops.S
 create mode 100644 tests/tcg/hexagon/test_jmp.S
 create mode 100644 tests/tcg/hexagon/test_lsr.S
 create mode 100644 tests/tcg/hexagon/test_mpyi.S
 create mode 100644 tests/tcg/hexagon/test_overflow.S
 create mode 100644 tests/tcg/hexagon/test_packet.S
 create mode 100644 tests/tcg/hexagon/test_reorder.S
 create mode 100644 tests/tcg/hexagon/test_round.S
 create mode 100644 tests/tcg/hexagon/test_vavgw.S
 create mode 100644 tests/tcg/hexagon/test_vcmpb.S
 create mode 100644 tests/tcg/hexagon/test_vcmpw.S
 create mode 100644 tests/tcg/hexagon/test_vcmpy.S
 create mode 100644 tests/tcg/hexagon/test_vlsrw.S
 create mode 100644 tests/tcg/hexagon/test_vmaxh.S
 create mode 100644 tests/tcg/hexagon/test_vminh.S
 create mode 100644 tests/tcg/hexagon/test_vpmpyh.S
 create mode 100644 tests/tcg/hexagon/test_vspliceb.S

diff --git a/tests/tcg/hexagon/Makefile.target b/tests/tcg/hexagon/Makefile.target
index 8b07a28166..6f1c0830aa 100644
--- a/tests/tcg/hexagon/Makefile.target
+++ b/tests/tcg/hexagon/Makefile.target
@@ -24,7 +24,7 @@ CFLAGS += -fno-unroll-loops
 HEX_SRC=$(SRC_PATH)/tests/tcg/hexagon
 VPATH += $(HEX_SRC)
 
-first: $(HEX_SRC)/first.S
+%: $(HEX_SRC)/%.S $(HEX_SRC)/crt.S
 	$(CC) -static -mv67 -nostdlib $^ -o $@
 
 HEX_TESTS = first
@@ -42,4 +42,32 @@ HEX_TESTS += atomics
 HEX_TESTS += fpstuff
 HEX_TESTS += overflow
 
+HEX_TESTS += test_abs
+HEX_TESTS += test_bitcnt
+HEX_TESTS += test_bitsplit
+HEX_TESTS += test_clobber
+HEX_TESTS += test_cmp
+HEX_TESTS += test_cmpy
+HEX_TESTS += test_dotnew
+HEX_TESTS += test_ext
+HEX_TESTS += test_fibonacci
+HEX_TESTS += test_hl
+HEX_TESTS += test_hwloops
+HEX_TESTS += test_jmp
+HEX_TESTS += test_lsr
+HEX_TESTS += test_mpyi
+HEX_TESTS += test_overflow
+HEX_TESTS += test_packet
+HEX_TESTS += test_reorder
+HEX_TESTS += test_round
+HEX_TESTS += test_vavgw
+HEX_TESTS += test_vcmpb
+HEX_TESTS += test_vcmpw
+HEX_TESTS += test_vcmpy
+HEX_TESTS += test_vlsrw
+HEX_TESTS += test_vmaxh
+HEX_TESTS += test_vminh
+HEX_TESTS += test_vpmpyh
+HEX_TESTS += test_vspliceb
+
 TESTS += $(HEX_TESTS)
diff --git a/tests/tcg/hexagon/crt.S b/tests/tcg/hexagon/crt.S
new file mode 100644
index 0000000000..cb119ae407
--- /dev/null
+++ b/tests/tcg/hexagon/crt.S
@@ -0,0 +1,26 @@
+#define SYS_exit_group           94
+
+    .text
+    .globl init
+init:
+    {
+        allocframe(r29,#0):raw
+    }
+    {
+        r0=#256
+    }
+    {
+        dealloc_return
+    }
+
+    .globl pass
+pass:
+    r0 = #0
+    r6 = #SYS_exit_group
+    trap0(#1)
+
+    .globl fail
+fail:
+    r0 = #1
+    r6 = #SYS_exit_group
+    trap0(#1)
diff --git a/tests/tcg/hexagon/test_abs.S b/tests/tcg/hexagon/test_abs.S
new file mode 100644
index 0000000000..880b2886b5
--- /dev/null
+++ b/tests/tcg/hexagon/test_abs.S
@@ -0,0 +1,20 @@
+/* Purpose: test example, verify the soundness of the abs operation */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r1=#-2
+        r2=#2
+    }
+    {
+        r3=abs(r1)
+    }
+    {
+        p0 = cmp.eq(r3, r2); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_bitcnt.S b/tests/tcg/hexagon/test_bitcnt.S
new file mode 100644
index 0000000000..df77fe61e2
--- /dev/null
+++ b/tests/tcg/hexagon/test_bitcnt.S
@@ -0,0 +1,42 @@
+/* Purpose: test example, verify the soundness of the cl[01] operations
+ *
+ * the number 0x000001aa has 23 leading zeroes
+ * they become 55 when considered as 64 bit register
+ * and it has 1 trailing zero
+ */
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#426
+        r1=#0
+    }
+    {
+        r2=cl0(r0)
+    }
+    {
+        p0 = cmp.eq(r2, #23); if (p0.new) jump:t test2
+        jump fail
+    }
+
+test2:
+    {
+        r2=cl0(r1:0)
+    }
+    {
+        p0 = cmp.eq(r2, #55); if (p0.new) jump:t test3
+        jump fail
+    }
+
+test3:
+    {
+        r2=ct0(r0)
+    }
+    {
+        p0 = cmp.eq(r2, #1); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_bitsplit.S b/tests/tcg/hexagon/test_bitsplit.S
new file mode 100644
index 0000000000..787cce72e4
--- /dev/null
+++ b/tests/tcg/hexagon/test_bitsplit.S
@@ -0,0 +1,25 @@
+/* Purpose: test example, verify the soundness of the bitsplit operation */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r1=#187
+    }
+    {
+        r3:2=bitsplit(r1, #3)
+    }
+    {
+        p0 = cmp.eq(r2, #3); if (p0.new) jump:t test2
+        jump fail
+    }
+
+test2:
+    {
+        p0 = cmp.eq(r3, #23); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_call.S b/tests/tcg/hexagon/test_call.S
new file mode 100644
index 0000000000..fe59a8f006
--- /dev/null
+++ b/tests/tcg/hexagon/test_call.S
@@ -0,0 +1,60 @@
+/* Purpose: test function calls and duplex instructions.
+ * The string "Hello there, I'm a test string!" with the first letter replaced
+ * with a capital L should be printed out.
+ */
+
+    .text
+    .globl    test
+test:
+    {
+        jumpr r31
+        memb(r0+#0)=#76
+    }
+.Lfunc_end0:
+.Ltmp0:
+    .size    test, .Ltmp0-test
+
+    .globl    _start
+_start:
+    {
+        call init
+    }
+    {
+        call test
+        r0=##dummy_buffer
+        allocframe(#0)
+    }
+    {
+        call write
+    }
+    {
+        jump pass
+    }
+    {
+        r31:30=deallocframe(r30):raw
+    }
+.Lfunc_end1:
+.Ltmp1:
+    .size    _start, .Ltmp1-_start
+write:
+    {
+        r0=##dummy_buffer
+    }
+    {
+        r1=#256
+    }
+    {
+        jumpr r31
+    }
+.Lfunc_end2:
+.Ltmp2:
+    .size    write, .Ltmp2-write
+
+    .type    dummy_buffer,@object
+    .data
+    .globl    dummy_buffer
+    .p2align    3
+dummy_buffer:
+    .string    "Hello there, I'm a test string!\n"
+    .space 223
+    .size    dummy_buffer, 256
diff --git a/tests/tcg/hexagon/test_clobber.S b/tests/tcg/hexagon/test_clobber.S
new file mode 100644
index 0000000000..198817ebd5
--- /dev/null
+++ b/tests/tcg/hexagon/test_clobber.S
@@ -0,0 +1,35 @@
+/* Purpose: demonstrate the succesful operation of the register save mechanism,
+ * in which the caller saves the registers that will be clobbered, and restores
+ * them after the call.
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r16=#47
+        r17=#155
+    }
+    {
+        memd(r29+#-16)=r17:16; allocframe(#8)
+    }
+    {
+        r16=#255
+        r17=#42
+    }
+    {
+        r17:16=memd(r29+#0); deallocframe
+    }
+    {
+        r3=add(r16,r17)
+    }
+    {
+        p0 = cmp.eq(r3, #202); if (p0.new) jump:t pass
+    }
+    {
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_cmp.S b/tests/tcg/hexagon/test_cmp.S
new file mode 100644
index 0000000000..31ee9565fe
--- /dev/null
+++ b/tests/tcg/hexagon/test_cmp.S
@@ -0,0 +1,34 @@
+/* Purpose: test a signed and unsigned comparison */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        jump signed
+    }
+
+    .globl signed
+signed:
+    {
+        r0=#-2
+        r1=#0
+    }
+    {
+        p0 = cmp.lt(r0, r1); if (p0.new) jump:t unsigned
+        jump fail
+    }
+
+    .globl unsigned
+unsigned:
+    {
+        r0=#-2
+        r1=#0
+    }
+    {
+        p0 = cmp.gtu(r0, r1); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_cmpy.S b/tests/tcg/hexagon/test_cmpy.S
new file mode 100644
index 0000000000..0b3dfb95de
--- /dev/null
+++ b/tests/tcg/hexagon/test_cmpy.S
@@ -0,0 +1,31 @@
+/* Purpose: test example, verify the soundness of the cmpy operation
+ *
+ *  3j+5 * 2j+4 = 22j+14
+ *
+ * the complex multiply between 0x00030005 and 0x00020004 is 0x000000160000000e
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#196613
+        r1=#131076
+    }
+    {
+        r3:2=cmpy(r0, r1):sat
+    }
+    {
+        p0 = cmp.eq(r2, #14); if (p0.new) jump:t test2
+        jump fail
+    }
+
+test2:
+    {
+        p0 = cmp.eq(r3, #22); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_dotnew.S b/tests/tcg/hexagon/test_dotnew.S
new file mode 100644
index 0000000000..70886d9483
--- /dev/null
+++ b/tests/tcg/hexagon/test_dotnew.S
@@ -0,0 +1,36 @@
+/* Purpose: test the .new operator while performing memory stores. */
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#1
+        memw(sp+#0)=r0.new
+    }
+    {
+        r1=#2
+        memw(sp+#4)=r1.new
+    }
+    {
+        r2=#3
+        memw(sp+#8)=r2.new
+    }
+    {
+        r0=memw(sp+#8)
+    }
+    {
+        r1=memw(sp+#4)
+    }
+    {
+        r2=memw(sp+#0)
+    }
+    {
+        r3=mpyi(r1,r2)
+    }
+    {
+        p0 = cmp.eq(r3, #2); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_ext.S b/tests/tcg/hexagon/test_ext.S
new file mode 100644
index 0000000000..0b855bc8e8
--- /dev/null
+++ b/tests/tcg/hexagon/test_ext.S
@@ -0,0 +1,16 @@
+/* Purpose: test immediate extender instructions. */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r2=##-559038737
+    }
+    {
+        p0 = cmp.eq(r2, ##-559038737); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_fibonacci.S b/tests/tcg/hexagon/test_fibonacci.S
new file mode 100644
index 0000000000..41cb1517cb
--- /dev/null
+++ b/tests/tcg/hexagon/test_fibonacci.S
@@ -0,0 +1,33 @@
+/* Purpose: computes the Fibonacci series up to a constant number. */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r2=#100
+    }
+    {
+        p0=cmp.gt(r2,#0); if (!p0.new) jump:nt .LBB0_3
+    }
+    {
+        r3=#0
+        r4=#1
+    }
+.LBB0_2:
+    {
+        r5=r4
+    }
+    {
+        p0=cmp.gt(r2,r5); if (p0.new) jump:nt .LBB0_2
+        r4=add(r3,r4)
+        r3=r5
+    }
+.LBB0_3:
+    {
+        p0 = cmp.eq(r3, #144); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_hl.S b/tests/tcg/hexagon/test_hl.S
new file mode 100644
index 0000000000..217b3143e2
--- /dev/null
+++ b/tests/tcg/hexagon/test_hl.S
@@ -0,0 +1,19 @@
+/* Purpose: test example, verify the soundness of the high/low assignment */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0.H=#42
+    }
+    {
+        r0.L=#69
+    }
+    {
+        p0 = cmp.eq(r0, #2752581); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_hwloops.S b/tests/tcg/hexagon/test_hwloops.S
new file mode 100644
index 0000000000..b6e858bcb7
--- /dev/null
+++ b/tests/tcg/hexagon/test_hwloops.S
@@ -0,0 +1,22 @@
+/* Purpose: simple C Program to test hardware loops. */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        loop0(.LBB0_1,#10)
+        r2=#0
+    }
+.LBB0_1:
+    {
+        r2=add(r2,#1)
+        nop
+    }:endloop0
+    {
+        p0 = cmp.eq(r2, #10); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_jmp.S b/tests/tcg/hexagon/test_jmp.S
new file mode 100644
index 0000000000..9bf6ea34e5
--- /dev/null
+++ b/tests/tcg/hexagon/test_jmp.S
@@ -0,0 +1,25 @@
+/* Purpose: test example, verify the soundness of the add operation */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r1=#0
+        r2=#0
+    }
+    {
+        r3=add(r1,r2)
+    }
+    {
+        p0 = cmp.eq(r3, #0)
+    }
+    {
+        if (p0) jump:t pass
+    }
+    {
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_lsr.S b/tests/tcg/hexagon/test_lsr.S
new file mode 100644
index 0000000000..202eb4aec7
--- /dev/null
+++ b/tests/tcg/hexagon/test_lsr.S
@@ -0,0 +1,39 @@
+/* Purpose: test the soundness of the lsr operation */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#-56984
+        r1=#2147483647
+    }
+    {
+        r2=#0x19
+    }
+    {
+        r0&=lsr(r1, r2)
+    }
+    {
+        p0 = cmp.eq(r0, #0x28); if (p0.new) jump:t test2
+        jump fail
+    }
+
+test2:
+    {
+        r0=#0x0000000a
+        r1=#0x00000000
+    }
+    {
+        r2=#-1
+    }
+    {
+        r1:0=lsl(r1:0, r2)
+    }
+    {
+        p0 = cmp.eq(r0, #0x5); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_mpyi.S b/tests/tcg/hexagon/test_mpyi.S
new file mode 100644
index 0000000000..b8e0d50b68
--- /dev/null
+++ b/tests/tcg/hexagon/test_mpyi.S
@@ -0,0 +1,20 @@
+/* Purpose: test a simple multiplication operation */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r1=#4
+        r2=#6
+    }
+    {
+        r3=mpyi(r1,r2)
+    }
+    {
+        p0 = cmp.eq(r3, #24); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_overflow.S b/tests/tcg/hexagon/test_overflow.S
new file mode 100644
index 0000000000..9e2a235616
--- /dev/null
+++ b/tests/tcg/hexagon/test_overflow.S
@@ -0,0 +1,63 @@
+// Purpose: test example, verify the soundness of the overflow bit
+//
+// a right shift with negative amount should make r0 saturate, setting the
+// overflow bit
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#0x10000000
+        r1=#-2
+    }
+    {
+        r2=asr(r0, r1):sat
+    }
+    {
+        r4=USR
+    }
+    {
+        r5=and(r4,#1)
+    }
+    {
+        p0 = cmp.eq(r5, #0); if (p0.new) jump:t check_ovfl
+        jump fail
+    }
+check_ovfl:
+    {
+        r1=#-3
+    }
+    {
+        r2=asr(r0, r1):sat
+    }
+    {
+        r4=USR
+    }
+    {
+        r5=and(r4,#1)
+    }
+    {
+        p0 = cmp.eq(r5, #1); if (p0.new) jump:t check_sticky
+        jump fail
+    }
+check_sticky:
+    {
+        r1=#-2
+    }
+    {
+        r2=asr(r0, r1):sat
+    }
+    {
+        r4=USR
+    }
+    {
+        r5=and(r4,#1)
+    }
+    {
+        p0 = cmp.eq(r5, #1); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_packet.S b/tests/tcg/hexagon/test_packet.S
new file mode 100644
index 0000000000..d26e284be9
--- /dev/null
+++ b/tests/tcg/hexagon/test_packet.S
@@ -0,0 +1,26 @@
+/* Purpose: test that writes of a register in a packet are performed only after
+ * that packet has finished its execution.
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r2=#4
+        r3=#6
+    }
+    {
+        memw(sp+#0)=r2
+    }
+    {
+        r3=memw(sp+#0)
+        r0=add(r2,r3)
+    }
+    {
+        p0 = cmp.eq(r0, #10); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_reorder.S b/tests/tcg/hexagon/test_reorder.S
new file mode 100644
index 0000000000..f341a0142b
--- /dev/null
+++ b/tests/tcg/hexagon/test_reorder.S
@@ -0,0 +1,29 @@
+/* Purpose: demonstrate handling of .new uses appearing before the associated
+ * definition.
+ * Here we perform a jump that skips the code resetting R2 from 0xDEADBEEF to 0,
+ * only if P0.new is true, but P0 is assigned to 1 (R4) in the next instruction
+ * in the packet.
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    { r2=#-559038737 }
+    { r4=#1 }
+    {
+        if (p0.new) jump:nt skip
+        p0=r4;
+    }
+
+fallthrough:
+    { r2=#0 }
+
+skip:
+    {
+        p0 = cmp.eq(r2, #-559038737); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_round.S b/tests/tcg/hexagon/test_round.S
new file mode 100644
index 0000000000..2becd62c4c
--- /dev/null
+++ b/tests/tcg/hexagon/test_round.S
@@ -0,0 +1,31 @@
+/* Purpose: test example, verify the soundness of the cround operation
+ * 106 = 0b1101010 with the comma at third digit is 12.5 which is crounded to 12
+ * but rounded to 13
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r1=#200
+    }
+    {
+        r2=round(r1, #4)
+    }
+    {
+        p0 = cmp.eq(r2, #13); if (p0.new) jump:t test2
+        jump fail
+    }
+
+test2:
+    {
+        r2=cround(r1, #4)
+    }
+    {
+        p0 = cmp.eq(r2, #12); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_vavgw.S b/tests/tcg/hexagon/test_vavgw.S
new file mode 100644
index 0000000000..8f67238900
--- /dev/null
+++ b/tests/tcg/hexagon/test_vavgw.S
@@ -0,0 +1,33 @@
+/* Purpose: test example, verify the soundness of the vavgw operation
+ *
+ * 0x00030001 averaged with 0x00010003 results 0x00020002
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#3
+        r1=#1
+    }
+    {
+        r2=#1
+        r3=#3
+    }
+    {
+        r1:0=vavgw(r1:0, r3:2):crnd
+    }
+    {
+        p0 = cmp.eq(r0, #2); if (p0.new) jump:t test2
+        jump fail
+    }
+
+test2:
+    {
+        p0 = cmp.eq(r1, #2); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_vcmpb.S b/tests/tcg/hexagon/test_vcmpb.S
new file mode 100644
index 0000000000..3c6700a63a
--- /dev/null
+++ b/tests/tcg/hexagon/test_vcmpb.S
@@ -0,0 +1,32 @@
+/* Purpose: test example, verify the soundness of the vector compare bytes
+ * operation
+ *
+ * Vector word comparison between 0x1234567887654321 and 0x1234567800000000
+ * should result in 0x11110000
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#305419896
+        r1=#-2023406815
+    }
+    {
+        r2=#305419896
+        r3=#0
+    }
+    {
+        p2=vcmpb.eq(r1:0, r3:2)
+    }
+    {
+        r4=p2
+    }
+    {
+        p0 = cmp.eq(r4, #15); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_vcmpw.S b/tests/tcg/hexagon/test_vcmpw.S
new file mode 100644
index 0000000000..112f08c92f
--- /dev/null
+++ b/tests/tcg/hexagon/test_vcmpw.S
@@ -0,0 +1,29 @@
+/* Purpose: test example, verify the soundness of the vector compare words
+ * operation
+ *
+ * Vector word comparison between 0x1234567887654321 and 0x1234567800000000
+ * should result in 0x11110000
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#305419896
+        r1=#-2023406815
+    }
+    {
+        r2=#305419896
+        r3=#0
+    }
+    {
+        p2=vcmpw.eq(r1:0, r3:2)
+    }
+    {
+        if (p2) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_vcmpy.S b/tests/tcg/hexagon/test_vcmpy.S
new file mode 100644
index 0000000000..df379f9186
--- /dev/null
+++ b/tests/tcg/hexagon/test_vcmpy.S
@@ -0,0 +1,50 @@
+/* Purpose: test example, verify the soundness of the vcmpy operation
+ * this operation is a complex multiply and accumulate on vectors of two values
+ *
+ *     (3j+5 * 2j+4) + (4j+6 * 5j+2) = 22j+14
+ *
+ * the complex multiply between  0x00030005 and 0x00020004 is 0x000000160000000e
+ * the complex multiply between  0x00040006 and 0x00050002 is 0x000000160000000e
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#196613
+        r1=#131076
+    }
+    {
+        r2=#262150
+        r3=#327682
+    }
+    {
+        r5:4=vcmpyr(r1:0, r3:2):sat
+        r7:6=vcmpyi(r1:0, r3:2):sat
+    }
+    {
+        p0 = cmp.eq(r4, #18); if (p0.new) jump:t test2
+        jump fail
+    }
+
+test2:
+    {
+        p0 = cmp.eq(r5, #-2); if (p0.new) jump:t test3
+        jump fail
+    }
+
+test3:
+    {
+        p0 = cmp.eq(r6, #38); if (p0.new) jump:t test4
+        jump fail
+    }
+
+test4:
+    {
+        p0 = cmp.eq(r7, #24); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_vlsrw.S b/tests/tcg/hexagon/test_vlsrw.S
new file mode 100644
index 0000000000..962ec99543
--- /dev/null
+++ b/tests/tcg/hexagon/test_vlsrw.S
@@ -0,0 +1,23 @@
+/* Purpose: test the soundness of the vlsrw operation */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#0x00000001
+        r1=#0x00000001
+    }
+    {
+        r1:0=vlsrw(r1:0, #1)
+    }
+    {
+        r0 = add(r0, r1)
+    }
+    {
+        p0 = cmp.eq(r0, #0); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_vmaxh.S b/tests/tcg/hexagon/test_vmaxh.S
new file mode 100644
index 0000000000..1fce935e35
--- /dev/null
+++ b/tests/tcg/hexagon/test_vmaxh.S
@@ -0,0 +1,37 @@
+/* Purpose: test example, verify the soundness of the vrmaxh operation
+ *
+ * the maximum between  0x0002000300010005 and 0x0003000200020007 is
+ * 0x0003000300020007.
+ *
+ *                      r1=0x00010003 r0=0x00010005 r3=0x00030002 r2=0x00020007
+ *     result:          r1=0x00030003 r0=0x00020007
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#65541
+        r1=#65539
+    }
+    {
+        r2=#131079
+        r3=#196610
+    }
+    {
+        r1:0=vmaxh(r1:0, r3:2)
+    }
+    {
+        p0 = cmp.eq(r0, #131079); if (p0.new) jump:t test2
+        jump fail
+    }
+
+test2:
+    {
+        p0 = cmp.eq(r1, #196611); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_vminh.S b/tests/tcg/hexagon/test_vminh.S
new file mode 100644
index 0000000000..6c6d18c673
--- /dev/null
+++ b/tests/tcg/hexagon/test_vminh.S
@@ -0,0 +1,37 @@
+/* Purpose: test example, verify the soundness of the vrmaxh operation
+ *
+ * the minimum between  0x0002000300010005 and 0x0003000200020007 is
+ * 0x0003000300020007
+ *
+ *                      r1=0x00010003 r0=0x00010005 r3=0x00030002 r2=0x00020007
+ *     result:          r1=0x00010002 r0=0x00010005
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#65541
+        r1=#65539
+    }
+    {
+        r2=#131079
+        r3=#196610
+    }
+    {
+        r1:0=vminh(r1:0, r3:2)
+    }
+    {
+        p0 = cmp.eq(r0, #65541); if (p0.new) jump:t test2
+        jump fail
+    }
+
+test2:
+    {
+        p0 = cmp.eq(r1, #65538); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_vpmpyh.S b/tests/tcg/hexagon/test_vpmpyh.S
new file mode 100644
index 0000000000..942d691da4
--- /dev/null
+++ b/tests/tcg/hexagon/test_vpmpyh.S
@@ -0,0 +1,30 @@
+/* Purpose: test example, verify the soundness of the vpmpyh operator
+ *
+ * 0x01020304 vector polynomial multiplied with 0x04030201 results
+ * 0x000400060b060b04
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#16909060
+        r1=#67305985
+    }
+    {
+        r1:0=vpmpyh(r0, r1)
+    }
+    {
+        p0 = cmp.eq(r0, #184945412); if (p0.new) jump:t test2
+        jump fail
+    }
+
+test2:
+    {
+        p0 = cmp.eq(r1, #262150); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_vspliceb.S b/tests/tcg/hexagon/test_vspliceb.S
new file mode 100644
index 0000000000..bae2a9c163
--- /dev/null
+++ b/tests/tcg/hexagon/test_vspliceb.S
@@ -0,0 +1,33 @@
+/* Purpose: test example, verify the soundness of the vspliceb operation
+ * the operation is a binary splice of two 64bit operators
+ *
+ *  vspliceb(0xffffffffffffffff,0x0000000000000000,5) = 0x000000000000001f
+ */
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#-1
+        r1=#-1
+    }
+    {
+        r2=#0
+        r3=#0
+    }
+    {
+        r5:4=vspliceb(r1:0, r3:2, #5)
+    }
+    {
+        p0 = cmp.eq(r4, #-1); if (p0.new) jump:t test2
+        jump fail
+    }
+
+test2:
+    {
+        p0 = cmp.eq(r5, #255); if (p0.new) jump:t pass
+        jump fail
+    }
-- 
2.33.1



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v7 13/13] gitlab-ci: do not use qemu-project Docker registry
  2021-12-17  9:01 [PATCH v7 00/13] target/hexagon: introduce idef-parser Anton Johansson via
                   ` (11 preceding siblings ...)
  2021-12-17  9:01 ` [PATCH v7 12/13] target/hexagon: import additional tests Anton Johansson via
@ 2021-12-17  9:01 ` Anton Johansson via
  12 siblings, 0 replies; 24+ messages in thread
From: Anton Johansson via @ 2021-12-17  9:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: ale, tsimpson, bcain, babush, nizzo, richard.henderson

From: Alessandro Di Federico <ale@rev.ng>

This commit is necessary in order to use container built by the current
run of the CI. If we don't do this, we use official containers which are
not affected by the additional dependencies we're introducing.

This should be considered as a temporary solution in order to test this
patchset.

Signed-off-by: Alessandro Di Federico <ale@rev.ng>
---
 .gitlab-ci.d/container-cross.yml    | 2 +-
 .gitlab-ci.d/container-template.yml | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.gitlab-ci.d/container-cross.yml b/.gitlab-ci.d/container-cross.yml
index a3b5b90552..07531965da 100644
--- a/.gitlab-ci.d/container-cross.yml
+++ b/.gitlab-ci.d/container-cross.yml
@@ -63,7 +63,7 @@ hexagon-cross-container:
     - docker:dind
   before_script:
     - export TAG="$CI_REGISTRY_IMAGE/qemu/$NAME:latest"
-    - export COMMON_TAG="$CI_REGISTRY/qemu-project/qemu/qemu/$NAME:latest"
+    - export COMMON_TAG="$CI_REGISTRY_IMAGE/qemu/$NAME:latest"
     - docker info
     - docker login $CI_REGISTRY -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD"
   script:
diff --git a/.gitlab-ci.d/container-template.yml b/.gitlab-ci.d/container-template.yml
index 1baecd9460..c85ae377b8 100644
--- a/.gitlab-ci.d/container-template.yml
+++ b/.gitlab-ci.d/container-template.yml
@@ -5,7 +5,7 @@
     - docker:dind
   before_script:
     - export TAG="$CI_REGISTRY_IMAGE/qemu/$NAME:latest"
-    - export COMMON_TAG="$CI_REGISTRY/qemu-project/qemu/$NAME:latest"
+    - export COMMON_TAG="$CI_REGISTRY_IMAGE/qemu/$NAME:latest"
     - apk add python3
     - docker info
     - docker login $CI_REGISTRY -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD"
@@ -14,7 +14,7 @@
     - echo "COMMON_TAG:$COMMON_TAG"
     - ./tests/docker/docker.py --engine docker build
           -t "qemu/$NAME" -f "tests/docker/dockerfiles/$NAME.docker"
-          -r $CI_REGISTRY/qemu-project/qemu
+          -r $CI_REGISTRY_IMAGE
     - docker tag "qemu/$NAME" "$TAG"
     - docker push "$TAG"
   after_script:
-- 
2.33.1



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* RE: [PATCH v7 01/13] target/hexagon: update MAINTAINERS for idef-parser
  2021-12-17  9:01 ` [PATCH v7 01/13] target/hexagon: update MAINTAINERS for idef-parser Anton Johansson via
@ 2021-12-20 22:50   ` Taylor Simpson
  0 siblings, 0 replies; 24+ messages in thread
From: Taylor Simpson @ 2021-12-20 22:50 UTC (permalink / raw)
  To: Anton Johansson, qemu-devel
  Cc: ale, Brian Cain, richard.henderson, babush, nizzo



> -----Original Message-----
> From: Anton Johansson <anjo@rev.ng>
> Sent: Friday, December 17, 2021 2:01 AM
> To: qemu-devel@nongnu.org
> Cc: ale@rev.ng; Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; babush@rev.ng; nizzo@rev.ng;
> richard.henderson@linaro.org
> Subject: [PATCH v7 01/13] target/hexagon: update MAINTAINERS for idef-
> parser
> 
> From: Alessandro Di Federico <ale@rev.ng>
> 
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Anton Johansson <anjo@rev.ng>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  MAINTAINERS | 11 ++++++++++-
>  1 file changed, 10 insertions(+), 1 deletion(-)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 7543eb4d59..f6fbc5f664 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS


> @@ -2788,7 +2797,7 @@ R: Paolo Bonzini <pbonzini@redhat.com>
>  R: Bandan Das <bsd@redhat.com>
>  R: Stefan Hajnoczi <stefanha@redhat.com>
>  R: Thomas Huth <thuth@redhat.com>
> -R: Darren Kenny <darren.kenny@oracle.com>
> +R: Darren Kenny <darren.kenny@oracle.com>

This change looks spurious.  Otherwise
Reviewed-by: Taylor Simpson <tsimpson@quicinc.com>


^ permalink raw reply	[flat|nested] 24+ messages in thread

* RE: [PATCH v7 09/13] target/hexagon: import lexer for idef-parser
  2021-12-17  9:01 ` [PATCH v7 09/13] target/hexagon: import lexer for idef-parser Anton Johansson via
@ 2021-12-21 18:48   ` Taylor Simpson
  0 siblings, 0 replies; 24+ messages in thread
From: Taylor Simpson @ 2021-12-21 18:48 UTC (permalink / raw)
  To: Anton Johansson, qemu-devel
  Cc: ale, Brian Cain, richard.henderson, babush, nizzo

[-- Attachment #1: Type: text/plain, Size: 2428 bytes --]



> -----Original Message-----
> From: Anton Johansson <anjo@rev.ng>
> Sent: Friday, December 17, 2021 2:01 AM
> To: qemu-devel@nongnu.org
> Cc: ale@rev.ng; Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; babush@rev.ng; nizzo@rev.ng;
> richard.henderson@linaro.org
> Subject: [PATCH v7 09/13] target/hexagon: import lexer for idef-parser
> 
> From: Paolo Montesel <babush@rev.ng>
> 
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Paolo Montesel <babush@rev.ng>
> Signed-off-by: Anton Johansson <anjo@rev.ng>
> ---
>  target/hexagon/idef-parser/idef-parser.h   | 259 ++++++++++
>  target/hexagon/idef-parser/idef-parser.lex | 571
> +++++++++++++++++++++
>  target/hexagon/meson.build                 |   4 +
>  3 files changed, 834 insertions(+)
>  create mode 100644 target/hexagon/idef-parser/idef-parser.h
>  create mode 100644 target/hexagon/idef-parser/idef-parser.lex
> 
> diff --git a/target/hexagon/idef-parser/idef-parser.lex
> b/target/hexagon/idef-parser/idef-parser.lex
> new file mode 100644
> index 0000000000..c7466c47f4
> --- /dev/null
> +++ b/target/hexagon/idef-parser/idef-parser.lex
> +"fSATN"                  { yylval->sat.set_overflow = true;
> +                           yylval->sat.signedness = SIGNED;
> +                           return SAT; }
> +"fVSATN"                 { yylval->sat.set_overflow = false;
> +                           yylval->sat.signedness = SIGNED;
> +                           return SAT; }
> +"fSATUN"                 { yylval->sat.set_overflow = false;

This should be true, just like fSATN.  Take a look at the satuh and satub instructions.

I tried changing it to true to make satuh and satub work.  However, the vaddubs, vadduhs, vsatub, vsatwuh, vsububs, and other instructions don't work.  I've attached a test case that demonstrates this problem.

When the value is set to false, the test case prints
ERROR at line 71: 0x00000000 != 0x00000001
ERROR at line 75: 0x00000000 != 0x00000001
ERROR at line 106: 0x00000000 != 0x00000001
FAIL

When the value is set to true, the test case prints
ERROR at line 105: 0x000000000000007f != 0x00000000000000ff
ERROR at line 106: 0x00000000 != 0x00000001
FAIL

Without your changes, the test case prints
PASS



> +                           yylval->sat.signedness = UNSIGNED;
> +                           return SAT; }

[-- Attachment #2: satub_vaddubs.c --]
[-- Type: text/plain, Size: 3070 bytes --]

/*
 *  Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdint.h>

int err;

static void __check32(int line, int val, int expect)
{
    if (val != expect) {
        printf("ERROR at line %d: 0x%08x != 0x%08x\n", line, val, expect);
        err++;
    }
}

#define check32(RES, EXP) __check32(__LINE__, RES, EXP)

static void __check64(int line, long long val, long long expect)
{
    if (val != expect) {
        printf("ERROR at line %d: 0x%016llx != 0x%016llx\n", line, val, expect);
        err++;
    }
}

#define check64(RES, EXP) __check64(__LINE__, RES, EXP)

static uint32_t satub(uint32_t src, int *ovf_result)
{
    uint32_t result;
    uint32_t usr;

    /*
     * This instruction can set bit 0 (OVF/overflow) in usr
     * Clear the bit first, then return that bit to the caller
     */
    asm volatile("r2 = usr\n\t"
                 "r2 = clrbit(r2, #0)\n\t"        /* clear overflow bit */
                 "usr = r2\n\t"
                 "%0 = satub(%2)\n\t"
                 "%1 = usr\n\t"
                 : "=r"(result), "=r"(usr)
                 : "r"(src)
                 : "r2", "usr");
    *ovf_result = (usr & 1);
    return result;
}

static void test_satub(void)
{
    uint32_t result;
    int ovf_result;

    result = satub(0xfff, &ovf_result);
    check32(result, 0xff);
    check32(ovf_result, 1);

    result = satub(-1, &ovf_result);
    check32(result, 0);
    check32(ovf_result, 1);
}

static uint64_t vaddubs(uint64_t src1, uint64_t src2, int *ovf_result)
{
    uint64_t result;
    uint32_t usr;

    /*
     * This instruction can set bit 0 (OVF/overflow) in usr
     * Clear the bit first, then return that bit to the caller
     */
    asm volatile("r2 = usr\n\t"
                 "r2 = clrbit(r2, #0)\n\t"        /* clear overflow bit */
                 "usr = r2\n\t"
                 "%0 = vaddub(%2, %3):sat\n\t"
                 "%1 = usr\n\t"
                 : "=r"(result), "=r"(usr)
                 : "r"(src1), "r"(src2)
                 : "r2", "usr");
    *ovf_result = (usr & 1);
    return result;
}

static void test_vaddubs(void)
{
    uint64_t result;
    int ovf_result;

    result = vaddubs(0xffLL, 0xffLL, &ovf_result);
    check64(result, 0xffLL);
    check32(ovf_result, 1);
}

int main()
{
    test_satub();
    test_vaddubs();

    puts(err ? "FAIL" : "PASS");
    return err;
}

^ permalink raw reply	[flat|nested] 24+ messages in thread

* RE: [PATCH v7 05/13] target/hexagon: introduce new helper functions
  2021-12-17  9:01 ` [PATCH v7 05/13] target/hexagon: introduce new helper functions Anton Johansson via
@ 2021-12-21 18:51   ` Taylor Simpson
  2021-12-22 19:29   ` Taylor Simpson
  1 sibling, 0 replies; 24+ messages in thread
From: Taylor Simpson @ 2021-12-21 18:51 UTC (permalink / raw)
  To: Anton Johansson, qemu-devel
  Cc: ale, Brian Cain, richard.henderson, babush, nizzo



> -----Original Message-----
> From: Anton Johansson <anjo@rev.ng>
> Sent: Friday, December 17, 2021 2:01 AM
> To: qemu-devel@nongnu.org
> Cc: ale@rev.ng; Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; babush@rev.ng; nizzo@rev.ng;
> richard.henderson@linaro.org
> Subject: [PATCH v7 05/13] target/hexagon: introduce new helper functions
> 
> From: Niccolò Izzo <nizzo@rev.ng>
> 
> These helpers will be employed by the idef-parser generated code.
> "Helper" can here mean two things, a helper in the QEMU sense added to
> `helper.h` and `op_helper.c`, but also helper functions providing a manual
> TCG implementation of a certain features.
> 
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Niccolò Izzo <nizzo@rev.ng>
> Signed-off-by: Anton Johansson <anjo@rev.ng>
> ---
>  target/hexagon/genptr.c    | 166
> +++++++++++++++++++++++++++++++++++--
>  target/hexagon/genptr.h    |  16 +++-
>  target/hexagon/helper.h    |   2 +
>  target/hexagon/macros.h    |   9 ++
>  target/hexagon/op_helper.c |  10 +++
>  5 files changed, 195 insertions(+), 8 deletions(-)
> 
> diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index
> ae798e921e..44a1ec9ccf 100644
> +void gen_satu_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int
> +width) {
> +    gen_sat_i64(dest, source, width);

Should be gen_satu_i64 (unsigned)


> +    TCGv_i64 ovfl_64 = tcg_temp_new_i64();
> +    tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, dest, source);
> +    tcg_gen_trunc_i64_tl(ovfl, ovfl_64);
> +    tcg_temp_free_i64(ovfl_64);
> +}


^ permalink raw reply	[flat|nested] 24+ messages in thread

* RE: [PATCH v7 05/13] target/hexagon: introduce new helper functions
  2021-12-17  9:01 ` [PATCH v7 05/13] target/hexagon: introduce new helper functions Anton Johansson via
  2021-12-21 18:51   ` Taylor Simpson
@ 2021-12-22 19:29   ` Taylor Simpson
  1 sibling, 0 replies; 24+ messages in thread
From: Taylor Simpson @ 2021-12-22 19:29 UTC (permalink / raw)
  To: Anton Johansson, qemu-devel
  Cc: ale, Brian Cain, richard.henderson, babush, nizzo



> -----Original Message-----
> From: Anton Johansson <anjo@rev.ng>
> Sent: Friday, December 17, 2021 2:01 AM
> To: qemu-devel@nongnu.org
> Cc: ale@rev.ng; Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; babush@rev.ng; nizzo@rev.ng;
> richard.henderson@linaro.org
> Subject: [PATCH v7 05/13] target/hexagon: introduce new helper functions
> 
> From: Niccolò Izzo <nizzo@rev.ng>
> 
> These helpers will be employed by the idef-parser generated code.
> "Helper" can here mean two things, a helper in the QEMU sense added to
> `helper.h` and `op_helper.c`, but also helper functions providing a manual
> TCG implementation of a certain features.
> 
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Niccolò Izzo <nizzo@rev.ng>
> Signed-off-by: Anton Johansson <anjo@rev.ng>
> ---
>  target/hexagon/genptr.c    | 166
> +++++++++++++++++++++++++++++++++++--
>  target/hexagon/genptr.h    |  16 +++-
>  target/hexagon/helper.h    |   2 +
>  target/hexagon/macros.h    |   9 ++
>  target/hexagon/op_helper.c |  10 +++
>  5 files changed, 195 insertions(+), 8 deletions(-)
> 
> diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index
> 
> +void gen_sat_i64(TCGv_i64 dest, TCGv_i64 source, int width) {
> +    TCGv_i64 max_val = tcg_const_i64((1 << (width - 1)) - 1);
> +    TCGv_i64 min_val = tcg_const_i64(-(1 << (width - 1)));

Doing those calculations as 32-bit numbers could be risky.  Either do the calculations in 64-bits (1LL << (width -1) -1LL) or assert that width <= 32.

Also, consider changing all the tcg_const_* to tcg_constant_*.  This is new in TCG and lets you avoid the tcg_temp_free at the end.

> +    tcg_gen_smin_i64(dest, source, max_val);
> +    tcg_gen_smax_i64(dest, dest, min_val);
> +    tcg_temp_free_i64(max_val);
> +    tcg_temp_free_i64(min_val);
> +}
> +
> +void gen_satu_i64(TCGv_i64 dest, TCGv_i64 source, int width) {
> +    TCGv_i64 max_val = tcg_const_i64((1 << width) - 1);

Same comment about this constant.

> +    tcg_gen_movcond_i64(TCG_COND_GTU, dest, source, max_val,
> max_val, source);
> +    TCGv_i64 zero = tcg_const_i64(0);

QEMU coding conventions call for declarations to be at the top of the function, not in the middle.

> +    tcg_gen_movcond_i64(TCG_COND_LT, dest, source, zero, zero, dest);
> +    tcg_temp_free_i64(max_val);
> +    tcg_temp_free_i64(zero);
> +}
> +
> +void gen_satu_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int
> +width) {
> +    gen_sat_i64(dest, source, width);

gen_satu_i64

> +    TCGv_i64 ovfl_64 = tcg_temp_new_i64();
> +    tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, dest, source);
> +    tcg_gen_trunc_i64_tl(ovfl, ovfl_64);
> +    tcg_temp_free_i64(ovfl_64);
> +}
> +
> +/* Implements the fADDSAT64 macro in TCG */ void
> +gen_add_sat_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b) {
> +    TCGv_i64 sum = tcg_temp_local_new_i64();
> +    tcg_gen_add_i64(sum, a, b);
> +
> +    TCGv_i64 xor = tcg_temp_new_i64();
> +    tcg_gen_xor_i64(xor, a, b);
> +
> +    TCGv_i64 mask = tcg_constant_i64(0x8000000000000000ULL);
> +
> +    TCGv_i64 cond1 = tcg_temp_local_new_i64();

This can be just tcg_temp_new_i64.

> +    tcg_gen_and_i64(cond1, xor, mask);
> +    tcg_temp_free_i64(xor);
> +
> +    TCGv_i64 cond2 = tcg_temp_local_new_i64();
> +    tcg_gen_xor_i64(cond2, a, sum);
> +    tcg_gen_and_i64(cond2, cond2, mask);
> +
> +    TCGLabel *no_ovfl_label = gen_new_label();
> +    TCGLabel *ovfl_label = gen_new_label();
> +    TCGLabel *ret_label = gen_new_label();
> +
> +    tcg_gen_brcondi_i64(TCG_COND_NE, cond1, 0, no_ovfl_label);
> +    tcg_temp_free_i64(cond1);
> +    tcg_gen_brcondi_i64(TCG_COND_NE, cond2, 0, ovfl_label);
> +    tcg_temp_free_i64(cond2);
> +    tcg_gen_br(no_ovfl_label);

This is redundant since the label is just after the jump.

> +
> +    gen_set_label(no_ovfl_label);
> +    tcg_gen_mov_i64(ret, sum);
> +    tcg_gen_br(ret_label);
> +
> +    gen_set_label(ovfl_label);
> +    TCGv_i64 cond3 = tcg_temp_new_i64();
> +    tcg_gen_and_i64(cond3, sum, mask);
> +    tcg_temp_free_i64(mask);
> +    tcg_temp_free_i64(sum);
> +    TCGv_i64 max_pos = tcg_constant_i64(0x7FFFFFFFFFFFFFFFLL);
> +    TCGv_i64 max_neg = tcg_constant_i64(0x8000000000000000LL);
> +    TCGv_i64 zero = tcg_constant_i64(0);
> +    tcg_gen_movcond_i64(TCG_COND_NE, ret, cond3, zero, max_pos,
> max_neg);
> +    tcg_temp_free_i64(max_pos);
> +    tcg_temp_free_i64(max_neg);
> +    tcg_temp_free_i64(zero);
> +    tcg_temp_free_i64(cond3);
> +    SET_USR_FIELD(USR_OVF, 1);
> +    tcg_gen_br(ret_label);

This is also redundant.

> +
> +    gen_set_label(ret_label);
> +}
> +


> diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
> index 722a115007..fc3844c8d1 100644
> --- a/target/hexagon/op_helper.c
> +++ b/target/hexagon/op_helper.c
> @@ -341,6 +341,16 @@ uint32_t HELPER(fbrev)(uint32_t addr)
>      return deposit32(addr, 0, 16, revbit16(addr));  }
> 
> +uint32_t HELPER(fbrev_32)(uint32_t addr) {
> +    return revbit32(addr);
> +}
> +
> +uint64_t HELPER(fbrev_64)(uint64_t addr) {
> +    return revbit64(addr);
> +}
> +

These are only used in a handful of instructions.  It would be better to let those use the existing generator to create helpers for the full instruction.

Here are the instructions in question:
Q6INSN(S2_brev,	"Rd32=brev(Rs32)",   ATTRIBS(A_ARCHV2), "Bit Reverse",{RdV = fBREV_4(RsV);})
Q6INSN(S2_brevp,"Rdd32=brev(Rss32)", ATTRIBS(), "Bit Reverse",{RddV = fBREV_8(RssV);})
Q6INSN(S2_ct0,  "Rd32=ct0(Rs32)",    ATTRIBS(A_ARCHV2), "Count Trailing",{RdV = fCL1_4(~fBREV_4(RsV));})
Q6INSN(S2_ct1,  "Rd32=ct1(Rs32)",    ATTRIBS(A_ARCHV2), "Count Trailing",{RdV = fCL1_4(fBREV_4(RsV));})
Q6INSN(S2_ct0p, "Rd32=ct0(Rss32)",   ATTRIBS(), "Count Trailing",{RdV = fCL1_8(~fBREV_8(RssV));})
Q6INSN(S2_ct1p, "Rd32=ct1(Rss32)",   ATTRIBS(), "Count Trailing",{RdV = fCL1_8(fBREV_8(RssV));})
Q6INSN(A4_tlbmatch,"Pd4=tlbmatch(Rss32,Rt32)",ATTRIBS(A_NOTE_LATEPRED,A_RESTRICT_LATEPRED),
"Detect if a VA/ASID matches a TLB entry",
{
    fHIDE(size4u_t TLBHI; size4u_t TLBLO; size4u_t MASK; size4u_t SIZE;)
    MASK = 0x07ffffff;
    TLBLO = fGETUWORD(0,RssV);
    TLBHI = fGETUWORD(1,RssV);
    SIZE = fMIN(6,fCL1_4(~fBREV_4(TLBLO)));
    MASK &= (0xffffffff << 2*SIZE);
    PdV = f8BITSOF(fGETBIT(31,TLBHI) && ((TLBHI & MASK) == (RtV & MASK)));
	fHIDE(MARK_LATE_PRED_WRITE(PdN))
})


^ permalink raw reply	[flat|nested] 24+ messages in thread

* RE: [PATCH v7 02/13] target/hexagon: import README for idef-parser
  2021-12-17  9:01 ` [PATCH v7 02/13] target/hexagon: import README " Anton Johansson via
@ 2021-12-22 21:05   ` Taylor Simpson
  0 siblings, 0 replies; 24+ messages in thread
From: Taylor Simpson @ 2021-12-22 21:05 UTC (permalink / raw)
  To: Anton Johansson, qemu-devel
  Cc: ale, Brian Cain, richard.henderson, babush, nizzo



> -----Original Message-----
> From: Anton Johansson <anjo@rev.ng>
> Sent: Friday, December 17, 2021 2:01 AM
> To: qemu-devel@nongnu.org
> Cc: ale@rev.ng; Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; babush@rev.ng; nizzo@rev.ng;
> richard.henderson@linaro.org
> Subject: [PATCH v7 02/13] target/hexagon: import README for idef-parser
> 
> From: Alessandro Di Federico <ale@rev.ng>
> 
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Anton Johansson <anjo@rev.ng>
> ---
>  target/hexagon/README                 |   5 +
>  target/hexagon/idef-parser/README.rst | 722
> ++++++++++++++++++++++++++
>  2 files changed, 727 insertions(+)
>  create mode 100644 target/hexagon/idef-parser/README.rst

Reviewed-by: Taylor Simpson <tsimpson@quicinc.com>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* RE: [PATCH v7 03/13] target/hexagon: make slot number an unsigned
  2021-12-17  9:01 ` [PATCH v7 03/13] target/hexagon: make slot number an unsigned Anton Johansson via
@ 2021-12-22 21:47   ` Taylor Simpson
  0 siblings, 0 replies; 24+ messages in thread
From: Taylor Simpson @ 2021-12-22 21:47 UTC (permalink / raw)
  To: Anton Johansson, qemu-devel
  Cc: ale, Brian Cain, richard.henderson, babush, nizzo



> -----Original Message-----
> From: Anton Johansson <anjo@rev.ng>
> Sent: Friday, December 17, 2021 2:01 AM
> To: qemu-devel@nongnu.org
> Cc: ale@rev.ng; Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; babush@rev.ng; nizzo@rev.ng;
> richard.henderson@linaro.org
> Subject: [PATCH v7 03/13] target/hexagon: make slot number an unsigned
> 
> WARNING: This email originated from outside of Qualcomm. Please be wary
> of any links or attachments, and do not enable macros.
> 
> From: Paolo Montesel <babush@rev.ng>
> 
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Paolo Montesel <babush@rev.ng>
> Acked-by: Richard Henderson <richard.henderson@linaro.org>

Reviewed-by: Taylor Simpson <tsimpson@quicinc.com>


^ permalink raw reply	[flat|nested] 24+ messages in thread

* RE: [PATCH v7 07/13] target/hexagon: prepare input for the idef-parser
  2021-12-17  9:01 ` [PATCH v7 07/13] target/hexagon: prepare input for the idef-parser Anton Johansson via
@ 2021-12-22 21:53   ` Taylor Simpson
  2021-12-23  1:53   ` Taylor Simpson
  1 sibling, 0 replies; 24+ messages in thread
From: Taylor Simpson @ 2021-12-22 21:53 UTC (permalink / raw)
  To: Anton Johansson, qemu-devel
  Cc: ale, Brian Cain, richard.henderson, babush, nizzo



> -----Original Message-----
> From: Anton Johansson <anjo@rev.ng>
> Sent: Friday, December 17, 2021 2:01 AM
> To: qemu-devel@nongnu.org
> Cc: ale@rev.ng; Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; babush@rev.ng; nizzo@rev.ng;
> richard.henderson@linaro.org
> Subject: [PATCH v7 07/13] target/hexagon: prepare input for the idef-parser
> 
> From: Alessandro Di Federico <ale@rev.ng>
> 
> Introduce infrastructure necessary to produce a file suitable for being parsed
> by the idef-parser.
> 
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Anton Johansson <anjo@rev.ng>
> ---
>  target/hexagon/gen_idef_parser_funcs.py | 123
> +++++++++++++++++++++
>  target/hexagon/idef-parser/macros.inc   | 140
> ++++++++++++++++++++++++
>  target/hexagon/idef-parser/prepare      |  24 ++++
>  target/hexagon/meson.build              |  16 +++
>  4 files changed, 303 insertions(+)
>  create mode 100644 target/hexagon/gen_idef_parser_funcs.py
>  create mode 100644 target/hexagon/idef-parser/macros.inc
>  create mode 100755 target/hexagon/idef-parser/prepare
> 
> diff --git a/target/hexagon/gen_idef_parser_funcs.py
> +            ## Skip other unsupported instructions
> +            if ( tag.startswith('S2_cabacdecbin') ) :
> +                continue
> +            if ( tag.startswith('A5_ACS') ) :
> +                continue

Not startswith, just
            if (tag == 'S2_cabacdecbin' or tag == 'A5_ACS'):
                continue

> +            if ( tag.startswith('Y') ) :
> +                continue
> +            if ( tag.startswith('V6_') ) :
> +                continue
> +            if ( tag.startswith('F') ) :
> +                continue
> +            if ( tag.endswith('_locked') ) :
> +                continue
> +
> +            regs = tagregs[tag]
> +            imms = tagimms[tag]
> +
> +            arguments = []
> +            if hex_common.need_ea(tag):
> +                arguments.append("EA")

It's a hack to add EA to the arguments list and then have special handling for it in the parser
                  /*
                   * The effective address EA is the only variable passed to
                   * function which needs to be "created".
                   */
                  if (c->inst.EA) {
                      gen_varid_allocate(c, &@1, c->inst.EA, 32, SIGNED);
                  }
Instead, put in a declaration inside the body - see below.


> +            for regtype,regid,toss,numregs in regs:
> +                prefix = "in " if hex_common.is_read(regid) else ""
> +
> +                is_pair = hex_common.is_pair(regid)
> +                is_single_old = (hex_common.is_single(regid)
> +                                 and hex_common.is_old_val(regtype, regid, tag))
> +                is_single_new = (hex_common.is_single(regid)
> +                                 and hex_common.is_new_val(regtype,
> + regid, tag))
> +
> +                if is_pair or is_single_old:
> +                    arguments.append("%s%s%sV" % (prefix, regtype, regid))
> +                elif is_single_new:
> +                    arguments.append("%s%s%sN" % (prefix, regtype, regid))
> +                else:
> +                    print("Bad register parse:
> + ",regtype,regid,toss,numregs)
> +
> +            for immlett,bits,immshift in imms:
> +                arguments.append(hex_common.imm_name(immlett))
> +
> +            f.write("%s(%s) {\n" % (tag, ", ".join(arguments)))

Put the declaration here inside the body.
            if hex_common.need_ea(tag):
                f.write("    size4u_t EA;\n")

> +            f.write("    %s\n" % hex_common.semdict[tag])
> +            f.write("}\n\n")
> +
> +if __name__ == "__main__":
> +    main()



> diff --git a/target/hexagon/idef-parser/prepare b/target/hexagon/idef-
> parser/prepare
> new file mode 100755
> index 0000000000..6377513dc5
> --- /dev/null
> +++ b/target/hexagon/idef-parser/prepare
> @@ -0,0 +1,24 @@
> +#!/bin/bash
> +
> +#
> +# Copyright(c) 2019-2021 rev.ng Labs Srl. 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/>.
> +#

I'm not a lawyer, but why are you marking this with LGPL?

> +
> +set -e
> +set -o pipefail
> +
> +# Run the preprocessor and drop comments cpp "$@"


> diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
> index b61243103f..236c3a3ffa 100644
> --- a/target/hexagon/meson.build
> +++ b/target/hexagon/meson.build
> @@ -21,6 +21,7 @@ hex_common_py = 'hex_common.py'
>  attribs_def = meson.current_source_dir() / 'attribs_def.h.inc'
>  gen_tcg_h = meson.current_source_dir() / 'gen_tcg.h'
>  gen_tcg_hvx_h = meson.current_source_dir() / 'gen_tcg_hvx.h'
> +idef_parser_dir = meson.current_source_dir() / 'idef-parser'
> 
>  #
>  #  Step 1
> @@ -179,4 +180,19 @@ hexagon_ss.add(files(
>      'mmvec/system_ext_mmvec.c',
>  ))
> 
> +idef_parser_input_generated = custom_target(
> +    'idef_parser_input.h.inc',
> +    output: 'idef_parser_input.h.inc',
> +    depends: [semantics_generated],
> +    depend_files: [hex_common_py],
> +    command: [python, files('gen_idef_parser_funcs.py'),
> +semantics_generated, attribs_def, '@OUTPUT@'],
> +)
> +
> +idef_parser_input_generated_prep = custom_target(
> +    'idef_parser_input.preprocessed.h.inc',
> +    output: 'idef_parser_input.preprocessed.h.inc',
> +    input: idef_parser_input_generated,
> +    command: [idef_parser_dir / 'prepare', '@INPUT@', '-I' +
> +idef_parser_dir, '-o', '@OUTPUT@'],
> +)
> +
>  target_arch += {'hexagon': hexagon_ss}
> --
> 2.33.1



^ permalink raw reply	[flat|nested] 24+ messages in thread

* RE: [PATCH v7 11/13] target/hexagon: call idef-parser functions
  2021-12-17  9:01 ` [PATCH v7 11/13] target/hexagon: call idef-parser functions Anton Johansson via
@ 2021-12-22 23:21   ` Taylor Simpson
  0 siblings, 0 replies; 24+ messages in thread
From: Taylor Simpson @ 2021-12-22 23:21 UTC (permalink / raw)
  To: Anton Johansson, qemu-devel
  Cc: ale, Brian Cain, richard.henderson, babush, nizzo



> -----Original Message-----
> From: Anton Johansson <anjo@rev.ng>
> Sent: Friday, December 17, 2021 2:01 AM
> To: qemu-devel@nongnu.org
> Cc: ale@rev.ng; Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; babush@rev.ng; nizzo@rev.ng;
> richard.henderson@linaro.org
> Subject: [PATCH v7 11/13] target/hexagon: call idef-parser functions
> 
> From: Alessandro Di Federico <ale@rev.ng>
> 
> Extend gen_tcg_funcs.py in order to emit calls to the functions emitted by
> the idef-parser, if available. An option is also added to fully disable the
> output of the idef-parser, which is useful for debugging purposes.
> 
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Anton Johansson <anjo@rev.ng>
> Reviewed-by: Taylor Simpson <tsimpson@quicinc.com>
> diff --git a/target/hexagon/gen_tcg_funcs.py
> b/target/hexagon/gen_tcg_funcs.py index 1fd9de95d5..0ea89d1ed7 100755
> --- a/target/hexagon/gen_tcg_funcs.py
> +++ b/target/hexagon/gen_tcg_funcs.py


>      hex_common.calculate_attribs()
> +    ## Whether or not idef-parser is enabled is
> +    ## determined by the number of arguments to
> +    ## this script:
> +    ##
> +    ##   5 args. -> not enabled,
> +    ##   6 args. -> idef-parser enabled.
> +    ##
> +    ## The 6:th arg. then holds a list of the successfully
> +    ## parsed instructions.
> +    if len(sys.argv) > 6:
> +        hex_common.read_idef_parser_enabled_file(sys.argv[5])
>      tagregs = hex_common.get_tagregs()
>      tagimms = hex_common.get_tagimms()
> 
> -    with open(sys.argv[5], 'w') as f:
> +    output_file = sys.argv[-1]
> +    with open(output_file, 'w') as f:
>          f.write("#ifndef HEXAGON_TCG_FUNCS_H\n")
>          f.write("#define HEXAGON_TCG_FUNCS_H\n\n")
> +        f.write("#include \"idef-generated-emitter.h.inc\"\n\n")

This should be conditional on the number of arguments to this script



^ permalink raw reply	[flat|nested] 24+ messages in thread

* RE: [PATCH v7 07/13] target/hexagon: prepare input for the idef-parser
  2021-12-17  9:01 ` [PATCH v7 07/13] target/hexagon: prepare input for the idef-parser Anton Johansson via
  2021-12-22 21:53   ` Taylor Simpson
@ 2021-12-23  1:53   ` Taylor Simpson
  1 sibling, 0 replies; 24+ messages in thread
From: Taylor Simpson @ 2021-12-23  1:53 UTC (permalink / raw)
  To: Anton Johansson, qemu-devel
  Cc: ale, Brian Cain, richard.henderson, babush, nizzo



> -----Original Message-----
> From: Anton Johansson <anjo@rev.ng>
> Sent: Friday, December 17, 2021 2:01 AM
> To: qemu-devel@nongnu.org
> Cc: ale@rev.ng; Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; babush@rev.ng; nizzo@rev.ng;
> richard.henderson@linaro.org
> Subject: [PATCH v7 07/13] target/hexagon: prepare input for the idef-parser
> 
> From: Alessandro Di Federico <ale@rev.ng>
> 
> Introduce infrastructure necessary to produce a file suitable for being parsed
> by the idef-parser.
> 
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Anton Johansson <anjo@rev.ng>


> diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
> index b61243103f..236c3a3ffa 100644
> --- a/target/hexagon/meson.build
> +++ b/target/hexagon/meson.build
> @@ -179,4 +180,19 @@ hexagon_ss.add(files(
> +
> +idef_parser_input_generated_prep = custom_target(
> +    'idef_parser_input.preprocessed.h.inc',
> +    output: 'idef_parser_input.preprocessed.h.inc',
> +    input: idef_parser_input_generated,
> +    command: [idef_parser_dir / 'prepare', '@INPUT@', '-I' +
> +idef_parser_dir, '-o', '@OUTPUT@'],

This depends on macros.inc, but that is not indicated anywhere.  So, a change to that file won't cause this file to be regenerated.


^ permalink raw reply	[flat|nested] 24+ messages in thread

* RE: [PATCH v7 12/13] target/hexagon: import additional tests
  2021-12-17  9:01 ` [PATCH v7 12/13] target/hexagon: import additional tests Anton Johansson via
@ 2021-12-23 18:16   ` Taylor Simpson
  0 siblings, 0 replies; 24+ messages in thread
From: Taylor Simpson @ 2021-12-23 18:16 UTC (permalink / raw)
  To: Anton Johansson, qemu-devel
  Cc: ale, Brian Cain, richard.henderson, babush, nizzo


> -----Original Message-----
> From: Anton Johansson <anjo@rev.ng>
> Sent: Friday, December 17, 2021 2:01 AM
> To: qemu-devel@nongnu.org
> Cc: ale@rev.ng; Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; babush@rev.ng; nizzo@rev.ng;
> richard.henderson@linaro.org
> Subject: [PATCH v7 12/13] target/hexagon: import additional tests
> 
> From: Niccolò Izzo <nizzo@rev.ng>
> 
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Niccolò Izzo <nizzo@rev.ng>
> diff --git a/tests/tcg/hexagon/Makefile.target
> b/tests/tcg/hexagon/Makefile.target
> index 8b07a28166..6f1c0830aa 100644
> --- a/tests/tcg/hexagon/Makefile.target
> +++ b/tests/tcg/hexagon/Makefile.target
> @@ -24,7 +24,7 @@ CFLAGS += -fno-unroll-loops
> HEX_SRC=$(SRC_PATH)/tests/tcg/hexagon
>  VPATH += $(HEX_SRC)
> 
> -first: $(HEX_SRC)/first.S
> +%: $(HEX_SRC)/%.S $(HEX_SRC)/crt.S
>         $(CC) -static -mv67 -nostdlib $^ -o $@
> 
>  HEX_TESTS = first
> @@ -42,4 +42,32 @@ HEX_TESTS += atomics
>  HEX_TESTS += fpstuff
>  HEX_TESTS += overflow
> 
> +HEX_TESTS += test_abs
> +HEX_TESTS += test_bitcnt
> +HEX_TESTS += test_bitsplit
> +HEX_TESTS += test_clobber

You forgot to add test_call to this list.

> +HEX_TESTS += test_cmp
> +HEX_TESTS += test_cmpy


> diff --git a/tests/tcg/hexagon/test_call.S b/tests/tcg/hexagon/test_call.S
> new file mode 100644 index 0000000000..fe59a8f006
> --- /dev/null
> +++ b/tests/tcg/hexagon/test_call.S
> @@ -0,0 +1,60 @@
> +/* Purpose: test function calls and duplex instructions.
> + * The string "Hello there, I'm a test string!" with the first letter
> +replaced
> + * with a capital L should be printed out.
> + */
> +    {
> +        call write
> +    }
> +    {
> +        jump pass
> +    }
> +    {
> +        r31:30=deallocframe(r30):raw
> +    }

The jump to pass will never return, so the deallocframe is unreachable.

> +.Lfunc_end1:
> +.Ltmp1:
> +    .size    _start, .Ltmp1-_start
> +write:
> +    {
> +        r0=##dummy_buffer
> +    }
> +    {
> +        r1=#256
> +    }

Were you intending to make a system call here?  If so, the sequence would be (see first.S for #define's)
	r6 = #SYS_write
	r0 = #FD_STDOUT
	r1 = ##dummy_buffer
	r2 = #33
	trap0(#1)

> +    {
> +        jumpr r31
> +    }


> diff --git a/tests/tcg/hexagon/test_cmpy.S
> b/tests/tcg/hexagon/test_cmpy.S new file mode 100644 index
> 0000000000..0b3dfb95de
> --- /dev/null
> +++ b/tests/tcg/hexagon/test_cmpy.S
> @@ -0,0 +1,31 @@
> +/* Purpose: test example, verify the soundness of the cmpy operation
> + *
> + *  3j+5 * 2j+4 = 22j+14
> + *
> + * the complex multiply between 0x00030005 and 0x00020004 is
> +0x000000160000000e  */
> +
> +    .text
> +    .globl _start
> +
> +_start:
> +    {
> +        call init
> +    }
> +    {
> +        r0=#196613
> +        r1=#131076
> +    }
> +    {
> +        r3:2=cmpy(r0, r1):sat
> +    }

You should also check the overflow bit in USR from the :sat.
Also, have one set of inputs that overflows and one that doesn't in order to verify the proper USR behavior.

> +    {
> +        p0 = cmp.eq(r2, #14); if (p0.new) jump:t test2
> +        jump fail
> +    }
> +
> +test2:
> +    {
> +        p0 = cmp.eq(r3, #22); if (p0.new) jump:t pass
> +        jump fail
> +    }
> diff --git a/tests/tcg/hexagon/test_dotnew.S
> b/tests/tcg/hexagon/test_dotnew.S new file mode 100644 index
> 0000000000..70886d9483
> --- /dev/null
> +++ b/tests/tcg/hexagon/test_dotnew.S
> @@ -0,0 +1,36 @@
> +/* Purpose: test the .new operator while performing memory stores. */
> +    .text
> +    .globl _start
> +
> +_start:
> +    {
> +        call init
> +    }
> +    {
> +        r0=#1
> +        memw(sp+#0)=r0.new
> +    }

You should allocframe before writing to the stack.

> diff --git a/tests/tcg/hexagon/test_jmp.S b/tests/tcg/hexagon/test_jmp.S
> new file mode 100644 index 0000000000..9bf6ea34e5
> --- /dev/null
> +++ b/tests/tcg/hexagon/test_jmp.S
> @@ -0,0 +1,25 @@
> +/* Purpose: test example, verify the soundness of the add operation */

This test is named test_jmp.S, but you are testing add?

diff --git a/tests/tcg/hexagon/test_overflow.S b/tests/tcg/hexagon/test_overflow.S
new file mode 100644
index 0000000000..9e2a235616
--- /dev/null
+++ b/tests/tcg/hexagon/test_overflow.S
@@ -0,0 +1,63 @@
+// Purpose: test example, verify the soundness of the overflow bit // 
+// a right shift with negative amount should make r0 saturate, setting 
+the // overflow bit
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#0x10000000
+        r1=#-2
+    }

You should clear bit 0 in USR before doing the asr(r0,r1):sat.

Also, do this for the other places in this review that mention USR.

+    {
+        r2=asr(r0, r1):sat
+    }
+    {
+        r4=USR
+    }
+    {
+        r5=and(r4,#1)
+    }

> diff --git a/tests/tcg/hexagon/test_packet.S
> b/tests/tcg/hexagon/test_packet.S new file mode 100644 index
> 0000000000..d26e284be9
> --- /dev/null
> +++ b/tests/tcg/hexagon/test_packet.S
> @@ -0,0 +1,26 @@
> +/* Purpose: test that writes of a register in a packet are performed
> +only after
> + * that packet has finished its execution.
> + */
> +
> +    .text
> +    .globl _start
> +
> +_start:
> +    {
> +        call init
> +    }
> +    {
> +        r2=#4
> +        r3=#6
> +    }
> +    {
> +        memw(sp+#0)=r2
> +    }

Need allocframe first

> +    {
> +        r3=memw(sp+#0)
> +        r0=add(r2,r3)
> +    }
> +    {
> +        p0 = cmp.eq(r0, #10); if (p0.new) jump:t pass
> +        jump fail
> +    }

Also check that r3 == 4


> diff --git a/tests/tcg/hexagon/test_vcmpb.S
> b/tests/tcg/hexagon/test_vcmpb.S new file mode 100644 index
> 0000000000..3c6700a63a
> --- /dev/null
> +++ b/tests/tcg/hexagon/test_vcmpb.S
> @@ -0,0 +1,32 @@
> +/* Purpose: test example, verify the soundness of the vector compare
> +bytes
> + * operation
> + *
> + * Vector word comparison between 0x1234567887654321 and
> +0x1234567800000000
> + * should result in 0x11110000

Comment is incorrect - should be Vector byte comparison.

> diff --git a/tests/tcg/hexagon/test_vcmpw.S
> b/tests/tcg/hexagon/test_vcmpw.S new file mode 100644 index
> 0000000000..112f08c92f
> --- /dev/null
> +++ b/tests/tcg/hexagon/test_vcmpw.S
> @@ -0,0 +1,29 @@
> +/* Purpose: test example, verify the soundness of the vector compare
> +words
> + * operation
> + *
> + * Vector word comparison between 0x1234567887654321 and
> +0x1234567800000000
> + * should result in 0x11110000

That's the expected result in binary, not hex.

> + */
> +
> +    .text
> +    .globl _start
> +
> +_start:
> +    {
> +        call init
> +    }
> +    {
> +        r0=#305419896
> +        r1=#-2023406815
> +    }
> +    {
> +        r2=#305419896
> +        r3=#0
> +    }
> +    {
> +        p2=vcmpw.eq(r1:0, r3:2)
> +    }
> +    {
> +        if (p2) jump:t pass

Check for the actual expected value, not just LSB.

Also, this doesn't match the comment above.  You're actually comparing
    0x8765432112345678
    0x0000000012345678
So, p2 will have 0xf, not 0xf0.

In other words, the assignments to r0/r1 and r2/r3 are swapped.

Go ahead and swap them and check that p2 gets 0xf0.
 

> diff --git a/tests/tcg/hexagon/test_vcmpy.S
> b/tests/tcg/hexagon/test_vcmpy.S new file mode 100644 index
> 0000000000..df379f9186
> --- /dev/null
> +++ b/tests/tcg/hexagon/test_vcmpy.S
> +    {
> +        r5:4=vcmpyr(r1:0, r3:2):sat
> +        r7:6=vcmpyi(r1:0, r3:2):sat
> +    }

Create some inputs that will saturate and check for overflow in USR.

> diff --git a/tests/tcg/hexagon/test_vspliceb.S
> b/tests/tcg/hexagon/test_vspliceb.S
> new file mode 100644
> index 0000000000..bae2a9c163
> --- /dev/null
> +++ b/tests/tcg/hexagon/test_vspliceb.S
> @@ -0,0 +1,33 @@
> +/* Purpose: test example, verify the soundness of the vspliceb
> +operation
> + * the operation is a binary splice of two 64bit operators
> + *
> + *  vspliceb(0xffffffffffffffff,0x0000000000000000,5) =
> +0x000000000000001f  */

The comment is incorrect.  The result is 0x000000ffffffffff.

The test is correct, though.



^ permalink raw reply related	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2021-12-23 18:19 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-17  9:01 [PATCH v7 00/13] target/hexagon: introduce idef-parser Anton Johansson via
2021-12-17  9:01 ` [PATCH v7 01/13] target/hexagon: update MAINTAINERS for idef-parser Anton Johansson via
2021-12-20 22:50   ` Taylor Simpson
2021-12-17  9:01 ` [PATCH v7 02/13] target/hexagon: import README " Anton Johansson via
2021-12-22 21:05   ` Taylor Simpson
2021-12-17  9:01 ` [PATCH v7 03/13] target/hexagon: make slot number an unsigned Anton Johansson via
2021-12-22 21:47   ` Taylor Simpson
2021-12-17  9:01 ` [PATCH v7 04/13] target/hexagon: make helper functions non-static Anton Johansson via
2021-12-17  9:01 ` [PATCH v7 05/13] target/hexagon: introduce new helper functions Anton Johansson via
2021-12-21 18:51   ` Taylor Simpson
2021-12-22 19:29   ` Taylor Simpson
2021-12-17  9:01 ` [PATCH v7 06/13] target/hexagon: expose next PC in DisasContext Anton Johansson via
2021-12-17  9:01 ` [PATCH v7 07/13] target/hexagon: prepare input for the idef-parser Anton Johansson via
2021-12-22 21:53   ` Taylor Simpson
2021-12-23  1:53   ` Taylor Simpson
2021-12-17  9:01 ` [PATCH v7 08/13] target/hexagon: import flex/bison to docker files Anton Johansson via
2021-12-17  9:01 ` [PATCH v7 09/13] target/hexagon: import lexer for idef-parser Anton Johansson via
2021-12-21 18:48   ` Taylor Simpson
2021-12-17  9:01 ` [PATCH v7 10/13] target/hexagon: import parser " Anton Johansson via
2021-12-17  9:01 ` [PATCH v7 11/13] target/hexagon: call idef-parser functions Anton Johansson via
2021-12-22 23:21   ` Taylor Simpson
2021-12-17  9:01 ` [PATCH v7 12/13] target/hexagon: import additional tests Anton Johansson via
2021-12-23 18:16   ` Taylor Simpson
2021-12-17  9:01 ` [PATCH v7 13/13] gitlab-ci: do not use qemu-project Docker registry Anton Johansson via

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.