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

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

It's the eight 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 Pseudocode
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:

* 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.

  As such the `debian-hexagon-cross` container will have to be manually
  rebuilt before merging.

* The eight patch, which introduces flex and bison as new build pre-
  requisites using `libvirt-ci` currently points to a fork, not yet
  merged upstream. This will have to be corrected before the final
  version of the patchset.

Alessandro Di Federico (4):
  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

Anton Johansson (2):
  target/hexagon: import flex/bison to docker files
  target/hexagon: import parser for idef-parser

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

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

 .gitlab-ci.d/cirrus/freebsd-12.vars           |    2 +-
 .gitlab-ci.d/cirrus/freebsd-13.vars           |    2 +-
 .gitlab-ci.d/windows.yml                      |    2 +
 .gitmodules                                   |    3 +-
 MAINTAINERS                                   |    9 +
 meson_options.txt                             |    3 +
 target/hexagon/README                         |    5 +
 target/hexagon/gen_helper_funcs.py            |   17 +-
 target/hexagon/gen_helper_protos.py           |   17 +-
 target/hexagon/gen_idef_parser_funcs.py       |  125 +
 target/hexagon/gen_tcg_funcs.py               |   41 +-
 target/hexagon/genptr.c                       |  230 +-
 target/hexagon/genptr.h                       |   44 +
 target/hexagon/hex_common.py                  |   10 +
 target/hexagon/idef-parser/README.rst         |  722 +++++
 target/hexagon/idef-parser/idef-parser.h      |  254 ++
 target/hexagon/idef-parser/idef-parser.lex    |  566 ++++
 target/hexagon/idef-parser/idef-parser.y      | 1039 +++++++
 target/hexagon/idef-parser/macros.inc         |  140 +
 target/hexagon/idef-parser/parser-helpers.c   | 2551 +++++++++++++++++
 target/hexagon/idef-parser/parser-helpers.h   |  375 +++
 target/hexagon/idef-parser/prepare            |   24 +
 target/hexagon/macros.h                       |   11 +-
 target/hexagon/meson.build                    |  138 +-
 target/hexagon/op_helper.c                    |   29 +-
 target/hexagon/op_helper.h                    |   37 +
 target/hexagon/translate.c                    |    3 +-
 target/hexagon/translate.h                    |    1 +
 tests/docker/dockerfiles/alpine.docker        |    5 +-
 tests/docker/dockerfiles/centos8.docker       |    7 +-
 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   |    1 +
 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        |    5 +-
 tests/docker/dockerfiles/opensuse-leap.docker |    7 +-
 tests/docker/dockerfiles/ubuntu1804.docker    |    7 +-
 tests/docker/dockerfiles/ubuntu2004.docker    |    7 +-
 tests/lcitool/libvirt-ci                      |    2 +-
 tests/lcitool/projects/qemu.yml               |    2 +
 tests/lcitool/refresh                         |    2 +-
 tests/tcg/hexagon/Makefile.target             |   28 +-
 tests/tcg/hexagon/crt.S                       |   14 +
 tests/tcg/hexagon/test_abs.S                  |   17 +
 tests/tcg/hexagon/test_bitcnt.S               |   40 +
 tests/tcg/hexagon/test_bitsplit.S             |   22 +
 tests/tcg/hexagon/test_call.S                 |   64 +
 tests/tcg/hexagon/test_clobber.S              |   29 +
 tests/tcg/hexagon/test_cmp.S                  |   31 +
 tests/tcg/hexagon/test_dotnew.S               |   38 +
 tests/tcg/hexagon/test_ext.S                  |   13 +
 tests/tcg/hexagon/test_fibonacci.S            |   30 +
 tests/tcg/hexagon/test_hl.S                   |   16 +
 tests/tcg/hexagon/test_hwloops.S              |   19 +
 tests/tcg/hexagon/test_jmp.S                  |   22 +
 tests/tcg/hexagon/test_lsr.S                  |   36 +
 tests/tcg/hexagon/test_mpyi.S                 |   17 +
 tests/tcg/hexagon/test_packet.S               |   29 +
 tests/tcg/hexagon/test_reorder.S              |   33 +
 tests/tcg/hexagon/test_round.S                |   29 +
 tests/tcg/hexagon/test_vavgw.S                |   31 +
 tests/tcg/hexagon/test_vcmpb.S                |   30 +
 tests/tcg/hexagon/test_vcmpw.S                |   30 +
 tests/tcg/hexagon/test_vlsrw.S                |   20 +
 tests/tcg/hexagon/test_vmaxh.S                |   35 +
 tests/tcg/hexagon/test_vminh.S                |   35 +
 tests/tcg/hexagon/test_vpmpyh.S               |   28 +
 tests/tcg/hexagon/test_vspliceb.S             |   31 +
 72 files changed, 7125 insertions(+), 107 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_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_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_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.34.1



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

* [PATCH v8 01/12] target/hexagon: update MAINTAINERS for idef-parser
  2022-02-09 17:03 [PATCH v8 00/12] target/hexagon: introduce idef-parser Anton Johansson via
@ 2022-02-09 17:03 ` Anton Johansson via
  2022-02-09 17:03 ` [PATCH v8 02/12] target/hexagon: import README " Anton Johansson via
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 23+ messages in thread
From: Anton Johansson via @ 2022-02-09 17:03 UTC (permalink / raw)
  To: qemu-devel
  Cc: ale, tsimpson, bcain, mlambert, 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>
Reviewed-by: Taylor Simpson <tsimpson@quicinc.com>
---
 MAINTAINERS | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 9814580975..1195edf040 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
-- 
2.34.1



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

* [PATCH v8 02/12] target/hexagon: import README for idef-parser
  2022-02-09 17:03 [PATCH v8 00/12] target/hexagon: introduce idef-parser Anton Johansson via
  2022-02-09 17:03 ` [PATCH v8 01/12] target/hexagon: update MAINTAINERS for idef-parser Anton Johansson via
@ 2022-02-09 17:03 ` Anton Johansson via
  2022-02-09 17:03 ` [PATCH v8 03/12] target/hexagon: make slot number an unsigned Anton Johansson via
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 23+ messages in thread
From: Anton Johansson via @ 2022-02-09 17:03 UTC (permalink / raw)
  To: qemu-devel
  Cc: ale, tsimpson, bcain, mlambert, 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: Taylor Simpson <tsimpson@quicinc.com>
---
 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.34.1



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

* [PATCH v8 03/12] target/hexagon: make slot number an unsigned
  2022-02-09 17:03 [PATCH v8 00/12] target/hexagon: introduce idef-parser Anton Johansson via
  2022-02-09 17:03 ` [PATCH v8 01/12] target/hexagon: update MAINTAINERS for idef-parser Anton Johansson via
  2022-02-09 17:03 ` [PATCH v8 02/12] target/hexagon: import README " Anton Johansson via
@ 2022-02-09 17:03 ` Anton Johansson via
  2022-02-09 17:03 ` [PATCH v8 04/12] target/hexagon: make helper functions non-static Anton Johansson via
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 23+ messages in thread
From: Anton Johansson via @ 2022-02-09 17:03 UTC (permalink / raw)
  To: qemu-devel
  Cc: ale, tsimpson, bcain, mlambert, 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>
Reviewed-by: Taylor Simpson <tsimpson@quicinc.com>
---
 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.34.1



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

* [PATCH v8 04/12] target/hexagon: make helper functions non-static
  2022-02-09 17:03 [PATCH v8 00/12] target/hexagon: introduce idef-parser Anton Johansson via
                   ` (2 preceding siblings ...)
  2022-02-09 17:03 ` [PATCH v8 03/12] target/hexagon: make slot number an unsigned Anton Johansson via
@ 2022-02-09 17:03 ` Anton Johansson via
  2022-02-09 17:03 ` [PATCH v8 05/12] target/hexagon: introduce new helper functions Anton Johansson via
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 23+ messages in thread
From: Anton Johansson via @ 2022-02-09 17:03 UTC (permalink / raw)
  To: qemu-devel
  Cc: ale, tsimpson, bcain, mlambert, 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.34.1



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

* [PATCH v8 05/12] target/hexagon: introduce new helper functions
  2022-02-09 17:03 [PATCH v8 00/12] target/hexagon: introduce idef-parser Anton Johansson via
                   ` (3 preceding siblings ...)
  2022-02-09 17:03 ` [PATCH v8 04/12] target/hexagon: make helper functions non-static Anton Johansson via
@ 2022-02-09 17:03 ` Anton Johansson via
  2022-03-21 18:28   ` Taylor Simpson
  2022-02-09 17:03 ` [PATCH v8 06/12] target/hexagon: expose next PC in DisasContext Anton Johansson via
                   ` (6 subsequent siblings)
  11 siblings, 1 reply; 23+ messages in thread
From: Anton Johansson via @ 2022-02-09 17:03 UTC (permalink / raw)
  To: qemu-devel
  Cc: ale, tsimpson, bcain, mlambert, babush, nizzo, richard.henderson

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

These helpers will be employed by the idef-parser generated code, to
correctly implement instruction semantics. "Helper" functions, in the
context of this patch, refers to functions which provide a manual TCG
implementation of 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 | 167 ++++++++++++++++++++++++++++++++++++++--
 target/hexagon/genptr.h |  16 +++-
 target/hexagon/macros.h |   9 +++
 3 files changed, 184 insertions(+), 8 deletions(-)

diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index ae798e921e..9d0c1fe2df 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,153 @@ 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)
+{
+    /*
+     * Apparently tcg_gen_deposit_i32/64 doesn't OR the input value
+     * with the previously present one, as deposit32/64 in bitops.h
+     * does. We therefore copy the old value to `old_usr` to later
+     * OR with it to replicate this behavior.
+     */
+    TCGv_i32 old_usr = tcg_temp_new_i32();
+    tcg_gen_mov_i32(old_usr, hex_new_value[HEX_REG_USR]);
+    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);
+    tcg_gen_or_i32(hex_new_value[HEX_REG_USR],
+                   old_usr,
+                   hex_new_value[HEX_REG_USR]);
+    tcg_temp_free(old_usr);
+}
+
+void gen_set_usr_fieldi(int field, int x)
+{
+    TCGv val = tcg_constant_tl(x);
+    gen_set_usr_field(field, val);
+}
+
+void gen_write_new_pc(TCGv addr)
+{
+    /* If there are multiple branches in a packet, ignore the second one */
+    TCGv zero = tcg_constant_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);
+}
+
+void gen_sat_i32(TCGv dest, TCGv source, int width)
+{
+    TCGv max_val = tcg_constant_tl((1 << (width - 1)) - 1);
+    TCGv min_val = tcg_constant_tl(-(1 << (width - 1)));
+    tcg_gen_smin_tl(dest, source, max_val);
+    tcg_gen_smax_tl(dest, dest, 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_constant_tl((1 << width) - 1);
+    TCGv zero = tcg_constant_tl(0);
+    tcg_gen_movcond_tl(TCG_COND_GTU, dest, source, max_val, max_val, source);
+    tcg_gen_movcond_tl(TCG_COND_LT, dest, source, zero, zero, dest);
+}
+
+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_constant_i64((1LL << (width - 1)) - 1LL);
+    TCGv_i64 min_val = tcg_constant_i64(-(1LL << (width - 1)));
+    tcg_gen_smin_i64(dest, source, max_val);
+    tcg_gen_smax_i64(dest, dest, min_val);
+}
+
+void gen_sat_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width)
+{
+    TCGv_i64 ovfl_64;
+    gen_sat_i64(dest, source, width);
+    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_constant_i64((1LL << width) - 1LL);
+    TCGv_i64 zero = tcg_constant_i64(0);
+    tcg_gen_movcond_i64(TCG_COND_GTU, dest, source, max_val, max_val, source);
+    tcg_gen_movcond_i64(TCG_COND_LT, dest, source, zero, zero, dest);
+}
+
+void gen_satu_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width)
+{
+    TCGv_i64 ovfl_64;
+    gen_satu_i64(dest, source, width);
+    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();
+    TCGv_i64 xor = tcg_temp_new_i64();
+    TCGv_i64 cond1 = tcg_temp_new_i64();
+    TCGv_i64 cond2 = tcg_temp_local_new_i64();
+    TCGv_i64 cond3 = tcg_temp_new_i64();
+    TCGv_i64 mask = tcg_constant_i64(0x8000000000000000ULL);
+    TCGv_i64 max_pos = tcg_constant_i64(0x7FFFFFFFFFFFFFFFLL);
+    TCGv_i64 max_neg = tcg_constant_i64(0x8000000000000000LL);
+    TCGv_i64 zero = tcg_constant_i64(0);
+    TCGLabel *no_ovfl_label = gen_new_label();
+    TCGLabel *ovfl_label = gen_new_label();
+    TCGLabel *ret_label = gen_new_label();
+
+    tcg_gen_add_i64(sum, a, b);
+    tcg_gen_xor_i64(xor, a, b);
+
+    /* if (xor & mask) */
+    tcg_gen_and_i64(cond1, xor, mask);
+    tcg_temp_free_i64(xor);
+    tcg_gen_brcondi_i64(TCG_COND_NE, cond1, 0, no_ovfl_label);
+    tcg_temp_free_i64(cond1);
+
+    /* else if ((a ^ sum) & mask) */
+    tcg_gen_xor_i64(cond2, a, sum);
+    tcg_gen_and_i64(cond2, cond2, mask);
+    tcg_gen_brcondi_i64(TCG_COND_NE, cond2, 0, ovfl_label);
+    tcg_temp_free_i64(cond2);
+    /* fallthrough to no_ovfl_label branch */
+
+    /* if branch */
+    gen_set_label(no_ovfl_label);
+    tcg_gen_mov_i64(ret, sum);
+    tcg_gen_br(ret_label);
+
+    /* else if branch */
+    gen_set_label(ovfl_label);
+    tcg_gen_and_i64(cond3, sum, mask);
+    tcg_temp_free_i64(mask);
+    tcg_temp_free_i64(sum);
+    tcg_gen_movcond_i64(TCG_COND_NE, ret, cond3, zero, max_pos, max_neg);
+    tcg_temp_free_i64(cond3);
+    SET_USR_FIELD(USR_OVF, 1);
+
+    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/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)
 
-- 
2.34.1



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

* [PATCH v8 06/12] target/hexagon: expose next PC in DisasContext
  2022-02-09 17:03 [PATCH v8 00/12] target/hexagon: introduce idef-parser Anton Johansson via
                   ` (4 preceding siblings ...)
  2022-02-09 17:03 ` [PATCH v8 05/12] target/hexagon: introduce new helper functions Anton Johansson via
@ 2022-02-09 17:03 ` Anton Johansson via
  2022-02-09 17:03 ` [PATCH v8 07/12] target/hexagon: prepare input for the idef-parser Anton Johansson via
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 23+ messages in thread
From: Anton Johansson via @ 2022-02-09 17:03 UTC (permalink / raw)
  To: qemu-devel
  Cc: ale, tsimpson, bcain, mlambert, 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.34.1



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

* [PATCH v8 07/12] target/hexagon: prepare input for the idef-parser
  2022-02-09 17:03 [PATCH v8 00/12] target/hexagon: introduce idef-parser Anton Johansson via
                   ` (5 preceding siblings ...)
  2022-02-09 17:03 ` [PATCH v8 06/12] target/hexagon: expose next PC in DisasContext Anton Johansson via
@ 2022-02-09 17:03 ` Anton Johansson via
  2022-03-21 18:33   ` Taylor Simpson
  2022-02-09 17:03 ` [PATCH v8 08/12] target/hexagon: import flex/bison to docker files Anton Johansson via
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 23+ messages in thread
From: Anton Johansson via @ 2022-02-09 17:03 UTC (permalink / raw)
  To: qemu-devel
  Cc: ale, tsimpson, bcain, mlambert, 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 | 125 +++++++++++++++++++++
 target/hexagon/idef-parser/macros.inc   | 140 ++++++++++++++++++++++++
 target/hexagon/idef-parser/prepare      |  24 ++++
 target/hexagon/meson.build              |  17 +++
 4 files changed, 306 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..5a802d08aa
--- /dev/null
+++ b/target/hexagon/gen_idef_parser_funcs.py
@@ -0,0 +1,125 @@
+#!/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 instructions using bit reverse
+            if ( tag in {'S2_brev', 'S2_brevp', 'S2_ct0', 'S2_ct1',
+                         'S2_ct0p', 'S2_ct1p', 'A4_tlbmatch'} ) :
+                continue
+            ## Skip other unsupported instructions
+            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 = []
+            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("    ");
+            if hex_common.need_ea(tag):
+                f.write("size4u_t EA; ");
+            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..b74a8f6f22
--- /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 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/>.
+ */
+
+/* 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..72d6fcbd21
--- /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 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/>.
+#
+
+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..5945098cc4 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,20 @@ 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@'],
+)
+
+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,
+    depend_files: [idef_parser_dir / 'macros.inc'],
+    command: [idef_parser_dir / 'prepare', '@INPUT@', '-I' + idef_parser_dir, '-o', '@OUTPUT@'],
+)
+
 target_arch += {'hexagon': hexagon_ss}
-- 
2.34.1



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

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

Note: In this version of the patchset `tests/lcitool/libvirt-ci` points
to a fork of libvirt-ci that includes flex/bison. This fork has not been
merged upstream yet, and can be found at

  https://gitlab.com/AntonJohansson/libvirt-ci/-/tree/mapping-flex-bison

This patch will have to be modified to point to the upstreamed version
before pulling.

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/cirrus/freebsd-12.vars                  | 2 +-
 .gitlab-ci.d/cirrus/freebsd-13.vars                  | 2 +-
 .gitlab-ci.d/windows.yml                             | 2 ++
 .gitmodules                                          | 3 ++-
 tests/docker/dockerfiles/alpine.docker               | 5 ++++-
 tests/docker/dockerfiles/centos8.docker              | 7 ++++---
 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 | 1 +
 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               | 5 +++--
 tests/docker/dockerfiles/opensuse-leap.docker        | 7 ++++---
 tests/docker/dockerfiles/ubuntu1804.docker           | 7 ++++---
 tests/docker/dockerfiles/ubuntu2004.docker           | 7 ++++---
 tests/lcitool/libvirt-ci                             | 2 +-
 tests/lcitool/projects/qemu.yml                      | 2 ++
 tests/lcitool/refresh                                | 2 +-
 21 files changed, 54 insertions(+), 20 deletions(-)

diff --git a/.gitlab-ci.d/cirrus/freebsd-12.vars b/.gitlab-ci.d/cirrus/freebsd-12.vars
index 9c52266811..f2385c1b4a 100644
--- a/.gitlab-ci.d/cirrus/freebsd-12.vars
+++ b/.gitlab-ci.d/cirrus/freebsd-12.vars
@@ -11,6 +11,6 @@ MAKE='/usr/local/bin/gmake'
 NINJA='/usr/local/bin/ninja'
 PACKAGING_COMMAND='pkg'
 PIP3='/usr/local/bin/pip-3.8'
-PKGS='alsa-lib bash bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage ctags curl cyrus-sasl dbus diffutils dtc gettext git glib gmake gnutls gsed gtk3 libepoxy libffi libgcrypt libjpeg-turbo libnfs libspice-server libssh libtasn1 libxml2 llvm lttng-ust lzo2 meson ncurses nettle ninja opencv p5-Test-Harness perl5 pixman pkgconf png py38-numpy py38-pillow py38-pip py38-sphinx py38-sphinx_rtd_theme py38-virtualenv py38-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd'
+PKGS='alsa-lib bash bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage ctags curl cyrus-sasl dbus diffutils dtc gettext git glib gmake gnutls gsed gtk3 libepoxy libffi libgcrypt libjpeg-turbo libnfs libspice-server libssh libtasn1 libxml2 llvm lzo2 meson ncurses nettle ninja opencv p5-Test-Harness perl5 pixman pkgconf png py38-numpy py38-pillow py38-pip py38-sphinx py38-sphinx_rtd_theme py38-virtualenv py38-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd'
 PYPI_PKGS=''
 PYTHON='/usr/local/bin/python3'
diff --git a/.gitlab-ci.d/cirrus/freebsd-13.vars b/.gitlab-ci.d/cirrus/freebsd-13.vars
index 7b44dba324..43904b65fa 100644
--- a/.gitlab-ci.d/cirrus/freebsd-13.vars
+++ b/.gitlab-ci.d/cirrus/freebsd-13.vars
@@ -11,6 +11,6 @@ MAKE='/usr/local/bin/gmake'
 NINJA='/usr/local/bin/ninja'
 PACKAGING_COMMAND='pkg'
 PIP3='/usr/local/bin/pip-3.8'
-PKGS='alsa-lib bash bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage ctags curl cyrus-sasl dbus diffutils dtc gettext git glib gmake gnutls gsed gtk3 libepoxy libffi libgcrypt libjpeg-turbo libnfs libspice-server libssh libtasn1 libxml2 llvm lttng-ust lzo2 meson ncurses nettle ninja opencv p5-Test-Harness perl5 pixman pkgconf png py38-numpy py38-pillow py38-pip py38-sphinx py38-sphinx_rtd_theme py38-virtualenv py38-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd'
+PKGS='alsa-lib bash bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage ctags curl cyrus-sasl dbus diffutils dtc gettext git glib gmake gnutls gsed gtk3 libepoxy libffi libgcrypt libjpeg-turbo libnfs libspice-server libssh libtasn1 libxml2 llvm lzo2 meson ncurses nettle ninja opencv p5-Test-Harness perl5 pixman pkgconf png py38-numpy py38-pillow py38-pip py38-sphinx py38-sphinx_rtd_theme py38-virtualenv py38-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd'
 PYPI_PKGS=''
 PYTHON='/usr/local/bin/python3'
diff --git a/.gitlab-ci.d/windows.yml b/.gitlab-ci.d/windows.yml
index 62dd9ed832..4ae49376cf 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/.gitmodules b/.gitmodules
index 84425d87e2..666e17907f 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -66,4 +66,5 @@
 	url = https://gitlab.com/qemu-project/vbootrom.git
 [submodule "tests/lcitool/libvirt-ci"]
 	path = tests/lcitool/libvirt-ci
-	url = http://gitlab.com/libvirt/libvirt-ci
+	url = http://gitlab.com/AntonJohansson/libvirt-ci
+        branch = mapping-flex-bison
diff --git a/tests/docker/dockerfiles/alpine.docker b/tests/docker/dockerfiles/alpine.docker
index eb2251c81c..d4f0279318 100644
--- a/tests/docker/dockerfiles/alpine.docker
+++ b/tests/docker/dockerfiles/alpine.docker
@@ -1,6 +1,6 @@
 # THIS FILE WAS AUTO-GENERATED
 #
-#  $ lcitool dockerfile alpine-edge qemu
+#  $ lcitool dockerfile --layers all alpine-edge qemu
 #
 # https://gitlab.com/libvirt/libvirt-ci
 
@@ -13,6 +13,7 @@ RUN apk update && \
         attr-dev \
         bash \
         bc \
+        bison \
         bzip2 \
         bzip2-dev \
         ca-certificates \
@@ -29,6 +30,7 @@ RUN apk update && \
         dtc-dev \
         eudev-dev \
         findutils \
+        flex \
         fuse3-dev \
         g++ \
         gcc \
@@ -109,6 +111,7 @@ RUN apk update && \
         zlib-dev \
         zlib-static \
         zstd-dev && \
+    apk list | sort > /packages.txt && \
     mkdir -p /usr/libexec/ccache-wrappers && \
     ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/c++ && \
     ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \
diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker
index cbb909d02b..66d1f09a86 100644
--- a/tests/docker/dockerfiles/centos8.docker
+++ b/tests/docker/dockerfiles/centos8.docker
@@ -1,10 +1,10 @@
 # THIS FILE WAS AUTO-GENERATED
 #
-#  $ lcitool dockerfile centos-8 qemu
+#  $ lcitool dockerfile --layers all almalinux-8 qemu
 #
 # https://gitlab.com/libvirt/libvirt-ci
 
-FROM docker.io/library/centos:8
+FROM docker.io/library/almalinux:8
 
 RUN dnf update -y && \
     dnf install 'dnf-command(config-manager)' -y && \
@@ -16,6 +16,7 @@ RUN dnf update -y && \
         alsa-lib-devel \
         bash \
         bc \
+        bison \
         brlapi-devel \
         bzip2 \
         bzip2-devel \
@@ -30,6 +31,7 @@ RUN dnf update -y && \
         device-mapper-multipath-devel \
         diffutils \
         findutils \
+        flex \
         fuse3-devel \
         gcc \
         gcc-c++ \
@@ -69,7 +71,6 @@ RUN dnf update -y && \
         libssh-devel \
         libtasn1-devel \
         libubsan \
-        libudev-devel \
         liburing-devel \
         libusbx-devel \
         libxml2-devel \
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 3f6b55562c..9191aafc7f 100644
--- a/tests/docker/dockerfiles/debian-tricore-cross.docker
+++ b/tests/docker/dockerfiles/debian-tricore-cross.docker
@@ -20,6 +20,7 @@ RUN apt update && \
        bzip2 \
        ca-certificates \
        ccache \
+       flex \
        g++ \
        gcc \
        git \
diff --git a/tests/docker/dockerfiles/debian10.docker b/tests/docker/dockerfiles/debian10.docker
index b414af1b9f..23285e7aa4 100644
--- a/tests/docker/dockerfiles/debian10.docker
+++ b/tests/docker/dockerfiles/debian10.docker
@@ -18,15 +18,18 @@ RUN apt update && \
     DEBIAN_FRONTEND=noninteractive eatmydata \
     apt install -y --no-install-recommends \
         bc \
+        bison \
         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 d80e66c651..ed08392657 100644
--- a/tests/docker/dockerfiles/fedora-win32-cross.docker
+++ b/tests/docker/dockerfiles/fedora-win32-cross.docker
@@ -3,13 +3,16 @@ FROM registry.fedoraproject.org/fedora:33
 # Please keep this list sorted alphabetically
 ENV PACKAGES \
     bc \
+    bison \
     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 2b12b94ccf..bc31c66aef 100644
--- a/tests/docker/dockerfiles/fedora-win64-cross.docker
+++ b/tests/docker/dockerfiles/fedora-win64-cross.docker
@@ -3,12 +3,15 @@ FROM registry.fedoraproject.org/fedora:33
 # Please keep this list sorted alphabetically
 ENV PACKAGES \
     bc \
+    bison \
     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 60207f3da3..e2ba993e6b 100644
--- a/tests/docker/dockerfiles/fedora.docker
+++ b/tests/docker/dockerfiles/fedora.docker
@@ -1,6 +1,6 @@
 # THIS FILE WAS AUTO-GENERATED
 #
-#  $ lcitool dockerfile fedora-35 qemu
+#  $ lcitool dockerfile --layers all fedora-35 qemu
 #
 # https://gitlab.com/libvirt/libvirt-ci
 
@@ -23,6 +23,7 @@ exec "$@"' > /usr/bin/nosync && \
         alsa-lib-devel \
         bash \
         bc \
+        bison \
         brlapi-devel \
         bzip2 \
         bzip2-devel \
@@ -37,6 +38,7 @@ exec "$@"' > /usr/bin/nosync && \
         device-mapper-multipath-devel \
         diffutils \
         findutils \
+        flex \
         fuse3-devel \
         gcc \
         gcc-c++ \
@@ -77,7 +79,6 @@ exec "$@"' > /usr/bin/nosync && \
         libssh-devel \
         libtasn1-devel \
         libubsan \
-        libudev-devel \
         liburing-devel \
         libusbx-devel \
         libxml2-devel \
diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker
index f57d8cfb29..146cd9f3e3 100644
--- a/tests/docker/dockerfiles/opensuse-leap.docker
+++ b/tests/docker/dockerfiles/opensuse-leap.docker
@@ -1,6 +1,6 @@
 # THIS FILE WAS AUTO-GENERATED
 #
-#  $ lcitool dockerfile opensuse-leap-152 qemu
+#  $ lcitool dockerfile --layers all opensuse-leap-152 qemu
 #
 # https://gitlab.com/libvirt/libvirt-ci
 
@@ -12,6 +12,7 @@ RUN zypper update -y && \
            alsa-lib-devel \
            bash \
            bc \
+           bison \
            brlapi-devel \
            bzip2 \
            ca-certificates \
@@ -22,6 +23,7 @@ RUN zypper update -y && \
            dbus-1 \
            diffutils \
            findutils \
+           flex \
            fuse3-devel \
            gcc \
            gcc-c++ \
@@ -128,8 +130,7 @@ RUN zypper update -y && \
     ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++ && \
     ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc
 
-RUN pip3 install \
-         meson==0.56.0
+RUN pip3 install meson==0.56.0
 
 ENV LANG "en_US.UTF-8"
 ENV MAKE "/usr/bin/make"
diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker
index 0ffa3c4d4b..0a5900f203 100644
--- a/tests/docker/dockerfiles/ubuntu1804.docker
+++ b/tests/docker/dockerfiles/ubuntu1804.docker
@@ -1,6 +1,6 @@
 # THIS FILE WAS AUTO-GENERATED
 #
-#  $ lcitool dockerfile ubuntu-1804 qemu
+#  $ lcitool dockerfile --layers all ubuntu-1804 qemu
 #
 # https://gitlab.com/libvirt/libvirt-ci
 
@@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
     eatmydata apt-get install --no-install-recommends -y \
             bash \
             bc \
+            bison \
             bsdmainutils \
             bzip2 \
             ca-certificates \
@@ -23,6 +24,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
             diffutils \
             exuberant-ctags \
             findutils \
+            flex \
             g++ \
             gcc \
             gcovr \
@@ -134,8 +136,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
     ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++ && \
     ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc
 
-RUN pip3 install \
-         meson==0.56.0
+RUN pip3 install meson==0.56.0
 
 ENV LANG "en_US.UTF-8"
 ENV MAKE "/usr/bin/make"
diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker
index 4e562dfdcd..75b5eee895 100644
--- a/tests/docker/dockerfiles/ubuntu2004.docker
+++ b/tests/docker/dockerfiles/ubuntu2004.docker
@@ -1,6 +1,6 @@
 # THIS FILE WAS AUTO-GENERATED
 #
-#  $ lcitool dockerfile ubuntu-2004 qemu
+#  $ lcitool dockerfile --layers all ubuntu-2004 qemu
 #
 # https://gitlab.com/libvirt/libvirt-ci
 
@@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
     eatmydata apt-get install --no-install-recommends -y \
             bash \
             bc \
+            bison \
             bsdmainutils \
             bzip2 \
             ca-certificates \
@@ -23,6 +24,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
             diffutils \
             exuberant-ctags \
             findutils \
+            flex \
             g++ \
             gcc \
             gcovr \
@@ -136,8 +138,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
     ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++ && \
     ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc
 
-RUN pip3 install \
-         meson==0.56.0
+RUN pip3 install meson==0.56.0
 
 ENV LANG "en_US.UTF-8"
 ENV MAKE "/usr/bin/make"
diff --git a/tests/lcitool/libvirt-ci b/tests/lcitool/libvirt-ci
index 29cec2153b..22a88ac731 160000
--- a/tests/lcitool/libvirt-ci
+++ b/tests/lcitool/libvirt-ci
@@ -1 +1 @@
-Subproject commit 29cec2153b9a4dbb2e66f1cbc9866a4eff519cfd
+Subproject commit 22a88ac73197e6c6b8a319eb92cdbd2ac06eb44a
diff --git a/tests/lcitool/projects/qemu.yml b/tests/lcitool/projects/qemu.yml
index ed5ab1407a..f464665990 100644
--- a/tests/lcitool/projects/qemu.yml
+++ b/tests/lcitool/projects/qemu.yml
@@ -3,6 +3,7 @@ packages:
  - alsa
  - bash
  - bc
+ - bison
  - brlapi
  - bzip2
  - bzip2-libs
@@ -18,6 +19,7 @@ packages:
  - diffutils
  - dtrace
  - findutils
+ - flex
  - fuse3
  - g++
  - gcc
diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh
index 033120e223..4d7e6e8383 100755
--- a/tests/lcitool/refresh
+++ b/tests/lcitool/refresh
@@ -77,7 +77,7 @@ ubuntu2004_tsanhack = [
 ]
 
 try:
-   generate_dockerfile("centos8", "centos-8")
+   generate_dockerfile("centos8", "almalinux-8")
    generate_dockerfile("fedora", "fedora-35")
    generate_dockerfile("ubuntu1804", "ubuntu-1804",
                        trailer="".join(ubuntu1804_skipssh))
-- 
2.34.1



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

* [PATCH v8 09/12] target/hexagon: import lexer for idef-parser
  2022-02-09 17:03 [PATCH v8 00/12] target/hexagon: introduce idef-parser Anton Johansson via
                   ` (7 preceding siblings ...)
  2022-02-09 17:03 ` [PATCH v8 08/12] target/hexagon: import flex/bison to docker files Anton Johansson via
@ 2022-02-09 17:03 ` Anton Johansson via
  2022-03-21 18:40   ` Taylor Simpson
  2022-02-09 17:03 ` [PATCH v8 10/12] target/hexagon: import parser " Anton Johansson via
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 23+ messages in thread
From: Anton Johansson via @ 2022-02-09 17:03 UTC (permalink / raw)
  To: qemu-devel
  Cc: ale, tsimpson, bcain, mlambert, 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   | 254 +++++++++
 target/hexagon/idef-parser/idef-parser.lex | 566 +++++++++++++++++++++
 target/hexagon/meson.build                 |   4 +
 3 files changed, 824 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..106eb3ec98
--- /dev/null
+++ b/target/hexagon/idef-parser/idef-parser.h
@@ -0,0 +1,254 @@
+/*
+ *  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/>.
+ */
+
+#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 {
+    unsigned 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, used when type is VARIABLE   */
+        uint64_t value;         /**< Immediate value, used when type is VALUE */
+        uint64_t index;         /**< Index, used when type is QEMU_TMP        */
+    };
+    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;          /**< Should the sat. op. set overflow?        */
+    HexSignedness signedness;   /**< Signedness of the sat. op.               */
+} HexSat;
+
+/**
+ * Semantic record of the CAST token, identifying the cast operator
+ */
+typedef struct HexCast {
+    unsigned 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 {
+    unsigned bit_width;         /**< Bit width of the extract operator        */
+    unsigned 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 {
+    unsigned first_bit_width;        /**< Bit width of 1st operand of fMPY    */
+    unsigned second_bit_width;       /**< Bit width of 2nd operand of fMPY    */
+    HexSignedness first_signedness;  /**< Signedness of 1st operand of fMPY   */
+    HexSignedness second_signedness; /**< Signedness of 2nd operand of fMPY   */
+} 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            */
+    unsigned tmp_count;         /**< Index of the last declared TCGv temp     */
+    unsigned qemu_tmp_count;    /**< Index of the last declared int temp      */
+    unsigned if_count;          /**< Index of the last declared if label      */
+    unsigned error_count;       /**< Number of generated errors               */
+    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    */
+    unsigned total_insn;        /**< Number of instructions in input file     */
+    unsigned 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..7cdfb22d80
--- /dev/null
+++ b/target/hexagon/idef-parser/idef-parser.lex
@@ -0,0 +1,566 @@
+%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 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 <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"                  { 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 = true;
+                           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_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 5945098cc4..63f13e1d21 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -196,4 +196,8 @@ preprocessed_idef_parser_input_generated = 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.34.1



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

* [PATCH v8 10/12] target/hexagon: import parser for idef-parser
  2022-02-09 17:03 [PATCH v8 00/12] target/hexagon: introduce idef-parser Anton Johansson via
                   ` (8 preceding siblings ...)
  2022-02-09 17:03 ` [PATCH v8 09/12] target/hexagon: import lexer for idef-parser Anton Johansson via
@ 2022-02-09 17:03 ` Anton Johansson via
  2022-04-11 15:20   ` Taylor Simpson
  2022-02-09 17:03 ` [PATCH v8 11/12] target/hexagon: call idef-parser functions Anton Johansson via
  2022-02-09 17:03 ` [PATCH v8 12/12] target/hexagon: import additional tests Anton Johansson via
  11 siblings, 1 reply; 23+ messages in thread
From: Anton Johansson via @ 2022-02-09 17:03 UTC (permalink / raw)
  To: qemu-devel
  Cc: ale, tsimpson, bcain, mlambert, 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    | 1039 ++++++++
 target/hexagon/idef-parser/parser-helpers.c | 2551 +++++++++++++++++++
 target/hexagon/idef-parser/parser-helpers.h |  375 +++
 target/hexagon/meson.build                  |   25 +
 4 files changed, 3990 insertions(+)
 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..b6489be9fb
--- /dev/null
+++ b/target/hexagon/idef-parser/idef-parser.y
@@ -0,0 +1,1039 @@
+%{
+/*
+ *  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/>.
+ */
+
+#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 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");
+              }
+              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);
+                }
+              ;
+
+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);
+         }
+       | 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..0ac18ca150
--- /dev/null
+++ b/target/hexagon/idef-parser/parser-helpers.c
@@ -0,0 +1,2551 @@
+/*
+ *  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/>.
+ */
+
+#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 (unsigned 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 (unsigned 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)
+{
+    Ternary *ternary = NULL;
+    HexValue cond;
+
+    yyassert(c, locp, is_inside_ternary(c), "unexisting condition");
+    ternary = &g_array_index(c->ternary, Ternary, 0);
+    cond = ternary->cond;
+
+    if (ternary->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;
+}
+
+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_constant(Context *c,
+                             YYLTYPE *locp,
+                             const char *value,
+                             unsigned bit_width,
+                             HexSignedness signedness)
+{
+    HexValue rvalue;
+    assert(bit_width == 32 || bit_width == 64);
+    memset(&rvalue, 0, sizeof(HexValue));
+    rvalue.type = TEMP;
+    rvalue.bit_width = bit_width;
+    rvalue.signedness = signedness;
+    rvalue.is_dotnew = false;
+    rvalue.is_manual = true;
+    rvalue.tmp.index = c->inst.tmp_count;
+    OUT(c, locp, "TCGv_i", &bit_width, " tmp_", &c->inst.tmp_count,
+        " = tcg_constant_i", &bit_width, "(", value, ");\n");
+    c->inst.tmp_count++;
+    return rvalue;
+}
+
+/* Temporary values creation */
+HexValue gen_tmp(Context *c,
+                 YYLTYPE *locp,
+                 unsigned bit_width,
+                 HexSignedness signedness)
+{
+    HexValue rvalue;
+    assert(bit_width == 32 || bit_width == 64);
+    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_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;
+    assert(bit_width == 32 || bit_width == 64);
+    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 HexValue gen_tmp_value_from_imm(Context *c,
+                                       YYLTYPE *locp,
+                                       HexValue *value)
+{
+    HexValue rvalue;
+    assert(value->type == IMMEDIATE);
+    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;
+    assert(bit_width == 32 || bit_width == 64);
+    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;
+    assert(bit_width == 32 || bit_width == 64);
+    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)
+{
+    assert_signedness(c, locp, rvalue->signedness);
+    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);
+        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");
+}
+
+/* Handle signedness, if both unsigned -> result is unsigned, else signed */
+static inline HexSignedness bin_op_signedness(Context *c, YYLTYPE *locp,
+                                              HexSignedness sign1,
+                                              HexSignedness sign2)
+{
+    assert_signedness(c, locp, sign1);
+    assert_signedness(c, locp, sign2);
+    return (sign1 == UNSIGNED && sign2 == UNSIGNED) ? UNSIGNED : SIGNED;
+}
+
+void gen_varid_allocate(Context *c,
+                        YYLTYPE *locp,
+                        HexValue *varid,
+                        unsigned bit_width,
+                        HexSignedness signedness)
+{
+    const char *bit_suffix = (bit_width == 64) ? "i64" : "i32";
+    bool found = try_find_variable(c, locp, NULL, varid);
+    Var new_var;
+
+    memset(&new_var, 0, sizeof(Var));
+
+    yyassert(c, locp, !found, "Redeclaration of variables not allowed!");
+    assert_signedness(c, locp, signedness);
+
+    /* `varid` only carries name information */
+    new_var.name = varid->var.name;
+    new_var.bit_width = bit_width;
+    new_var.signedness = signedness;
+
+    EMIT_HEAD(c, "TCGv_%s %s", bit_suffix, varid->var.name->str);
+    EMIT_HEAD(c, " = tcg_temp_local_new_%s();\n", bit_suffix);
+    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;
+    const char *bit_suffix = op_is64bit ? "i64" : "i32";
+    unsigned bit_width = (op_is64bit) ? 64 : 32;
+    HexValue res = gen_tmp(c, locp, bit_width, UNSIGNED);
+
+    /* 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);
+    }
+
+    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 = bin_op_signedness(c, locp,
+                                                     op1->signedness,
+                                                     op2->signedness);
+        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 = bin_op_signedness(c, locp,
+                                                     op1->signedness,
+                                                     op2->signedness);
+        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 = bin_op_signedness(c, locp,
+                                                     op1->signedness,
+                                                     op2->signedness);
+        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 zero = gen_constant(c, locp, "0", bit_width, UNSIGNED);
+        HexValue edge = gen_imm_value(c, locp, bit_width, bit_width, UNSIGNED);
+        edge = rvalue_materialize(c, locp, &edge);
+        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, &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 = bin_op_signedness(c, locp,
+                                                     op1->signedness,
+                                                     op2->signedness);
+        gen_c_int_type(c, locp, bit_width, signedness);
+        OUT(c, locp, " ", res,
+            " = ", op1, " >> ", op2, ";\n");
+    } break;
+    case REG_IMM: {
+        HexSignedness signedness = bin_op_signedness(c, locp,
+                                                     op1->signedness,
+                                                     op2->signedness);
+        OUT(c, locp, "{\n");
+        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 */
+        const char *offset = op_is64bit ? "63" : "31";
+        HexValue tmp = gen_tmp(c, locp, bit_width, SIGNED);
+        HexValue zero = gen_constant(c, locp, "0", bit_width, SIGNED);
+        HexValue edge = gen_imm_value(c, locp, bit_width, bit_width, UNSIGNED);
+
+        edge = rvalue_materialize(c, locp, &edge);
+        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_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, &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 = bin_op_signedness(c, locp,
+                                                     op1->signedness,
+                                                     op2->signedness);
+        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 zero = gen_constant(c, locp, "0", bit_width, UNSIGNED);
+        HexValue edge = gen_imm_value(c, locp, bit_width, bit_width, UNSIGNED);
+        edge = rvalue_materialize(c, locp, &edge);
+        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, &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 tmp1, tmp2;
+    HexValue zero = gen_constant(c, locp, "0", 32, UNSIGNED);
+    memset(&tmp1, 0, sizeof(HexValue));
+    memset(&tmp2, 0, sizeof(HexValue));
+    switch (op_types) {
+    case IMM_IMM: {
+        HexSignedness signedness = bin_op_signedness(c, locp,
+                                                     op1->signedness,
+                                                     op2->signedness);
+        gen_c_int_type(c, locp, bit_width, signedness);
+        OUT(c, locp, " ",
+            res, " = ", op1, " && ", op2, ";\n");
+    } break;
+    case IMM_REG:
+        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:
+        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:
+        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)
+{
+    const char *mm;
+    HexValue op1_m = *op1;
+    HexValue op2_m = *op2;
+    bool is_unsigned;
+
+    assert_signedness(c, locp, res->signedness);
+    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 = bin_op_signedness(c, locp,
+                                                     op1->signedness,
+                                                     op2->signedness);
+        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 = bin_op_signedness(c, locp,
+                                                     op1->signedness,
+                                                     op2->signedness);
+        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;
+    enum OpTypes op_types;
+    bool op_is64bit;
+    HexSignedness signedness;
+    unsigned bit_width;
+    const char *bit_suffix;
+    HexValue res;
+
+    memset(&res, 0, sizeof(HexValue));
+
+    /*
+     * 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);
+    }
+
+    op_types = (op1_m.type != IMMEDIATE) << 1
+               | (op2_m.type != IMMEDIATE);
+    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;
+    }
+
+    bit_width = (op_is64bit) ? 64 : 32;
+    bit_suffix = op_is64bit ? "i64" : "i32";
+
+    /* 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);
+    }
+
+    signedness = bin_op_signedness(c, locp, op1_m.signedness, op2_m.signedness);
+    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)
+{
+    assert_signedness(c, locp, src->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)
+{
+    /*
+     * 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.
+     */
+    const char *sign_prefix;
+    bool need_guarding;
+
+    assert_signedness(c, locp, signedness);
+    assert(dst_width == 64 || dst_width == 32);
+    assert(src_width->type == IMMEDIATE);
+
+    sign_prefix = (signedness == UNSIGNED) ? "" : "s";
+    need_guarding = (src_width->imm.type != VALUE);
+
+    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.
+         */
+        return gen_imm_value(c, locp, 0, dst_width, signedness);
+    }
+
+    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)
+{
+    HexValue src_width_m = rvalue_materialize(c, locp, src_width);
+    HexValue zero = gen_constant(c, locp, "0", dst_width, UNSIGNED);
+    HexValue shift = gen_tmp(c, locp, dst_width, UNSIGNED);
+    HexValue res;
+
+    assert_signedness(c, locp, signedness);
+    assert(dst_width == 64 || dst_width == 32);
+    assert(src_width->type != IMMEDIATE);
+
+    res = gen_tmp(c, locp, dst_width, signedness);
+
+    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);
+
+    return res;
+}
+
+HexValue gen_extend_op(Context *c,
+                       YYLTYPE *locp,
+                       HexValue *src_width,
+                       unsigned dst_width,
+                       HexValue *value,
+                       HexSignedness signedness)
+{
+    unsigned bit_width = (dst_width = 64) ? 64 : 32;
+    HexValue value_m = *value;
+    HexValue src_width_m = *src_width;
+
+    assert_signedness(c, locp, signedness);
+
+    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);
+    }
+
+    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 begin_m = *begin;
+    HexValue value_m = *value;
+    HexValue width_orig = *width;
+    HexValue width_m = width_orig;
+    const char *mask_str = (dst->bit_width == 32)
+        ? "0xffffffffUL"
+        : "0xffffffffffffffffUL";
+    HexValue mask = gen_constant(c, locp, mask_str, dst->bit_width,
+                                 UNSIGNED);
+    const char *dst_width_str = (dst->bit_width == 32) ? "32" : "64";
+    HexValue k64 = gen_constant(c, locp, dst_width_str, dst->bit_width,
+                                UNSIGNED);
+    HexValue res;
+    HexValue zero;
+
+    width_orig.is_manual = true;
+
+    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);
+    }
+
+    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);
+    }
+    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);
+
+    /*
+     * mask = 0xffffffffffffffff >> (64 - width)
+     * mask = mask << begin
+     * value = (value << begin) & mask
+     * res = dst & ~mask
+     * res = res | value
+     * dst = (width != 0) ? res : dst
+     */
+    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;
+    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 */
+    zero = gen_constant(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, width);
+    gen_rvalue_free(c, locp, &res);
+}
+
+
+void gen_rdeposit_op(Context *c,
+                     YYLTYPE *locp,
+                     HexValue *dst,
+                     HexValue *value,
+                     HexValue *begin,
+                     HexValue *width)
+{
+    HexValue dst_m = *dst;
+    dst_m.is_manual = true;
+
+    assert(dst->bit_width >= value->bit_width);
+    assert(begin->type == IMMEDIATE && begin->imm.type == VALUE);
+    assert(dst->type == REGISTER_ARG);
+
+    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)
+{
+    HexValue value_m = *value;
+    unsigned bit_width = (dst->bit_width == 64) ? 64 : 32;
+    unsigned width = cast->bit_width;
+
+    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);
+
+    /* 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,
+                         unsigned begin,
+                         unsigned width)
+{
+    unsigned 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)
+{
+    unsigned bit_width = (src->bit_width == 64) ? 64 : 32;
+    unsigned width = extract->bit_width;
+    const char *sign_prefix;
+    HexValue res;
+
+    yyassert(c, locp, index->type == IMMEDIATE,
+             "Extract index must be immediate!\n");
+    assert_signedness(c, locp, extract->signedness);
+
+    sign_prefix = (extract->signedness == UNSIGNED) ? "" : "s";
+    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)
+{
+    HexValue value_m = *value;
+    yyassert(c, locp, reg->type == REGISTER, "reg must be a register!");
+    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)
+{
+    HexValue value_m = *value;
+    unsigned bit_width;
+
+    yyassert(c, locp,
+             !is_inside_ternary(c) ||
+             !(dst->type == REGISTER),
+             "register assign in ternary");
+
+    if (dst->type == REGISTER) {
+        gen_write_reg(c, locp, dst, &value_m);
+        return;
+    }
+
+    if (dst->type == VARID) {
+        find_variable(c, locp, dst, dst);
+    }
+    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)) {
+        HexValue zero = gen_constant(c, locp, "0", bit_width, UNSIGNED);
+        HexValue cond = get_ternary_cond(c, locp);
+        value_m = rvalue_materialize(c, locp, &value_m);
+        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);
+            }
+        }
+        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);
+    } 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;
+    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_constant(c, locp, "0x3", bit_width, UNSIGNED);
+    HexValue one = gen_constant(c, locp, "1", bit_width, UNSIGNED);
+    HexValue and;
+    HexValue src_p1;
+
+    src_m.is_manual = true;
+
+    and = gen_bin_op(c, locp, ANDB_OP, &src_m, &mask);
+    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(c, locp, &src_p1);
+
+    return res;
+}
+
+static HexValue gen_convround_n_b(Context *c,
+                                  YYLTYPE *locp,
+                                  HexValue *a,
+                                  HexValue *n)
+{
+    HexValue one = gen_constant(c, locp, "1", 32, UNSIGNED);
+    HexValue res = gen_tmp(c, locp, 64, UNSIGNED);
+    HexValue tmp = gen_tmp(c, locp, 32, UNSIGNED);
+    HexValue tmp_64 = gen_tmp(c, locp, 64, UNSIGNED);
+
+    assert(n->type != IMMEDIATE);
+    OUT(c, locp, "tcg_gen_ext_i32_i64(", &res, ", ", a, ");\n");
+    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, &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);
+    HexValue one = gen_constant(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_ext_i32_i64(", &res, ", ", a, ");\n");
+    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)
+{
+    HexValue zero = gen_constant(c, locp, "0", 64, UNSIGNED);
+    HexValue l_32 = gen_constant(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);
+    /* 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);
+    HexValue r1;
+    HexValue r2;
+    HexValue r3;
+
+    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.
+     */
+    r1 = gen_rvalue_extend(c, locp, &src_casted);
+    r2 = gen_convround_n_b(c, locp, &src_casted, &pos_casted);
+    r3 = gen_convround_n_c(c, locp, &src_casted, &pos_casted);
+
+    /*
+     * 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, &mask);
+    gen_rvalue_free(c, locp, &n_64);
+
+    res = gen_rvalue_truncate(c, locp, &res);
+    return res;
+}
+
+HexValue gen_round(Context *c,
+                   YYLTYPE *locp,
+                   HexValue *src,
+                   HexValue *pos)
+{
+    HexValue zero = gen_constant(c, locp, "0", 64, UNSIGNED);
+    HexValue one = gen_constant(c, locp, "1", 64, UNSIGNED);
+    HexValue res;
+    HexValue n_m1;
+    HexValue shifted;
+    HexValue sum;
+    HexValue src_width;
+    HexValue a;
+    HexValue b;
+
+    assert_signedness(c, locp, src->signedness);
+    yyassert(c, locp, src->bit_width <= 32,
+             "fRNDN not implemented for bit widths > 32!");
+
+    res = gen_tmp(c, locp, 64, src->signedness);
+
+    src_width = gen_imm_value(c, locp, src->bit_width, 32, UNSIGNED);
+    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);
+    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;
+
+    n_m1 = gen_bin_op(c, locp, SUB_OP, &b, &one);
+    shifted = gen_bin_op(c, locp, ASL_OP, &one, &n_m1);
+    sum = gen_bin_op(c, locp, ADD_OP, &shifted, &a);
+
+    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, &sum);
+
+    return res;
+}
+
+/* Circular addressing mode with auto-increment */
+void gen_circ_op(Context *c,
+                 YYLTYPE *locp,
+                 HexValue *addr,
+                 HexValue *increment,
+                 HexValue *modifier)
+{
+    HexValue cs = gen_tmp(c, locp, 32, UNSIGNED);
+    HexValue increment_m = *increment;
+    increment_m = rvalue_materialize(c, locp, &increment_m);
+    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)
+{
+    const char *bit_suffix = src->bit_width == 64 ? "64" : "32";
+    HexValue src_m = *src;
+    HexValue res;
+
+    assert_signedness(c, locp, src->signedness);
+    res = gen_tmp(c, locp, src->bit_width == 64 ? 64 : 32, src->signedness);
+    src_m = rvalue_materialize(c, locp, &src_m);
+    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)
+{
+    const char *bit_suffix = src->bit_width == 64 ? "64" : "32";
+    HexValue src_m = *src;
+    HexValue res;
+    assert_signedness(c, locp, src->signedness);
+    res = gen_tmp(c, locp, src->bit_width == 64 ? 64 : 32, src->signedness);
+    src_m = rvalue_materialize(c, locp, &src_m);
+    OUT(c, locp, "tcg_gen_ctpop_i", bit_suffix,
+        "(", &res, ", ", &src_m, ");\n");
+    gen_rvalue_free(c, locp, &src_m);
+    return res;
+}
+
+HexValue gen_rotl(Context *c, YYLTYPE *locp, HexValue *src, HexValue *width)
+{
+    const char *suffix = src->bit_width == 64 ? "i64" : "i32";
+    HexValue amount = *width;
+    HexValue res;
+    assert_signedness(c, locp, src->signedness);
+    res = gen_tmp(c, locp, src->bit_width, src->signedness);
+    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);
+    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 zero = gen_constant(c, locp, "0", 64, UNSIGNED);
+    HexValue res = gen_tmp(c, locp, 64, UNSIGNED);
+    HexValue cf = gen_tmp(c, locp, 64, UNSIGNED);
+    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);
+
+    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, &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)
+{
+    char pred_id[2] = {left_pred->pred.id, 0};
+    bool is_direct = is_direct_predicate(left_pred);
+    HexValue r = rvalue_materialize(c, locp, right_pred);
+    r = gen_rvalue_truncate(c, locp, &r);
+    /* Extract predicate TCGv */
+    if (is_direct) {
+        *left_pred = gen_tmp_value(c, locp, "0", 32, UNSIGNED);
+    }
+    /* Extract first 8 bits, and store new predicate value */
+    if (is_inside_ternary(c)) {
+        HexValue zero = gen_constant(c, locp, "0", r.bit_width, UNSIGNED);
+        HexValue tmp = gen_tmp(c, locp, r.bit_width, UNSIGNED);
+        HexValue cond = get_ternary_cond(c, locp);
+        yyassert(c, locp, !is_direct, "direct pred assign inside ternary op");
+        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);
+    } 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)
+{
+    char size_suffix[4] = {0};
+    const char *sign_suffix;
+    /* Memop width is specified in the load macro */
+    assert_signedness(c, locp, signedness);
+    sign_suffix = (width->imm.value > 4)
+                   ? ""
+                   : ((signedness == UNSIGNED) ? "u" : "s");
+    /* 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 */
+    unsigned 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)
+{
+    unsigned len;
+    HexValue tmp;
+
+    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);
+    len = hi->imm.value + 1 - lo->imm.value;
+    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);
+}
+
+unsigned gen_if_cond(Context *c, YYLTYPE *locp, HexValue *cond)
+{
+    const char *bit_suffix;
+    /* 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);
+    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++;
+}
+
+unsigned gen_if_else(Context *c, YYLTYPE *locp, unsigned index)
+{
+    unsigned if_index = c->inst.if_count++;
+    /* Generate label to jump if else is not verified */
+    OUT(c, locp, "TCGLabel *if_label_", &if_index,
+        " = gen_new_label();\n");
+    /* 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)
+{
+    HexValue res;
+    memset(&res, 0, sizeof(HexValue));
+
+    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);
+    }
+    res = 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);
+        HexSignedness signedness = bin_op_signedness(c, locp,
+                                                     mpy->first_signedness,
+                                                     mpy->second_signedness);
+        res = gen_extend_op(c, locp, &src_width, 64, &res,
+                            signedness);
+    }
+    return res;
+}
+
+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;
+    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;
+    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 {
+        HexValue zero = gen_constant(c, locp, "0", bit_width, UNSIGNED);
+        HexValue one = gen_constant(c, locp, "0xff", bit_width, UNSIGNED);
+        res = gen_tmp(c, locp, bit_width, value->signedness);
+        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);
+    }
+    return res;
+}
+
+void gen_set_overflow(Context *c, YYLTYPE *locp, HexValue *value)
+{
+    HexValue value_m = *value;
+
+    if (is_inside_ternary(c)) {
+        /* Inside ternary operator, need to take care of the side-effect */
+        HexValue cond = get_ternary_cond(c, locp);
+        HexValue zero = gen_constant(c, locp, "0", cond.bit_width, UNSIGNED);
+        bool is_64bit = cond.bit_width == 64;
+        unsigned bit_width = cond.bit_width;
+        value_m = rvalue_materialize(c, locp, &value_m);
+        if (is_64bit) {
+            value_m = gen_rvalue_extend(c, locp, &value_m);
+        }
+        OUT(c, locp, "tcg_gen_movcond_i", &bit_width,
+                     "(TCG_COND_NE, ", &value_m, ", ", &cond);
+        OUT(c, locp, ", ", &zero, ", ", &value_m, ", ", &zero, ");\n");
+        if (is_64bit) {
+            value_m = gen_rvalue_truncate(c, locp, &value_m);
+        }
+        gen_rvalue_free(c, locp, &cond);
+    }
+
+    OUT(c, locp, "SET_USR_FIELD(USR_OVF, ", &value_m, ");\n");
+    gen_rvalue_free(c, locp, &value_m);
+}
+
+HexValue gen_rvalue_sat(Context *c, YYLTYPE *locp, HexSat *sat,
+                        HexValue *width, HexValue *value)
+{
+    const char *unsigned_str;
+    const char *bit_suffix = (value->bit_width == 64) ? "i64" : "i32";
+    HexValue res;
+    assert_signedness(c, locp, sat->signedness);
+    res = gen_tmp(c, locp, value->bit_width, sat->signedness);
+    unsigned_str = (sat->signedness == UNSIGNED) ? "u" : "";
+    if (sat->set_overflow) {
+        yyassert(c, locp, width->imm.value < value->bit_width,
+                 "To compute overflow, source width must be greater than"
+                 "saturation width!");
+    }
+    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);
+    HexValue frame_key = gen_tmp(c, locp, 32, UNSIGNED);
+    *value = gen_rvalue_extend(c, locp, value);
+    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)
+{
+    HexValue res;
+    yyassert(c, locp, value->bit_width <= 32,
+             "fbrev not implemented for 64-bit integers!");
+    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);
+    unsigned bit_width = (is_64bit) ? 64 : 32;
+    HexValue zero = gen_constant(c, locp, "0", bit_width, UNSIGNED);
+    HexValue res = gen_tmp(c, locp, bit_width, UNSIGNED);
+    Ternary *ternary = NULL;
+
+    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);
+
+    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 = &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, 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..af19eb2f41
--- /dev/null
+++ b/target/hexagon/idef-parser/parser-helpers.h
@@ -0,0 +1,375 @@
+/*
+ *  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/>.
+ */
+
+#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,
+                         unsigned begin,
+                         unsigned width);
+
+HexValue gen_extract_op(Context *c,
+                        YYLTYPE *locp,
+                        HexValue *src,
+                        HexValue *index,
+                        HexExtract *extract);
+
+HexValue gen_read_reg(Context *c, YYLTYPE *locp, HexValue *reg);
+
+void gen_write_reg(Context *c, YYLTYPE *locp, HexValue *reg, HexValue *value);
+
+void gen_assign(Context *c,
+                YYLTYPE *locp,
+                HexValue *dst,
+                HexValue *value);
+
+HexValue gen_convround(Context *c,
+                       YYLTYPE *locp,
+                       HexValue *src);
+
+HexValue gen_round(Context *c,
+                   YYLTYPE *locp,
+                   HexValue *src,
+                   HexValue *position);
+
+HexValue gen_convround_n(Context *c,
+                         YYLTYPE *locp,
+                         HexValue *src,
+                         HexValue *pos);
+
+/**
+ * Circular addressing mode with auto-increment
+ */
+void gen_circ_op(Context *c,
+                 YYLTYPE *locp,
+                 HexValue *addr,
+                 HexValue *increment,
+                 HexValue *modifier);
+
+HexValue gen_locnt_op(Context *c, YYLTYPE *locp, HexValue *src);
+
+HexValue gen_ctpop_op(Context *c, YYLTYPE *locp, HexValue *src);
+
+HexValue gen_rotl(Context *c, YYLTYPE *locp, HexValue *src, HexValue *n);
+
+HexValue gen_deinterleave(Context *c, YYLTYPE *locp, HexValue *mixed);
+
+HexValue gen_interleave(Context *c,
+                        YYLTYPE *locp,
+                        HexValue *odd,
+                        HexValue *even);
+
+HexValue gen_carry_from_add(Context *c,
+                            YYLTYPE *locp,
+                            HexValue *op1,
+                            HexValue *op2,
+                            HexValue *op3);
+
+void gen_addsat64(Context *c,
+                  YYLTYPE *locp,
+                  HexValue *dst,
+                  HexValue *op1,
+                  HexValue *op2);
+
+void gen_inst(Context *c, GString *iname);
+
+void gen_inst_init_args(Context *c, YYLTYPE *locp);
+
+void gen_inst_code(Context *c, YYLTYPE *locp);
+
+void gen_pred_assign(Context *c, YYLTYPE *locp, HexValue *left_pred,
+                     HexValue *right_pred);
+
+void gen_load(Context *c, YYLTYPE *locp, HexValue *size,
+              HexSignedness signedness, HexValue *ea, HexValue *dst);
+
+void gen_store(Context *c, YYLTYPE *locp, HexValue *size, HexValue *ea,
+               HexValue *src);
+
+void gen_sethalf(Context *c, YYLTYPE *locp, HexCast *sh, HexValue *n,
+                 HexValue *dst, HexValue *value);
+
+void gen_setbits(Context *c, YYLTYPE *locp, HexValue *hi, HexValue *lo,
+                 HexValue *dst, HexValue *value);
+
+unsigned gen_if_cond(Context *c, YYLTYPE *locp, HexValue *cond);
+
+unsigned gen_if_else(Context *c, YYLTYPE *locp, unsigned index);
+
+HexValue gen_rvalue_pred(Context *c, YYLTYPE *locp, HexValue *pred);
+
+HexValue gen_rvalue_var(Context *c, YYLTYPE *locp, HexValue *var);
+
+HexValue gen_rvalue_mpy(Context *c, YYLTYPE *locp, HexMpy *mpy, HexValue *op1,
+                        HexValue *op2);
+
+HexValue gen_rvalue_not(Context *c, YYLTYPE *locp, HexValue *value);
+
+HexValue gen_rvalue_notl(Context *c, YYLTYPE *locp, HexValue *value);
+
+HexValue gen_rvalue_sat(Context *c, YYLTYPE *locp, HexSat *sat, HexValue *n,
+                        HexValue *value);
+
+HexValue gen_rvalue_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 63f13e1d21..bfc74ba441 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -200,4 +200,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.34.1



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

* [PATCH v8 11/12] target/hexagon: call idef-parser functions
  2022-02-09 17:03 [PATCH v8 00/12] target/hexagon: introduce idef-parser Anton Johansson via
                   ` (9 preceding siblings ...)
  2022-02-09 17:03 ` [PATCH v8 10/12] target/hexagon: import parser " Anton Johansson via
@ 2022-02-09 17:03 ` Anton Johansson via
  2022-02-09 17:03 ` [PATCH v8 12/12] target/hexagon: import additional tests Anton Johansson via
  11 siblings, 0 replies; 23+ messages in thread
From: Anton Johansson via @ 2022-02-09 17:03 UTC (permalink / raw)
  To: qemu-devel
  Cc: ale, tsimpson, bcain, mlambert, 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  | 17 +++++-
 target/hexagon/gen_helper_protos.py | 17 +++++-
 target/hexagon/gen_tcg_funcs.py     | 41 ++++++++++++-
 target/hexagon/hex_common.py        | 10 ++++
 target/hexagon/meson.build          | 92 +++++++++++++++++++----------
 6 files changed, 146 insertions(+), 34 deletions(-)

diff --git a/meson_options.txt b/meson_options.txt
index 921967eddb..3d66149356 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -208,3 +208,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..71d611283a 100755
--- a/target/hexagon/gen_helper_funcs.py
+++ b/target/hexagon/gen_helper_funcs.py
@@ -287,11 +287,24 @@ 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.
+    is_idef_parser_enabled = len(sys.argv) > 6
+    if is_idef_parser_enabled:
+        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 +321,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..74eff457a6 100755
--- a/target/hexagon/gen_helper_protos.py
+++ b/target/hexagon/gen_helper_protos.py
@@ -136,11 +136,24 @@ 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.
+    is_idef_parser_enabled = len(sys.argv) > 6
+    if is_idef_parser_enabled:
+        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 +171,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..4d12e192a7 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,27 @@ 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.
+    is_idef_parser_enabled = len(sys.argv) > 6
+    if is_idef_parser_enabled:
+        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")
+        if is_idef_parser_enabled:
+            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 bfc74ba441..6adf7e2464 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',
@@ -225,4 +197,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.34.1



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

* [PATCH v8 12/12] target/hexagon: import additional tests
  2022-02-09 17:03 [PATCH v8 00/12] target/hexagon: introduce idef-parser Anton Johansson via
                   ` (10 preceding siblings ...)
  2022-02-09 17:03 ` [PATCH v8 11/12] target/hexagon: call idef-parser functions Anton Johansson via
@ 2022-02-09 17:03 ` Anton Johansson via
  2022-03-21 18:58   ` Taylor Simpson
  11 siblings, 1 reply; 23+ messages in thread
From: Anton Johansson via @ 2022-02-09 17:03 UTC (permalink / raw)
  To: qemu-devel
  Cc: ale, tsimpson, bcain, mlambert, 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>
Signed-off-by: Anton Johansson <anjo@rev.ng>
---
 tests/tcg/hexagon/Makefile.target  | 28 ++++++++++++-
 tests/tcg/hexagon/crt.S            | 14 +++++++
 tests/tcg/hexagon/test_abs.S       | 17 ++++++++
 tests/tcg/hexagon/test_bitcnt.S    | 40 +++++++++++++++++++
 tests/tcg/hexagon/test_bitsplit.S  | 22 ++++++++++
 tests/tcg/hexagon/test_call.S      | 64 ++++++++++++++++++++++++++++++
 tests/tcg/hexagon/test_clobber.S   | 29 ++++++++++++++
 tests/tcg/hexagon/test_cmp.S       | 31 +++++++++++++++
 tests/tcg/hexagon/test_dotnew.S    | 38 ++++++++++++++++++
 tests/tcg/hexagon/test_ext.S       | 13 ++++++
 tests/tcg/hexagon/test_fibonacci.S | 30 ++++++++++++++
 tests/tcg/hexagon/test_hl.S        | 16 ++++++++
 tests/tcg/hexagon/test_hwloops.S   | 19 +++++++++
 tests/tcg/hexagon/test_jmp.S       | 22 ++++++++++
 tests/tcg/hexagon/test_lsr.S       | 36 +++++++++++++++++
 tests/tcg/hexagon/test_mpyi.S      | 17 ++++++++
 tests/tcg/hexagon/test_packet.S    | 29 ++++++++++++++
 tests/tcg/hexagon/test_reorder.S   | 33 +++++++++++++++
 tests/tcg/hexagon/test_round.S     | 29 ++++++++++++++
 tests/tcg/hexagon/test_vavgw.S     | 31 +++++++++++++++
 tests/tcg/hexagon/test_vcmpb.S     | 30 ++++++++++++++
 tests/tcg/hexagon/test_vcmpw.S     | 30 ++++++++++++++
 tests/tcg/hexagon/test_vlsrw.S     | 20 ++++++++++
 tests/tcg/hexagon/test_vmaxh.S     | 35 ++++++++++++++++
 tests/tcg/hexagon/test_vminh.S     | 35 ++++++++++++++++
 tests/tcg/hexagon/test_vpmpyh.S    | 28 +++++++++++++
 tests/tcg/hexagon/test_vspliceb.S  | 31 +++++++++++++++
 27 files changed, 766 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_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_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_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..508ab08065 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,30 @@ HEX_TESTS += atomics
 HEX_TESTS += fpstuff
 HEX_TESTS += overflow
 
+HEX_TESTS += test_abs
+HEX_TESTS += test_bitcnt
+HEX_TESTS += test_bitsplit
+HEX_TESTS += test_call
+HEX_TESTS += test_clobber
+HEX_TESTS += test_cmp
+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_packet
+HEX_TESTS += test_reorder
+HEX_TESTS += test_round
+HEX_TESTS += test_vavgw
+HEX_TESTS += test_vcmpb
+HEX_TESTS += test_vcmpw
+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..f9e6bc80f7
--- /dev/null
+++ b/tests/tcg/hexagon/crt.S
@@ -0,0 +1,14 @@
+#define SYS_exit_group 94
+
+    .text
+    .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..d68aea6f64
--- /dev/null
+++ b/tests/tcg/hexagon/test_abs.S
@@ -0,0 +1,17 @@
+/* Purpose: test example, verify the soundness of the abs operation */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        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..624460488e
--- /dev/null
+++ b/tests/tcg/hexagon/test_bitcnt.S
@@ -0,0 +1,40 @@
+/*
+ * 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:
+    {
+        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..275658e613
--- /dev/null
+++ b/tests/tcg/hexagon/test_bitsplit.S
@@ -0,0 +1,22 @@
+/* Purpose: test example, verify the soundness of the bitsplit operation */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        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..338cd04e40
--- /dev/null
+++ b/tests/tcg/hexagon/test_call.S
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#define SYS_write 64
+#define FD_STDOUT 1
+
+    .text
+    .globl    test
+test:
+    {
+        jumpr r31
+        memb(r0+#0) = #76
+    }
+.Lfunc_end0:
+.Ltmp0:
+    .size    test, .Ltmp0-test
+
+    .globl    _start
+_start:
+    {
+        r0 = ##dummy_buffer
+        allocframe(#0)
+        call test
+    }
+    {
+        call write
+    }
+    {
+        deallocframe
+        jump pass
+    }
+.Lfunc_end1:
+.Ltmp1:
+    .size    _start, .Ltmp1-_start
+
+write:
+    {
+        r6 = #SYS_write
+        r0 = #FD_STDOUT
+        r1 = ##dummy_buffer
+        r2 = #33
+    }
+    {
+        trap0(#1)
+    }
+    {
+        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..a7aeb2b60c
--- /dev/null
+++ b/tests/tcg/hexagon/test_clobber.S
@@ -0,0 +1,29 @@
+/*
+ * 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:
+    allocframe(#8)
+    {
+        r16 = #47
+        r17 = #155
+    }
+    memd(sp+#0) = r17:16
+    {
+        r16 = #255
+        r17 = #42
+    }
+    {
+        deallocframe
+        r17:16 = memd(sp+#0)
+    }
+    {
+        p0 = cmp.eq(r16, #47)
+        p0 = cmp.eq(r17, #155); 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..1db87d3db5
--- /dev/null
+++ b/tests/tcg/hexagon/test_cmp.S
@@ -0,0 +1,31 @@
+/* Purpose: test a signed and unsigned comparison */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        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_dotnew.S b/tests/tcg/hexagon/test_dotnew.S
new file mode 100644
index 0000000000..b18b6a72e2
--- /dev/null
+++ b/tests/tcg/hexagon/test_dotnew.S
@@ -0,0 +1,38 @@
+/* Purpose: test the .new operator while performing memory stores. */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        allocframe(#16)
+    }
+    {
+        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)
+    }
+    {
+        deallocframe
+        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..03e7bce2a7
--- /dev/null
+++ b/tests/tcg/hexagon/test_ext.S
@@ -0,0 +1,13 @@
+/* Purpose: test immediate extender instructions. */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        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..4ef2c3896e
--- /dev/null
+++ b/tests/tcg/hexagon/test_fibonacci.S
@@ -0,0 +1,30 @@
+/* Purpose: computes the Fibonacci series up to a constant number. */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        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..93ace46aeb
--- /dev/null
+++ b/tests/tcg/hexagon/test_hl.S
@@ -0,0 +1,16 @@
+/* Purpose: test example, verify the soundness of the high/low assignment */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        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..42785e6f25
--- /dev/null
+++ b/tests/tcg/hexagon/test_hwloops.S
@@ -0,0 +1,19 @@
+/* Purpose: simple C Program to test hardware loops. */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        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..5be25c52b2
--- /dev/null
+++ b/tests/tcg/hexagon/test_jmp.S
@@ -0,0 +1,22 @@
+/* Purpose: test example, verify the soundness of the jump operation */
+
+#define SYS_exit_group 94
+
+    .text
+    .globl _start
+
+_start:
+    {
+        jump pass
+    }
+    /*
+     * Inlined fail label in crt.S so we can fail without
+     * having a functioning jump
+     */
+    {
+        r0 = #1
+        r6 = #SYS_exit_group
+    }
+    {
+        trap0(#1)
+    }
diff --git a/tests/tcg/hexagon/test_lsr.S b/tests/tcg/hexagon/test_lsr.S
new file mode 100644
index 0000000000..b30aa64673
--- /dev/null
+++ b/tests/tcg/hexagon/test_lsr.S
@@ -0,0 +1,36 @@
+/* Purpose: test the soundness of the lsr operation */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        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..953b46e57e
--- /dev/null
+++ b/tests/tcg/hexagon/test_mpyi.S
@@ -0,0 +1,17 @@
+/* Purpose: test a simple multiplication operation */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        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_packet.S b/tests/tcg/hexagon/test_packet.S
new file mode 100644
index 0000000000..9ec9d8d6fb
--- /dev/null
+++ b/tests/tcg/hexagon/test_packet.S
@@ -0,0 +1,29 @@
+/*
+ * Purpose: test that writes of a register in a packet are performed only after
+ * that packet has finished its execution.
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        allocframe(#8)
+    }
+    {
+        r2 = #4
+        r3 = #6
+    }
+    {
+        memw(sp+#0) = r2
+    }
+    {
+        r3 = memw(sp+#0)
+        r0 = add(r2, r3)
+    }
+    {
+        deallocframe
+        p0 = cmp.eq(r3, #4)
+        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..5ee0539836
--- /dev/null
+++ b/tests/tcg/hexagon/test_reorder.S
@@ -0,0 +1,33 @@
+/*
+ * 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:
+    {
+        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..3c83812fe8
--- /dev/null
+++ b/tests/tcg/hexagon/test_round.S
@@ -0,0 +1,29 @@
+/*
+ * 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:
+    {
+        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..53c9df706a
--- /dev/null
+++ b/tests/tcg/hexagon/test_vavgw.S
@@ -0,0 +1,31 @@
+/*
+ * Purpose: test example, verify the soundness of the vavgw operation.
+ *
+ * 0x00030001 averaged with 0x00010003 results 0x00020002.
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        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..66d253eb48
--- /dev/null
+++ b/tests/tcg/hexagon/test_vcmpb.S
@@ -0,0 +1,30 @@
+/*
+ * Purpose: test example, verify the soundness of the vector compare bytes
+ * operation.
+ *
+ * Vector byte comparison between 0x1234567887654321 and 0x1234567800000000
+ * should result in 0b11110000 in binary, or 0xf0 in hex.
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        r0 = #0x87654321
+        r1 = #0x12345678
+    }
+    {
+        r2 = #0x00000000
+        r3 = #0x12345678
+    }
+    {
+        p2 = vcmpb.eq(r1:0, r3:2)
+    }
+    {
+        r4 = p2
+    }
+    {
+        p0 = cmp.eq(r4, #0xf0); 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..5be88d1e2e
--- /dev/null
+++ b/tests/tcg/hexagon/test_vcmpw.S
@@ -0,0 +1,30 @@
+/*
+ * Purpose: test example, verify the soundness of the vector compare words
+ * operation.
+ *
+ * Vector word comparison between 0x1234567887654321 and 0x1234567800000000
+ * should result in 0b11110000 in binary, or 0xf0 in hex.
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        r0 = #0x87654321
+        r1 = #0x12345678
+    }
+    {
+        r2 = #0x00000000
+        r3 = #0x12345678
+    }
+    {
+        p2 = vcmpw.eq(r1:0, r3:2)
+    }
+    {
+        r4 = p2
+    }
+    {
+        p0 = cmp.eq(r4, #0xf0); 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..912e49aa0b
--- /dev/null
+++ b/tests/tcg/hexagon/test_vlsrw.S
@@ -0,0 +1,20 @@
+/* Purpose: test the soundness of the vlsrw operation */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        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..4ea6bd9d96
--- /dev/null
+++ b/tests/tcg/hexagon/test_vmaxh.S
@@ -0,0 +1,35 @@
+/*
+ * Purpose: test example, verify the soundness of the vrmaxh operation.
+ *
+ * The maximum between  0x0002000300010005 and 0x0003000200020007 is
+ * 0x0003000300020007.
+ *
+ *      input:  r1 = 0x00010003 r0 = 0x00010005 r3 = 0x00030002 r2 = 0x00020007
+ *     output:  r1 = 0x00030003 r0 = 0x00020007
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        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..e5fcf2eb94
--- /dev/null
+++ b/tests/tcg/hexagon/test_vminh.S
@@ -0,0 +1,35 @@
+/*
+ * Purpose: test example, verify the soundness of the vrmaxh operation.
+ *
+ * The minimum between  0x0002000300010005 and 0x0003000200020007 is
+ * 0x0003000300020007.
+ *
+ *      input:  r1 = 0x00010003 r0 = 0x00010005 r3 = 0x00030002 r2 = 0x00020007
+ *     output:  r1 = 0x00010002 r0 = 0x00010005
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        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..f02758e449
--- /dev/null
+++ b/tests/tcg/hexagon/test_vpmpyh.S
@@ -0,0 +1,28 @@
+/*
+ * Purpose: test example, verify the soundness of the vpmpyh operator.
+ *
+ * 0x01020304 vector polynomial multiplied with 0x04030201 results
+ * 0x000400060b060b04.
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        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..53c4a91c51
--- /dev/null
+++ b/tests/tcg/hexagon/test_vspliceb.S
@@ -0,0 +1,31 @@
+/*
+ * Purpose: test example, verify the soundness of the vspliceb operation
+ * the operation is a binary splice of two 64bit operators.
+ *
+ *  vspliceb(0xffffffffffffffff,0x0000000000000000,5) = 0x000000ffffffffff.
+ */
+    .text
+    .globl _start
+
+_start:
+    {
+        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.34.1



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

* RE: [PATCH v8 05/12] target/hexagon: introduce new helper functions
  2022-02-09 17:03 ` [PATCH v8 05/12] target/hexagon: introduce new helper functions Anton Johansson via
@ 2022-03-21 18:28   ` Taylor Simpson
  0 siblings, 0 replies; 23+ messages in thread
From: Taylor Simpson @ 2022-03-21 18:28 UTC (permalink / raw)
  To: Anton Johansson, qemu-devel
  Cc: ale, Brian Cain, richard.henderson, babush, nizzo, Michael Lambert



> -----Original Message-----
> From: Anton Johansson <anjo@rev.ng>
> Sent: Wednesday, February 9, 2022 11:03 AM
> To: qemu-devel@nongnu.org
> Cc: ale@rev.ng; Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; Michael Lambert <mlambert@quicinc.com>;
> babush@rev.ng; nizzo@rev.ng; richard.henderson@linaro.org
> Subject: [PATCH v8 05/12] target/hexagon: introduce new helper functions
> 
> From: Niccolò Izzo <nizzo@rev.ng>
> 
> These helpers will be employed by the idef-parser generated code, to
> correctly implement instruction semantics. "Helper" functions, in the context
> of this patch, refers to functions which provide a manual TCG
> implementation of 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 | 167
> ++++++++++++++++++++++++++++++++++++++--
>  target/hexagon/genptr.h |  16 +++-
>  target/hexagon/macros.h |   9 +++
>  3 files changed, 184 insertions(+), 8 deletions(-)

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

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

* RE: [PATCH v8 07/12] target/hexagon: prepare input for the idef-parser
  2022-02-09 17:03 ` [PATCH v8 07/12] target/hexagon: prepare input for the idef-parser Anton Johansson via
@ 2022-03-21 18:33   ` Taylor Simpson
  0 siblings, 0 replies; 23+ messages in thread
From: Taylor Simpson @ 2022-03-21 18:33 UTC (permalink / raw)
  To: Anton Johansson, qemu-devel
  Cc: ale, Brian Cain, richard.henderson, babush, nizzo, Michael Lambert



> -----Original Message-----
> From: Anton Johansson <anjo@rev.ng>
> Sent: Wednesday, February 9, 2022 11:03 AM
> To: qemu-devel@nongnu.org
> Cc: ale@rev.ng; Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; Michael Lambert <mlambert@quicinc.com>;
> babush@rev.ng; nizzo@rev.ng; richard.henderson@linaro.org
> Subject: [PATCH v8 07/12] 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 | 125
> +++++++++++++++++++++
>  target/hexagon/idef-parser/macros.inc   | 140
> ++++++++++++++++++++++++
>  target/hexagon/idef-parser/prepare      |  24 ++++
>  target/hexagon/meson.build              |  17 +++
>  4 files changed, 306 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

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


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

* RE: [PATCH v8 09/12] target/hexagon: import lexer for idef-parser
  2022-02-09 17:03 ` [PATCH v8 09/12] target/hexagon: import lexer for idef-parser Anton Johansson via
@ 2022-03-21 18:40   ` Taylor Simpson
  0 siblings, 0 replies; 23+ messages in thread
From: Taylor Simpson @ 2022-03-21 18:40 UTC (permalink / raw)
  To: Anton Johansson, qemu-devel
  Cc: ale, Brian Cain, richard.henderson, babush, nizzo, Michael Lambert



> -----Original Message-----
> From: Anton Johansson <anjo@rev.ng>
> Sent: Wednesday, February 9, 2022 11:03 AM
> To: qemu-devel@nongnu.org
> Cc: ale@rev.ng; Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; Michael Lambert <mlambert@quicinc.com>;
> babush@rev.ng; nizzo@rev.ng; richard.henderson@linaro.org
> Subject: [PATCH v8 09/12] 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   | 254 +++++++++
>  target/hexagon/idef-parser/idef-parser.lex | 566
> +++++++++++++++++++++
>  target/hexagon/meson.build                 |   4 +
>  3 files changed, 824 insertions(+)
>  create mode 100644 target/hexagon/idef-parser/idef-parser.h
>  create mode 100644 target/hexagon/idef-parser/idef-parser.lex

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



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

* RE: [PATCH v8 12/12] target/hexagon: import additional tests
  2022-02-09 17:03 ` [PATCH v8 12/12] target/hexagon: import additional tests Anton Johansson via
@ 2022-03-21 18:58   ` Taylor Simpson
  0 siblings, 0 replies; 23+ messages in thread
From: Taylor Simpson @ 2022-03-21 18:58 UTC (permalink / raw)
  To: Anton Johansson, qemu-devel
  Cc: ale, Brian Cain, richard.henderson, babush, nizzo, Michael Lambert



> -----Original Message-----
> From: Anton Johansson <anjo@rev.ng>
> Sent: Wednesday, February 9, 2022 11:03 AM
> To: qemu-devel@nongnu.org
> Cc: ale@rev.ng; Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; Michael Lambert <mlambert@quicinc.com>;
> babush@rev.ng; nizzo@rev.ng; richard.henderson@linaro.org
> Subject: [PATCH v8 12/12] 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>
> Signed-off-by: Anton Johansson <anjo@rev.ng>
> ---
>  tests/tcg/hexagon/Makefile.target  | 28 ++++++++++++-
>  tests/tcg/hexagon/crt.S            | 14 +++++++
>  tests/tcg/hexagon/test_abs.S       | 17 ++++++++
>  tests/tcg/hexagon/test_bitcnt.S    | 40 +++++++++++++++++++
>  tests/tcg/hexagon/test_bitsplit.S  | 22 ++++++++++
>  tests/tcg/hexagon/test_call.S      | 64 ++++++++++++++++++++++++++++++
>  tests/tcg/hexagon/test_clobber.S   | 29 ++++++++++++++
>  tests/tcg/hexagon/test_cmp.S       | 31 +++++++++++++++
>  tests/tcg/hexagon/test_dotnew.S    | 38 ++++++++++++++++++
>  tests/tcg/hexagon/test_ext.S       | 13 ++++++
>  tests/tcg/hexagon/test_fibonacci.S | 30 ++++++++++++++
>  tests/tcg/hexagon/test_hl.S        | 16 ++++++++
>  tests/tcg/hexagon/test_hwloops.S   | 19 +++++++++
>  tests/tcg/hexagon/test_jmp.S       | 22 ++++++++++
>  tests/tcg/hexagon/test_lsr.S       | 36 +++++++++++++++++
>  tests/tcg/hexagon/test_mpyi.S      | 17 ++++++++
>  tests/tcg/hexagon/test_packet.S    | 29 ++++++++++++++
>  tests/tcg/hexagon/test_reorder.S   | 33 +++++++++++++++
>  tests/tcg/hexagon/test_round.S     | 29 ++++++++++++++
>  tests/tcg/hexagon/test_vavgw.S     | 31 +++++++++++++++
>  tests/tcg/hexagon/test_vcmpb.S     | 30 ++++++++++++++
>  tests/tcg/hexagon/test_vcmpw.S     | 30 ++++++++++++++
>  tests/tcg/hexagon/test_vlsrw.S     | 20 ++++++++++
>  tests/tcg/hexagon/test_vmaxh.S     | 35 ++++++++++++++++
>  tests/tcg/hexagon/test_vminh.S     | 35 ++++++++++++++++
>  tests/tcg/hexagon/test_vpmpyh.S    | 28 +++++++++++++
>  tests/tcg/hexagon/test_vspliceb.S  | 31 +++++++++++++++
>  27 files changed, 766 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_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_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_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

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


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

* RE: [PATCH v8 10/12] target/hexagon: import parser for idef-parser
  2022-02-09 17:03 ` [PATCH v8 10/12] target/hexagon: import parser " Anton Johansson via
@ 2022-04-11 15:20   ` Taylor Simpson
  2022-04-12 15:10     ` Anton Johansson via
  0 siblings, 1 reply; 23+ messages in thread
From: Taylor Simpson @ 2022-04-11 15:20 UTC (permalink / raw)
  To: Anton Johansson, qemu-devel
  Cc: ale, Brian Cain, richard.henderson, babush, nizzo, Michael Lambert



> -----Original Message-----
> From: Anton Johansson <anjo@rev.ng>
> Sent: Wednesday, February 9, 2022 11:03 AM
> To: qemu-devel@nongnu.org
> Cc: ale@rev.ng; Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; Michael Lambert <mlambert@quicinc.com>;
> babush@rev.ng; nizzo@rev.ng; richard.henderson@linaro.org
> Subject: [PATCH v8 10/12] target/hexagon: import parser for idef-parser
> 
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Paolo Montesel <babush@rev.ng>
> Signed-off-by: Anton Johansson <anjo@rev.ng>


> diff --git a/target/hexagon/idef-parser/parser-helpers.c
> b/target/hexagon/idef-parser/parser-helpers.c
> new file mode 100644



> +void gen_set_overflow(Context *c, YYLTYPE *locp, HexValue *value)
> +{
> +    HexValue value_m = *value;
> +
> +    if (is_inside_ternary(c)) {
> +        /* Inside ternary operator, need to take care of the side-effect */
> +        HexValue cond = get_ternary_cond(c, locp);
> +        HexValue zero = gen_constant(c, locp, "0", cond.bit_width,
> UNSIGNED);
> +        bool is_64bit = cond.bit_width == 64;
> +        unsigned bit_width = cond.bit_width;
> +        value_m = rvalue_materialize(c, locp, &value_m);
> +        if (is_64bit) {
> +            value_m = gen_rvalue_extend(c, locp, &value_m);
> +        }
> +        OUT(c, locp, "tcg_gen_movcond_i", &bit_width,
> +                     "(TCG_COND_NE, ", &value_m, ", ", &cond);
> +        OUT(c, locp, ", ", &zero, ", ", &value_m, ", ", &zero, ");\n");

You shouldn't write zero when the condition is false - you should do nothing.  Try a test where OVF is already set.  You can't overwrite the bit with zero when the current instruction doesn't overflow.



> +        if (is_64bit) {
> +            value_m = gen_rvalue_truncate(c, locp, &value_m);
> +        }
> +        gen_rvalue_free(c, locp, &cond);
> +    }
> +
> +    OUT(c, locp, "SET_USR_FIELD(USR_OVF, ", &value_m, ");\n");
> +    gen_rvalue_free(c, locp, &value_m);
> +}


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

* Re: [PATCH v8 10/12] target/hexagon: import parser for idef-parser
  2022-04-11 15:20   ` Taylor Simpson
@ 2022-04-12 15:10     ` Anton Johansson via
  2022-04-12 18:41       ` Taylor Simpson
  0 siblings, 1 reply; 23+ messages in thread
From: Anton Johansson via @ 2022-04-12 15:10 UTC (permalink / raw)
  To: Taylor Simpson, qemu-devel
  Cc: ale, Brian Cain, Michael Lambert, babush, nizzo, richard.henderson

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

Very nice catch, this is the bug that plagued us a few weeks ago when 
rebasing,
it has since been fixed. Actually the `gen_set_overflow` fucntion has 
been removed
completely as it was only called when we handled `asl/asr_r_r_sat`.

Current way we handle overflow:

Overflow is now only set by saturates, this assumption holds for the 
instructions
we parse in phase 1. In the parser, all saturates call `gen_rvalue_sat` 
which emits
a call to `gen_set_usr_field_if` in `genptr.c` to set USR_OVF only if 
the value is
non-zero. It does this via OR'ing with the previous value.

See here 
<https://gitlab.com/AntonJohansson/qemu/-/blob/feature/idef-parser/target/hexagon/idef-parser/parser-helpers.c#L2109> 
for `gen_rvalue_sat`
and here 
<https://gitlab.com/AntonJohansson/qemu/-/blob/feature/idef-parser/target/hexagon/genptr.c#L669> 
for `gen_set_usr_field_if`

>
>> -----Original Message-----
>> From: Anton Johansson<anjo@rev.ng>
>> Sent: Wednesday, February 9, 2022 11:03 AM
>> To:qemu-devel@nongnu.org
>> Cc:ale@rev.ng; Taylor Simpson<tsimpson@quicinc.com>; Brian Cain
>> <bcain@quicinc.com>; Michael Lambert<mlambert@quicinc.com>;
>> babush@rev.ng;nizzo@rev.ng;richard.henderson@linaro.org
>> Subject: [PATCH v8 10/12] target/hexagon: import parser for idef-parser
>>
>> Signed-off-by: Alessandro Di Federico<ale@rev.ng>
>> Signed-off-by: Paolo Montesel<babush@rev.ng>
>> Signed-off-by: Anton Johansson<anjo@rev.ng>
>
>> diff --git a/target/hexagon/idef-parser/parser-helpers.c
>> b/target/hexagon/idef-parser/parser-helpers.c
>> new file mode 100644
>
>
>> +void gen_set_overflow(Context *c, YYLTYPE *locp, HexValue *value)
>> +{
>> +    HexValue value_m = *value;
>> +
>> +    if (is_inside_ternary(c)) {
>> +        /* Inside ternary operator, need to take care of the side-effect */
>> +        HexValue cond = get_ternary_cond(c, locp);
>> +        HexValue zero = gen_constant(c, locp, "0", cond.bit_width,
>> UNSIGNED);
>> +        bool is_64bit = cond.bit_width == 64;
>> +        unsigned bit_width = cond.bit_width;
>> +        value_m = rvalue_materialize(c, locp, &value_m);
>> +        if (is_64bit) {
>> +            value_m = gen_rvalue_extend(c, locp, &value_m);
>> +        }
>> +        OUT(c, locp, "tcg_gen_movcond_i", &bit_width,
>> +                     "(TCG_COND_NE, ", &value_m, ", ", &cond);
>> +        OUT(c, locp, ", ", &zero, ", ", &value_m, ", ", &zero, ");\n");
> You shouldn't write zero when the condition is false - you should do nothing.  Try a test where OVF is already set.  You can't overwrite the bit with zero when the current instruction doesn't overflow.
>
>
>
>> +        if (is_64bit) {
>> +            value_m = gen_rvalue_truncate(c, locp, &value_m);
>> +        }
>> +        gen_rvalue_free(c, locp, &cond);
>> +    }
>> +
>> +    OUT(c, locp, "SET_USR_FIELD(USR_OVF, ", &value_m, ");\n");
>> +    gen_rvalue_free(c, locp, &value_m);
>> +}

[-- Attachment #2: Type: text/html, Size: 4983 bytes --]

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

* RE: [PATCH v8 10/12] target/hexagon: import parser for idef-parser
  2022-04-12 15:10     ` Anton Johansson via
@ 2022-04-12 18:41       ` Taylor Simpson
  2022-04-21 11:50         ` Anton Johansson via
  0 siblings, 1 reply; 23+ messages in thread
From: Taylor Simpson @ 2022-04-12 18:41 UTC (permalink / raw)
  To: anjo, qemu-devel
  Cc: ale, Brian Cain, richard.henderson, babush, nizzo, Michael Lambert



> From: Anton Johansson <anjo@rev.ng> 
> Sent: Tuesday, April 12, 2022 10:11 AM
> To: Taylor Simpson <tsimpson@quicinc.com>; qemu-devel@nongnu.org
> Cc: ale@rev.ng; Brian Cain <bcain@quicinc.com>; Michael Lambert <mlambert@quicinc.com>; babush@rev.ng; nizzo@rev.ng; richard.henderson@linaro.org
> Subject: Re: [PATCH v8 10/12] target/hexagon: import parser for idef-parser
> 
> Very nice catch, this is the bug that plagued us a few weeks ago when rebasing,
> it has since been fixed. Actually the `gen_set_overflow` fucntion has been removed
> completely as it was only called when we handled `asl/asr_r_r_sat`.
> Current way we handle overflow:
>
> Overflow is now only set by saturates, this assumption holds for the instructions
> we parse in phase 1. In the parser, all saturates call `gen_rvalue_sat` which emits
> a call to `gen_set_usr_field_if` in `genptr.c` to set USR_OVF only if the value is
> non-zero. It does this via OR'ing with the previous value.
>
> See https://gitlab.com/AntonJohansson/qemu/-/blob/feature/idef-parser/target/hexagon/idef-parser/parser-helpers.c#L2109 for `gen_rvalue_sat`
> and https://gitlab.com/AntonJohansson/qemu/-/blob/feature/idef-parser/target/hexagon/genptr.c#L669 for `gen_set_usr_field_if`

Your implementation of gen_set_usr_field_if is not correct.  Don't extract the bits from the value based on the reg_field_info.  The easiest thing to do is compare val with zero and jump over a call to gen_set_usr_field.  If you are determined to do an "or", you have to assert that ref_field_info[field].width == 1.  Then, you can extract 1 bit from val starting at offset zero and shift the result left by ref_field_info[field].offset and then "or" with USR.

Thanks,
Taylor


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

* Re: [PATCH v8 10/12] target/hexagon: import parser for idef-parser
  2022-04-12 18:41       ` Taylor Simpson
@ 2022-04-21 11:50         ` Anton Johansson via
  2022-04-21 14:22           ` Taylor Simpson
  0 siblings, 1 reply; 23+ messages in thread
From: Anton Johansson via @ 2022-04-21 11:50 UTC (permalink / raw)
  To: Taylor Simpson, qemu-devel
  Cc: ale, Brian Cain, Michael Lambert, babush, nizzo, richard.henderson

Here's an updated version of `gen_set_usr_field_If`

https://gitlab.com/AntonJohansson/qemu/-/blob/feature/idef-parser/target/hexagon/genptr.c#L673

If this looks alright and we have your "reviewed-by" on this patch, I'll 
go ahead and submit the new
patchset! :)

-- 
Anton Johansson,
rev.ng Labs Srl.

>
>> From: Anton Johansson <anjo@rev.ng>
>> Sent: Tuesday, April 12, 2022 10:11 AM
>> To: Taylor Simpson <tsimpson@quicinc.com>; qemu-devel@nongnu.org
>> Cc: ale@rev.ng; Brian Cain <bcain@quicinc.com>; Michael Lambert <mlambert@quicinc.com>; babush@rev.ng; nizzo@rev.ng; richard.henderson@linaro.org
>> Subject: Re: [PATCH v8 10/12] target/hexagon: import parser for idef-parser
>>
>> Very nice catch, this is the bug that plagued us a few weeks ago when rebasing,
>> it has since been fixed. Actually the `gen_set_overflow` fucntion has been removed
>> completely as it was only called when we handled `asl/asr_r_r_sat`.
>> Current way we handle overflow:
>>
>> Overflow is now only set by saturates, this assumption holds for the instructions
>> we parse in phase 1. In the parser, all saturates call `gen_rvalue_sat` which emits
>> a call to `gen_set_usr_field_if` in `genptr.c` to set USR_OVF only if the value is
>> non-zero. It does this via OR'ing with the previous value.
>>
>> See https://gitlab.com/AntonJohansson/qemu/-/blob/feature/idef-parser/target/hexagon/idef-parser/parser-helpers.c#L2109 for `gen_rvalue_sat`
>> and https://gitlab.com/AntonJohansson/qemu/-/blob/feature/idef-parser/target/hexagon/genptr.c#L669 for `gen_set_usr_field_if`
> Your implementation of gen_set_usr_field_if is not correct.  Don't extract the bits from the value based on the reg_field_info.  The easiest thing to do is compare val with zero and jump over a call to gen_set_usr_field.  If you are determined to do an "or", you have to assert that ref_field_info[field].width == 1.  Then, you can extract 1 bit from val starting at offset zero and shift the result left by ref_field_info[field].offset and then "or" with USR.
>
> Thanks,
> Taylor



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

* RE: [PATCH v8 10/12] target/hexagon: import parser for idef-parser
  2022-04-21 11:50         ` Anton Johansson via
@ 2022-04-21 14:22           ` Taylor Simpson
  2022-04-21 16:38             ` Anton Johansson via
  0 siblings, 1 reply; 23+ messages in thread
From: Taylor Simpson @ 2022-04-21 14:22 UTC (permalink / raw)
  To: anjo, qemu-devel
  Cc: ale, Brian Cain, richard.henderson, babush, nizzo, Michael Lambert



> -----Original Message-----
> From: Anton Johansson <anjo@rev.ng>
> Sent: Thursday, April 21, 2022 6:51 AM
> To: Taylor Simpson <tsimpson@quicinc.com>; qemu-devel@nongnu.org
> Cc: ale@rev.ng; Brian Cain <bcain@quicinc.com>; Michael Lambert
> <mlambert@quicinc.com>; babush@rev.ng; nizzo@rev.ng;
> richard.henderson@linaro.org
> Subject: Re: [PATCH v8 10/12] target/hexagon: import parser for idef-parser
> 
> 
> Here's an updated version of `gen_set_usr_field_If`
> 
> https://gitlab.com/AntonJohansson/qemu/-/blob/feature/idef-
> parser/target/hexagon/genptr.c#L673
> 
> If this looks alright and we have your "reviewed-by" on this patch, I'll go
> ahead and submit the new patchset! :)

> /*
>  * Note: Since this function might branch, `val` is
>  * required to be a `tcg_temp_local`.
>  */
> void gen_set_usr_field_if(int field, TCGv val)
> {
>     /* Sets the USR field if `val` is non-zero */
>     if (false && reg_field_info[field].width == 1) {

Remove the "false &&"

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


>         TCGv tmp = tcg_temp_new();
>         tcg_gen_extract_tl(tmp, val, 0, reg_field_info[field].width);
>         tcg_gen_shli_tl(tmp, tmp, reg_field_info[field].offset);
>         tcg_gen_or_tl(hex_new_value[HEX_REG_USR],
>                       hex_new_value[HEX_REG_USR],
>                       tmp);
>         tcg_temp_free(tmp);
>     } else {
>         TCGLabel *skip_label = gen_new_label();
>         tcg_gen_brcondi_tl(TCG_COND_EQ, val, 0, skip_label);
>         gen_set_usr_field(field, val);
>         gen_set_label(skip_label);
>     }
> }

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

* Re: [PATCH v8 10/12] target/hexagon: import parser for idef-parser
  2022-04-21 14:22           ` Taylor Simpson
@ 2022-04-21 16:38             ` Anton Johansson via
  0 siblings, 0 replies; 23+ messages in thread
From: Anton Johansson via @ 2022-04-21 16:38 UTC (permalink / raw)
  To: Taylor Simpson, qemu-devel
  Cc: ale, Brian Cain, Michael Lambert, babush, nizzo, richard.henderson


>
>> -----Original Message-----
>> From: Anton Johansson <anjo@rev.ng>
>> Sent: Thursday, April 21, 2022 6:51 AM
>> To: Taylor Simpson <tsimpson@quicinc.com>; qemu-devel@nongnu.org
>> Cc: ale@rev.ng; Brian Cain <bcain@quicinc.com>; Michael Lambert
>> <mlambert@quicinc.com>; babush@rev.ng; nizzo@rev.ng;
>> richard.henderson@linaro.org
>> Subject: Re: [PATCH v8 10/12] target/hexagon: import parser for idef-parser
>>
>>
>> Here's an updated version of `gen_set_usr_field_If`
>>
>> https://gitlab.com/AntonJohansson/qemu/-/blob/feature/idef-
>> parser/target/hexagon/genptr.c#L673
>>
>> If this looks alright and we have your "reviewed-by" on this patch, I'll go
>> ahead and submit the new patchset! :)
>> /*
>>   * Note: Since this function might branch, `val` is
>>   * required to be a `tcg_temp_local`.
>>   */
>> void gen_set_usr_field_if(int field, TCGv val)
>> {
>>      /* Sets the USR field if `val` is non-zero */
>>      if (false && reg_field_info[field].width == 1) {
> Remove the "false &&"
>
> Otherwise
> Reviewed-by: Taylor Simpson <tsimpson@quicinc.com>

Ah ofc! Remnant of testing. Fixed.

I'll rebase and run the usual pre-submit tests once again.

>
>
>>          TCGv tmp = tcg_temp_new();
>>          tcg_gen_extract_tl(tmp, val, 0, reg_field_info[field].width);
>>          tcg_gen_shli_tl(tmp, tmp, reg_field_info[field].offset);
>>          tcg_gen_or_tl(hex_new_value[HEX_REG_USR],
>>                        hex_new_value[HEX_REG_USR],
>>                        tmp);
>>          tcg_temp_free(tmp);
>>      } else {
>>          TCGLabel *skip_label = gen_new_label();
>>          tcg_gen_brcondi_tl(TCG_COND_EQ, val, 0, skip_label);
>>          gen_set_usr_field(field, val);
>>          gen_set_label(skip_label);
>>      }
>> }


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

end of thread, other threads:[~2022-04-21 17:00 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-09 17:03 [PATCH v8 00/12] target/hexagon: introduce idef-parser Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 01/12] target/hexagon: update MAINTAINERS for idef-parser Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 02/12] target/hexagon: import README " Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 03/12] target/hexagon: make slot number an unsigned Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 04/12] target/hexagon: make helper functions non-static Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 05/12] target/hexagon: introduce new helper functions Anton Johansson via
2022-03-21 18:28   ` Taylor Simpson
2022-02-09 17:03 ` [PATCH v8 06/12] target/hexagon: expose next PC in DisasContext Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 07/12] target/hexagon: prepare input for the idef-parser Anton Johansson via
2022-03-21 18:33   ` Taylor Simpson
2022-02-09 17:03 ` [PATCH v8 08/12] target/hexagon: import flex/bison to docker files Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 09/12] target/hexagon: import lexer for idef-parser Anton Johansson via
2022-03-21 18:40   ` Taylor Simpson
2022-02-09 17:03 ` [PATCH v8 10/12] target/hexagon: import parser " Anton Johansson via
2022-04-11 15:20   ` Taylor Simpson
2022-04-12 15:10     ` Anton Johansson via
2022-04-12 18:41       ` Taylor Simpson
2022-04-21 11:50         ` Anton Johansson via
2022-04-21 14:22           ` Taylor Simpson
2022-04-21 16:38             ` Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 11/12] target/hexagon: call idef-parser functions Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 12/12] target/hexagon: import additional tests Anton Johansson via
2022-03-21 18:58   ` Taylor Simpson

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.