qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/10] target/hexagon: introduce idef-parser
@ 2021-02-25 15:18 Alessandro Di Federico via
  2021-02-25 15:18 ` [PATCH v2 01/10] target/hexagon: update MAINTAINERS for idef-parser Alessandro Di Federico via
                   ` (10 more replies)
  0 siblings, 11 replies; 30+ messages in thread
From: Alessandro Di Federico via @ 2021-02-25 15:18 UTC (permalink / raw)
  To: qemu-devel
  Cc: tsimpson, bcain, babush, nizzo, philmd, richard.henderson,
	Alessandro Di Federico

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

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

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

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

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

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

A couple of notes:

* `idef-parser` also supports certain things that are not used in the
  most recently submitted version of the "Hexagon patch
  series". However, they will be needed and stripping them out of the
  parser is quite a bit of work.
* checkpatch.pl complains on a single macro which has a trailing
  semi-colon, which is required.

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

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

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

 MAINTAINERS                                   |    8 +
 target/hexagon/README                         |    5 +
 target/hexagon/gen_idef_parser_funcs.py       |  114 +
 target/hexagon/gen_tcg_funcs.py               |   28 +-
 target/hexagon/genptr.c                       |  240 +-
 target/hexagon/genptr.h                       |   26 +
 target/hexagon/hex_common.py                  |   10 +
 target/hexagon/idef-parser/README.rst         |  447 ++++
 target/hexagon/idef-parser/idef-parser.h      |  245 +++
 target/hexagon/idef-parser/idef-parser.lex    |  647 ++++++
 target/hexagon/idef-parser/idef-parser.y      | 1250 +++++++++++
 target/hexagon/idef-parser/macros.inc         |  166 ++
 target/hexagon/idef-parser/parser-helpers.c   | 1925 +++++++++++++++++
 target/hexagon/idef-parser/parser-helpers.h   |  293 +++
 target/hexagon/idef-parser/prepare            |   33 +
 target/hexagon/macros.h                       |    2 +-
 target/hexagon/meson.build                    |   67 +-
 target/hexagon/translate.c                    |    4 +-
 target/hexagon/translate.h                    |    1 +
 tests/docker/dockerfiles/alpine.docker        |    2 +
 tests/docker/dockerfiles/centos7.docker       |    2 +
 tests/docker/dockerfiles/centos8.docker       |    2 +
 tests/docker/dockerfiles/debian10.docker      |    2 +
 .../dockerfiles/fedora-i386-cross.docker      |    2 +
 .../dockerfiles/fedora-win32-cross.docker     |    2 +
 .../dockerfiles/fedora-win64-cross.docker     |    2 +
 tests/docker/dockerfiles/fedora.docker        |    2 +
 tests/docker/dockerfiles/opensuse-leap.docker |    2 +
 tests/docker/dockerfiles/ubuntu.docker        |    2 +
 tests/docker/dockerfiles/ubuntu1804.docker    |    2 +
 tests/docker/dockerfiles/ubuntu2004.docker    |    4 +-
 tests/tcg/hexagon/Makefile.target             |   35 +-
 tests/tcg/hexagon/crt.S                       |   28 +
 tests/tcg/hexagon/first.S                     |   24 +-
 tests/tcg/hexagon/test_abs.S                  |   20 +
 tests/tcg/hexagon/test_add.S                  |   20 +
 tests/tcg/hexagon/test_andp.S                 |   23 +
 tests/tcg/hexagon/test_bitcnt.S               |   42 +
 tests/tcg/hexagon/test_bitsplit.S             |   25 +
 tests/tcg/hexagon/test_call.S                 |   63 +
 tests/tcg/hexagon/test_clobber.S              |   35 +
 tests/tcg/hexagon/test_cmp.S                  |   34 +
 tests/tcg/hexagon/test_cmpy.S                 |   31 +
 tests/tcg/hexagon/test_djump.S                |   24 +
 tests/tcg/hexagon/test_dotnew.S               |   39 +
 tests/tcg/hexagon/test_dstore.S               |   29 +
 tests/tcg/hexagon/test_ext.S                  |   18 +
 tests/tcg/hexagon/test_fibonacci.S            |   33 +
 tests/tcg/hexagon/test_hello.S                |   21 +
 tests/tcg/hexagon/test_hl.S                   |   19 +
 tests/tcg/hexagon/test_hwloops.S              |   25 +
 tests/tcg/hexagon/test_jmp.S                  |   25 +
 tests/tcg/hexagon/test_lsr.S                  |   39 +
 tests/tcg/hexagon/test_mpyi.S                 |   20 +
 tests/tcg/hexagon/test_packet.S               |   26 +
 tests/tcg/hexagon/test_reorder.S              |   31 +
 tests/tcg/hexagon/test_round.S                |   31 +
 tests/tcg/hexagon/test_vavgw.S                |   33 +
 tests/tcg/hexagon/test_vcmpb.S                |   32 +
 tests/tcg/hexagon/test_vcmpw.S                |   29 +
 tests/tcg/hexagon/test_vcmpy.S                |   50 +
 tests/tcg/hexagon/test_vlsrw.S                |   23 +
 tests/tcg/hexagon/test_vmaxh.S                |   37 +
 tests/tcg/hexagon/test_vminh.S                |   37 +
 tests/tcg/hexagon/test_vpmpyh.S               |   30 +
 tests/tcg/hexagon/test_vspliceb.S             |   33 +
 66 files changed, 6568 insertions(+), 33 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 tests/tcg/hexagon/crt.S
 create mode 100644 tests/tcg/hexagon/test_abs.S
 create mode 100644 tests/tcg/hexagon/test_add.S
 create mode 100644 tests/tcg/hexagon/test_andp.S
 create mode 100644 tests/tcg/hexagon/test_bitcnt.S
 create mode 100644 tests/tcg/hexagon/test_bitsplit.S
 create mode 100644 tests/tcg/hexagon/test_call.S
 create mode 100644 tests/tcg/hexagon/test_clobber.S
 create mode 100644 tests/tcg/hexagon/test_cmp.S
 create mode 100644 tests/tcg/hexagon/test_cmpy.S
 create mode 100644 tests/tcg/hexagon/test_djump.S
 create mode 100644 tests/tcg/hexagon/test_dotnew.S
 create mode 100644 tests/tcg/hexagon/test_dstore.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_hello.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_vcmpy.S
 create mode 100644 tests/tcg/hexagon/test_vlsrw.S
 create mode 100644 tests/tcg/hexagon/test_vmaxh.S
 create mode 100644 tests/tcg/hexagon/test_vminh.S
 create mode 100644 tests/tcg/hexagon/test_vpmpyh.S
 create mode 100644 tests/tcg/hexagon/test_vspliceb.S

-- 
2.30.1



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

* [PATCH v2 01/10] target/hexagon: update MAINTAINERS for idef-parser
  2021-02-25 15:18 [PATCH v2 00/10] target/hexagon: introduce idef-parser Alessandro Di Federico via
@ 2021-02-25 15:18 ` Alessandro Di Federico via
  2021-02-25 20:46   ` Richard Henderson
  2021-02-25 15:18 ` [PATCH v2 02/10] target/hexagon: import README " Alessandro Di Federico via
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 30+ messages in thread
From: Alessandro Di Federico via @ 2021-02-25 15:18 UTC (permalink / raw)
  To: qemu-devel
  Cc: tsimpson, bcain, babush, nizzo, philmd, richard.henderson,
	Alessandro Di Federico

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

Signed-off-by: Alessandro Di Federico <ale@rev.ng>
---
 MAINTAINERS | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 9b2aa18e1f..9a6878b970 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -192,11 +192,19 @@ 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
 F: default-configs/targets/hexagon-linux-user.mak
 
+Hexagon idef-parser
+M: Alessandro Di Federico <ale@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.30.1



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

* [PATCH v2 02/10] target/hexagon: import README for idef-parser
  2021-02-25 15:18 [PATCH v2 00/10] target/hexagon: introduce idef-parser Alessandro Di Federico via
  2021-02-25 15:18 ` [PATCH v2 01/10] target/hexagon: update MAINTAINERS for idef-parser Alessandro Di Federico via
@ 2021-02-25 15:18 ` Alessandro Di Federico via
  2021-02-25 20:20   ` Richard Henderson
  2021-02-25 15:18 ` [PATCH v2 03/10] target/hexagon: make helper functions non-static Alessandro Di Federico via
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 30+ messages in thread
From: Alessandro Di Federico via @ 2021-02-25 15:18 UTC (permalink / raw)
  To: qemu-devel
  Cc: tsimpson, bcain, babush, nizzo, philmd, richard.henderson,
	Alessandro Di Federico

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

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

diff --git a/target/hexagon/README b/target/hexagon/README
index b0b2435070..2f2814380c 100644
--- a/target/hexagon/README
+++ b/target/hexagon/README
@@ -23,6 +23,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
@@ -43,6 +47,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..95377cc7e0
--- /dev/null
+++ b/target/hexagon/idef-parser/README.rst
@@ -0,0 +1,447 @@
+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;} */
+   {
+       tcg_gen_movi_i32(RdV, 0);
+       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.
+
+::
+
+   tcg_gen_movi_i32(RdV, 0);
+
+This code starts by initializing ``RdV``, since reading from that register
+without initialization will cause a segmentation fault by QEMU.  This is emitted
+because a declaration of the ``RdV`` register was parsed, but no reading of the
+``RdV`` register was found.
+
+::
+
+   TCGv_i32 tmp_0 = tcg_temp_new_i32();
+
+Then we are declaring a temporary TCGv to hold the result from the sum
+operation.
+
+::
+
+   tcg_gen_add_i32(tmp_0, RsV, RtV);
+
+Now we are actually 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 might not seem an efficient code, but QEMU
+will perform some tinycode optimization, reducing the unnecessary copy.
+
+::
+
+   tcg_temp_free_i32(tmp_0);
+
+Finally, we free the temporary we used to hold the addition result.
+
+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 code
+
+   code        : LBR decls statements decls RBR
+
+   statements  : statements statement
+               | statement
+
+   statement   : control_statement
+               | rvalue SEMI
+               | code_block
+               | SEMI
+
+   code_block  : LBR statements RBR
+               | LBR RBR
+
+With this initial portion of the grammar we are defining the instruction
+statements, which are enclosed by the declarations. Each statement can be a
+``control_statement``, a code block, which is just a bracket-enclosed list of
+statements, a ``SEMI``, which is a ``nop`` instruction, and an ``rvalue SEMI``.
+
+Expressions
+~~~~~~~~~~~
+
+``rvalue`` is the nonterminal representing expressions, which are everything
+that could be assigned to a variable. ``rvalue SEMI`` can be a statement on its
+own because the assign statement, just as in the C language, is itself an
+expression.
+
+``rvalue``\ s can be registers, immediates, predicates, control registers,
+variables, or any combination of other ``rvalue``\ s through operators. An
+``rvalue`` can be either an immediate or a TCGv, the actual type is determined
+by the ``t_hex_value.type`` field. In case it is an immediate, its combination
+with other immediates can be performed at compile-time (constant folding), only
+the result will be written into the code. If the ``rvalue`` instead is a TCGv,
+the operations performed on it will have to be emitted as tinycode instructions,
+therefore their result will be known only at runtime. An immediate can be copied
+into a TCGv through the ``rvalue_materialize`` function, which allocates a
+temporary TCGv and copies the value of the immediate in it. Each temporary
+should be freed after that it is no more used, we usually free both operands of
+each operator, in an SSA fashion.
+
+``lvalue``\ s instead represents all the variables which can be assigned to a
+value, and are specialized into registers and variables:
+
+::
+
+   lvalue        : REG
+                 | VAR
+
+The effective assignment of ``lvalue``\ s is handled by the ``gen_assign()``
+function.
+
+Automatic Variables
+~~~~~~~~~~~~~~~~~~~
+
+The input code can contain implicitly declared automatic variables, which are
+initialized with a value and then used. We performed a dedicated handling of
+such variables, because they will be matched by a generic ``VARID`` token, which
+will feature the variable name as a decoration. Each time that the variable is
+found, we have to check if that's the first variable use, in that case we
+declare a new automatic variable in the tinycode, which can be considered at all
+effects as an immediate. Special care is taken to make sure that each variable
+is declared only the first time it is seen. Furthermore the variable might
+inherit some characteristics like the signedness and the bit width, which must
+be propagated from the initialization of the variable to all the further uses of
+the variable.
+
+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.
+
+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 (``bool is_unsigned``).
+
+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 algebraic 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.
+
+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. 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 a 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 instruction 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.
+
+-  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.
+
+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 SEMI
+
+   rvalue                : rvalue QMARK rvalue COLON rvalue
+                         | rvalue EQ rvalue
+                         | LPAR rvalue RPAR
+                         | assign_statement
+                         | IMM
+
+   assign_statement      : pre 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.30.1



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

* [PATCH v2 03/10] target/hexagon: make helper functions non-static
  2021-02-25 15:18 [PATCH v2 00/10] target/hexagon: introduce idef-parser Alessandro Di Federico via
  2021-02-25 15:18 ` [PATCH v2 01/10] target/hexagon: update MAINTAINERS for idef-parser Alessandro Di Federico via
  2021-02-25 15:18 ` [PATCH v2 02/10] target/hexagon: import README " Alessandro Di Federico via
@ 2021-02-25 15:18 ` Alessandro Di Federico via
  2021-02-25 20:47   ` Richard Henderson
  2021-02-25 15:18 ` [PATCH v2 04/10] target/hexagon: introduce new helper functions Alessandro Di Federico via
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 30+ messages in thread
From: Alessandro Di Federico via @ 2021-02-25 15:18 UTC (permalink / raw)
  To: qemu-devel
  Cc: tsimpson, bcain, babush, nizzo, philmd, richard.henderson,
	Alessandro Di Federico

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.

Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Paolo Montesel <babush@rev.ng>
---
 target/hexagon/genptr.c | 13 ++++++++++---
 target/hexagon/genptr.h |  7 +++++++
 2 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index 7481f4c1dd..97de669f38 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -26,8 +26,15 @@
 #include "translate.h"
 #include "macros.h"
 #include "gen_tcg.h"
+#include "genptr.h"
 
-static inline TCGv gen_read_preg(TCGv pred, uint8_t num)
+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]);
     return pred;
@@ -53,7 +60,7 @@ static inline void gen_log_predicated_reg_write(int rnum, TCGv val, int slot)
     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)
 #endif
 }
 
-static inline void gen_log_pred_write(int pnum, TCGv val)
+void gen_log_pred_write(int pnum, TCGv val)
 {
     TCGv zero = tcg_const_tl(0);
     TCGv base_val = tcg_temp_new();
diff --git a/target/hexagon/genptr.h b/target/hexagon/genptr.h
index c158005d2a..0bfa99b463 100644
--- a/target/hexagon/genptr.h
+++ b/target/hexagon/genptr.h
@@ -19,7 +19,14 @@
 #define HEXAGON_GENPTR_H
 
 #include "insn.h"
+#include "tcg/tcg.h"
+#include "translate.h"
 
 extern const SemanticInsn opcode_genptr[];
 
+TCGv gen_read_reg(TCGv result, int num);
+TCGv gen_read_preg(TCGv pred, uint8_t num);
+void gen_log_reg_write(int rnum, TCGv val);
+void gen_log_pred_write(int pnum, TCGv val);
+
 #endif
-- 
2.30.1



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

* [PATCH v2 04/10] target/hexagon: introduce new helper functions
  2021-02-25 15:18 [PATCH v2 00/10] target/hexagon: introduce idef-parser Alessandro Di Federico via
                   ` (2 preceding siblings ...)
  2021-02-25 15:18 ` [PATCH v2 03/10] target/hexagon: make helper functions non-static Alessandro Di Federico via
@ 2021-02-25 15:18 ` Alessandro Di Federico via
  2021-02-25 20:45   ` Richard Henderson
  2021-02-25 15:18 ` [PATCH v2 05/10] target/hexagon: expose next PC in DisasContext Alessandro Di Federico via
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 30+ messages in thread
From: Alessandro Di Federico via @ 2021-02-25 15:18 UTC (permalink / raw)
  To: qemu-devel
  Cc: tsimpson, bcain, babush, nizzo, philmd, richard.henderson,
	Alessandro Di Federico

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

These helpers will be employed by the idef-parser generated code.

Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Niccolò Izzo <nizzo@rev.ng>
---
 target/hexagon/genptr.c | 227 +++++++++++++++++++++++++++++++++++++++-
 target/hexagon/genptr.h |  19 ++++
 target/hexagon/macros.h |   2 +-
 3 files changed, 245 insertions(+), 3 deletions(-)

diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index 97de669f38..78cda032db 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -40,7 +40,8 @@ TCGv gen_read_preg(TCGv pred, uint8_t num)
     return pred;
 }
 
-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,
+                                                unsigned slot)
 {
     TCGv one = tcg_const_tl(1);
     TCGv zero = tcg_const_tl(0);
@@ -69,7 +70,8 @@ void gen_log_reg_write(int rnum, TCGv val)
 #endif
 }
 
-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,
+                                              unsigned slot)
 {
     TCGv val32 = tcg_temp_new();
     TCGv one = tcg_const_tl(1);
@@ -334,5 +336,226 @@ static inline void gen_store_conditional8(CPUHexagonState *env,
     tcg_gen_movi_tl(hex_llsc_addr, ~0);
 }
 
+void gen_fbrev(TCGv result, TCGv src)
+{
+    TCGv lo = tcg_temp_new();
+    TCGv tmp1 = tcg_temp_new();
+    TCGv tmp2 = tcg_temp_new();
+
+    /* Bit reversal of low 16 bits */
+    tcg_gen_extract_tl(lo, src, 0, 16);
+    tcg_gen_andi_tl(tmp1, lo, 0xaaaa);
+    tcg_gen_shri_tl(tmp1, tmp1, 1);
+    tcg_gen_andi_tl(tmp2, lo, 0x5555);
+    tcg_gen_shli_tl(tmp2, tmp2, 1);
+    tcg_gen_or_tl(lo, tmp1, tmp2);
+    tcg_gen_andi_tl(tmp1, lo, 0xcccc);
+    tcg_gen_shri_tl(tmp1, tmp1, 2);
+    tcg_gen_andi_tl(tmp2, lo, 0x3333);
+    tcg_gen_shli_tl(tmp2, tmp2, 2);
+    tcg_gen_or_tl(lo, tmp1, tmp2);
+    tcg_gen_andi_tl(tmp1, lo, 0xf0f0);
+    tcg_gen_shri_tl(tmp1, tmp1, 4);
+    tcg_gen_andi_tl(tmp2, lo, 0x0f0f);
+    tcg_gen_shli_tl(tmp2, tmp2, 4);
+    tcg_gen_or_tl(lo, tmp1, tmp2);
+    tcg_gen_bswap16_tl(lo, lo);
+
+    /* Final tweaks */
+    tcg_gen_extract_tl(result, src, 16, 16);
+    tcg_gen_or_tl(result, result, lo);
+
+    tcg_temp_free(lo);
+    tcg_temp_free(tmp1);
+    tcg_temp_free(tmp2);
+}
+
+TCGv gen_set_bit(tcg_target_long i, TCGv result, TCGv src)
+{
+    TCGv mask = tcg_const_tl(~(1 << i));
+    TCGv bit = tcg_temp_new();
+    tcg_gen_shli_tl(bit, src, i);
+    tcg_gen_and_tl(result, result, mask);
+    tcg_gen_or_tl(result, result, bit);
+    tcg_temp_free(mask);
+    tcg_temp_free(bit);
+
+    return result;
+}
+
+void gen_cancel(tcg_target_ulong slot)
+{
+    TCGv one = tcg_const_tl(1);
+    tcg_gen_deposit_tl(hex_slot_cancelled, hex_slot_cancelled, one, slot, 1);
+    tcg_temp_free(one);
+}
+
+void gen_store32(TCGv vaddr, TCGv src, tcg_target_long width, unsigned 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);
+}
+
+void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
+                unsigned slot)
+{
+    gen_store32(vaddr, src, 1, slot);
+    ctx->store_width[slot] = 1;
+}
+
+void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
+                unsigned slot)
+{
+    gen_store32(vaddr, src, 2, slot);
+    ctx->store_width[slot] = 2;
+}
+
+void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
+                unsigned slot)
+{
+    gen_store32(vaddr, src, 4, slot);
+    ctx->store_width[slot] = 4;
+}
+
+
+void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src, DisasContext *ctx,
+                unsigned slot)
+{
+    tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
+    tcg_gen_movi_tl(hex_store_width[slot], 8);
+    tcg_gen_mov_i64(hex_store_val64[slot], src);
+    ctx->store_width[slot] = 8;
+}
+
+void gen_set_usr_field(int field, TCGv val)
+{
+    tcg_gen_deposit_tl(hex_gpr[HEX_REG_USR], hex_gpr[HEX_REG_USR], val,
+                       reg_field_info[field].offset,
+                       reg_field_info[field].width);
+}
+
+void gen_set_usr_fieldi(int field, int x)
+{
+    TCGv val = tcg_const_tl(x);
+    gen_set_usr_field(field, val);
+    tcg_temp_free(val);
+}
+
+void gen_write_new_pc(TCGv addr)
+{
+    /* If there are multiple branches in a packet, ignore the second one */
+    TCGv zero = tcg_const_tl(0);
+    tcg_gen_movcond_tl(TCG_COND_NE, hex_next_PC, hex_branch_taken, zero,
+                       hex_next_PC, addr);
+    tcg_gen_movi_tl(hex_branch_taken, 1);
+    tcg_temp_free(zero);
+}
+
+void gen_sat_i32(TCGv dest, TCGv source, int width, bool set_overflow)
+{
+    TCGv max_val = tcg_const_i32((1 << (width - 1)) - 1);
+    TCGv min_val = tcg_const_i32(-(1 << (width - 1)));
+    tcg_gen_movcond_i32(TCG_COND_GT, dest, source, max_val, max_val, source);
+    tcg_gen_movcond_i32(TCG_COND_LT, dest, source, min_val, min_val, dest);
+    /* Set Overflow Bit */
+    if (set_overflow) {
+        TCGv ovf = tcg_temp_new();
+        TCGv one = tcg_const_i32(1);
+        GET_USR_FIELD(USR_OVF, ovf);
+        tcg_gen_movcond_i32(TCG_COND_GT, ovf, source, max_val, one, ovf);
+        tcg_gen_movcond_i32(TCG_COND_LT, ovf, source, min_val, one, ovf);
+        SET_USR_FIELD(USR_OVF, ovf);
+        tcg_temp_free_i32(ovf);
+        tcg_temp_free_i32(one);
+    }
+    tcg_temp_free_i32(max_val);
+    tcg_temp_free_i32(min_val);
+}
+
+void gen_satu_i32(TCGv dest, TCGv source, int width, bool set_overflow)
+{
+    TCGv max_val = tcg_const_i32((1 << width) - 1);
+    tcg_gen_movcond_i32(TCG_COND_GTU, dest, source, max_val, max_val, source);
+    TCGv_i32 zero = tcg_const_i32(0);
+    tcg_gen_movcond_i32(TCG_COND_LT, dest, source, zero, zero, dest);
+    /* Set Overflow Bit */
+    if (set_overflow) {
+        TCGv ovf = tcg_temp_new();
+        TCGv one = tcg_const_i32(1);
+        GET_USR_FIELD(USR_OVF, ovf);
+        tcg_gen_movcond_i32(TCG_COND_GTU, ovf, source, max_val, one, ovf);
+        SET_USR_FIELD(USR_OVF, ovf);
+        tcg_temp_free_i32(ovf);
+        tcg_temp_free_i32(one);
+    }
+    tcg_temp_free_i32(max_val);
+    tcg_temp_free_i32(zero);
+}
+
+void gen_sat_i64(TCGv_i64 dest, TCGv_i64 source, int width, bool set_overflow)
+{
+    TCGv_i64 max_val = tcg_const_i64((1 << (width - 1)) - 1);
+    TCGv_i64 min_val = tcg_const_i64(-(1 << (width - 1)));
+    tcg_gen_movcond_i64(TCG_COND_GT, dest, source, max_val, max_val, source);
+    tcg_gen_movcond_i64(TCG_COND_LT, dest, source, min_val, min_val, dest);
+    /* Set Overflow Bit */
+    if (set_overflow) {
+        TCGv ovf = tcg_temp_new();
+        TCGv_i64 ovf_ext = tcg_temp_new_i64();
+        TCGv_i64 one = tcg_const_i64(1);
+        GET_USR_FIELD(USR_OVF, ovf);
+        tcg_gen_ext_i32_i64(ovf_ext, ovf);
+        tcg_gen_movcond_i64(TCG_COND_GT,
+                            ovf_ext,
+                            source,
+                            max_val,
+                            one,
+                            ovf_ext);
+        tcg_gen_movcond_i64(TCG_COND_LT,
+                            ovf_ext,
+                            source,
+                            min_val,
+                            one,
+                            ovf_ext);
+        tcg_gen_trunc_i64_tl(ovf, ovf_ext);
+        SET_USR_FIELD(USR_OVF, ovf);
+        tcg_temp_free_i32(ovf);
+        tcg_temp_free_i64(ovf_ext);
+        tcg_temp_free_i64(one);
+    }
+    tcg_temp_free_i64(max_val);
+    tcg_temp_free_i64(min_val);
+}
+
+void gen_satu_i64(TCGv_i64 dest, TCGv_i64 source, int width, bool set_overflow)
+{
+    TCGv_i64 max_val = tcg_const_i64((1 << width) - 1);
+    tcg_gen_movcond_i64(TCG_COND_GTU, dest, source, max_val, max_val, source);
+    TCGv_i64 zero = tcg_const_i64(0);
+    tcg_gen_movcond_i64(TCG_COND_LT, dest, source, zero, zero, dest);
+    /* Set Overflow Bit */
+    if (set_overflow) {
+        TCGv ovf = tcg_temp_new();
+        TCGv_i64 ovf_ext = tcg_temp_new_i64();
+        TCGv_i64 one = tcg_const_i64(1);
+        GET_USR_FIELD(USR_OVF, ovf);
+        tcg_gen_ext_i32_i64(ovf_ext, ovf);
+        tcg_gen_movcond_i64(TCG_COND_GTU,
+                            ovf_ext,
+                            source,
+                            max_val,
+                            one,
+                            ovf_ext);
+        tcg_gen_trunc_i64_tl(ovf, ovf_ext);
+        SET_USR_FIELD(USR_OVF, ovf);
+        tcg_temp_free_i32(ovf);
+        tcg_temp_free_i64(ovf_ext);
+        tcg_temp_free_i64(one);
+    }
+    tcg_temp_free_i64(max_val);
+    tcg_temp_free_i64(zero);
+}
+
 #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 0bfa99b463..86f5d5222e 100644
--- a/target/hexagon/genptr.h
+++ b/target/hexagon/genptr.h
@@ -28,5 +28,24 @@ TCGv gen_read_reg(TCGv result, int num);
 TCGv gen_read_preg(TCGv pred, uint8_t num);
 void gen_log_reg_write(int rnum, TCGv val);
 void gen_log_pred_write(int pnum, TCGv val);
+void gen_fbrev(TCGv result, TCGv src);
+void gen_cancel(tcg_target_ulong slot);
+TCGv gen_set_bit(tcg_target_long i, TCGv result, TCGv src);
+void gen_store32(TCGv vaddr, TCGv src, tcg_target_long width, unsigned slot);
+void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
+                unsigned slot);
+void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
+                unsigned slot);
+void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
+                unsigned slot);
+void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src, DisasContext *ctx,
+                unsigned slot);
+void gen_set_usr_field(int field, TCGv val);
+void gen_set_usr_fieldi(int field, int x);
+void gen_write_new_pc(TCGv addr);
+void gen_sat_i32(TCGv dest, TCGv source, int width, bool set_overflow);
+void gen_satu_i32(TCGv dest, TCGv source, int width, bool set_overflow);
+void gen_sat_i64(TCGv_i64 dest, TCGv_i64 source, int width, bool set_overflow);
+void gen_satu_i64(TCGv_i64 dest, TCGv_i64 source, int width, bool set_overflow);
 
 #endif
diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h
index 78c4efb5cb..7b6556b07b 100644
--- a/target/hexagon/macros.h
+++ b/target/hexagon/macros.h
@@ -154,7 +154,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, tcg_target_ulong slot_num)
  {
     TCGv slot_mask = tcg_const_tl(1 << slot_num);
     TCGv tmp = tcg_temp_new();
-- 
2.30.1



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

* [PATCH v2 05/10] target/hexagon: expose next PC in DisasContext
  2021-02-25 15:18 [PATCH v2 00/10] target/hexagon: introduce idef-parser Alessandro Di Federico via
                   ` (3 preceding siblings ...)
  2021-02-25 15:18 ` [PATCH v2 04/10] target/hexagon: introduce new helper functions Alessandro Di Federico via
@ 2021-02-25 15:18 ` Alessandro Di Federico via
  2021-02-25 20:48   ` Richard Henderson
  2021-02-25 15:18 ` [PATCH v2 06/10] target/hexagon: prepare input for the idef-parser Alessandro Di Federico via
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 30+ messages in thread
From: Alessandro Di Federico via @ 2021-02-25 15:18 UTC (permalink / raw)
  To: qemu-devel
  Cc: tsimpson, bcain, babush, nizzo, philmd, richard.henderson,
	Alessandro Di Federico

From: Paolo Montesel <babush@rev.ng>

Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Paolo Montesel <babush@rev.ng>
---
 target/hexagon/translate.c | 4 +++-
 target/hexagon/translate.h | 1 +
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index eeaad5f8ba..a59db485a3 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -503,11 +503,13 @@ 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(ctx, &pkt);
-        ctx->base.pc_next += pkt.encod_pkt_size_in_bytes;
+        ctx->base.pc_next = ctx->npc;
+        ctx->npc = 0;
     } else {
         gen_exception(HEX_EXCP_INVALID_PACKET);
         ctx->base.is_jmp = DISAS_NORETURN;
diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h
index 938f7fbb9f..2195e20f4b 100644
--- a/target/hexagon/translate.h
+++ b/target/hexagon/translate.h
@@ -36,6 +36,7 @@ typedef struct DisasContext {
     int preg_log_idx;
     uint8_t store_width[STORES_MAX];
     uint8_t s1_store_processed;
+    uint32_t npc;
 } DisasContext;
 
 static inline void ctx_log_reg_write(DisasContext *ctx, int rnum)
-- 
2.30.1



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

* [PATCH v2 06/10] target/hexagon: prepare input for the idef-parser
  2021-02-25 15:18 [PATCH v2 00/10] target/hexagon: introduce idef-parser Alessandro Di Federico via
                   ` (4 preceding siblings ...)
  2021-02-25 15:18 ` [PATCH v2 05/10] target/hexagon: expose next PC in DisasContext Alessandro Di Federico via
@ 2021-02-25 15:18 ` Alessandro Di Federico via
  2021-02-25 21:34   ` Richard Henderson
  2021-02-25 15:18 ` [PATCH v2 07/10] target/hexagon: import lexer for idef-parser Alessandro Di Federico via
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 30+ messages in thread
From: Alessandro Di Federico via @ 2021-02-25 15:18 UTC (permalink / raw)
  To: qemu-devel
  Cc: tsimpson, bcain, babush, nizzo, philmd, richard.henderson,
	Alessandro Di Federico

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>
---
 target/hexagon/gen_idef_parser_funcs.py | 114 ++++++++++++++++
 target/hexagon/idef-parser/macros.inc   | 166 ++++++++++++++++++++++++
 target/hexagon/idef-parser/prepare      |  33 +++++
 target/hexagon/meson.build              |  18 +++
 4 files changed, 331 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..6fb3659201
--- /dev/null
+++ b/target/hexagon/gen_idef_parser_funcs.py
@@ -0,0 +1,114 @@
+#!/usr/bin/env python3
+
+##
+##  Copyright(c) 2019-2020 rev.ng Srls. 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.read_overrides_file(sys.argv[3])
+    hex_common.calculate_attribs()
+    tagregs = hex_common.get_tagregs()
+    tagimms = hex_common.get_tagimms()
+
+    with open(sys.argv[4], '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
+            ## Skip other unsupported instructions
+            if ( tag.startswith('S2_cabacdecbin') ) :
+                continue
+            if ( tag.startswith('Y') ) :
+                continue
+            if ( tag.startswith('V6_') ) :
+                continue
+            if ( tag.startswith('F') ) :
+                continue
+            if ( tag.endswith('_locked') ) :
+                continue
+
+            regs = tagregs[tag]
+            imms = tagimms[tag]
+
+            arguments = []
+            if hex_common.need_ea(tag):
+                arguments.append("EA")
+
+            for regtype,regid,toss,numregs in regs:
+                prefix = "in " if hex_common.is_read(regid) else ""
+
+                is_pair = hex_common.is_pair(regid)
+                is_single_old = (hex_common.is_single(regid)
+                                 and hex_common.is_old_val(regtype, regid, tag))
+                is_single_new = (hex_common.is_single(regid)
+                                 and hex_common.is_new_val(regtype, regid, tag))
+
+                if is_pair or is_single_old:
+                    arguments.append("%s%s%sV" % (prefix, regtype, regid))
+                elif is_single_new:
+                    arguments.append("%s%s%sN" % (prefix, regtype, regid))
+                else:
+                    print("Bad register parse: ",regtype,regid,toss,numregs)
+
+            for immlett,bits,immshift in imms:
+                arguments.append(hex_common.imm_name(immlett))
+
+            f.write("%s(%s) {\n" % (tag, ", ".join(arguments)))
+            f.write("    %s\n" % hex_common.semdict[tag])
+            f.write("}\n\n")
+
+if __name__ == "__main__":
+    main()
diff --git a/target/hexagon/idef-parser/macros.inc b/target/hexagon/idef-parser/macros.inc
new file mode 100644
index 0000000000..719bebaee3
--- /dev/null
+++ b/target/hexagon/idef-parser/macros.inc
@@ -0,0 +1,166 @@
+/*
+ * Copyright(c) 2019-2020 rev.ng Srls. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* 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 fCAST8S_16S(A) (fSXTN(64, 128, A))
+#define fCAST16S_8S(A) (fSXTN(128, 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)))
+
+#define fCARRY_FROM_ADD(A, B, C)                                        \
+    fGETUWORD(1,                                                        \
+              fGETUWORD(1, A) +                                         \
+              fGETUWORD(1, B) +                                         \
+              fGETUWORD(1,                                              \
+                        fGETUWORD(0, A) +                               \
+                        fGETUWORD(0, B) + C))
+
+#define fADDSAT64(DST, A, B)                                            \
+        __a = fCAST8u(A);                                               \
+        __b = fCAST8u(B);                                               \
+        __sum = __a + __b;                                              \
+        __xor = __a ^ __b;                                              \
+        __mask = 0x8000000000000000ULL;                                 \
+        if (__xor & __mask) {                                           \
+            DST = __sum;                                                \
+        }                                                               \
+        else if ((__a ^ __sum) & __mask) {                              \
+            if (__sum & __mask) {                                       \
+                DST = 0x7FFFFFFFFFFFFFFFLL;                             \
+                fSET_OVERFLOW();                                        \
+            } else {                                                    \
+                DST = 0x8000000000000000ULL;                            \
+                fSET_OVERFLOW();                                        \
+            }                                                           \
+        } else {                                                        \
+            DST = __sum;                                                \
+        }
+
+/* Negation operator */
+#define fLSBOLDNOT(VAL) (!fGETBIT(0, VAL))
+#define fLSBNEWNOT(PNUM) (!fLSBNEW(PNUM))
+#define fLSBNEW0NOT (!fLSBNEW0)
+
+/* 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)
+#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 fADD128(A, B) (A + B)
+#define fSUB128(A, B) (A - B)
+#define fSHIFTR128(A, B) (size8s_t) (A >> B)
+#define fSHIFTL128(A, B) (A << B)
+#define fAND128(A, B) (A & B)
+#define fSCALE(N, A) (A << N)
+#define fASHIFTR(SRC, SHAMT, REGSTYPE) (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)
+
+/* Purge non-relavant parts */
+#define fHIDE(A)
+#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..a11a86dc01
--- /dev/null
+++ b/target/hexagon/idef-parser/prepare
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+#
+# Copyright(c) 2019-2020 rev.ng Srls. All Rights Reserved.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, see <http://www.gnu.org/licenses/>.
+#
+
+set -e
+set -o pipefail
+
+# 1. Run the preprocessor
+# 2. Transform
+#
+#        condition ? A = B : A = C
+#
+#    in
+#
+#        A = (condition ? B : C)
+#
+# 3. Remove comments (starting with "#")
+cpp "$@" | sed 's/\(\s*[{;]\)\s*\([^;?]*\) ? (\([^;=]*\)=\([^;)]*\))\s*:\s*([^;=]*=\([^;)]*\));/\1 \3 = (\2) ? \4 : \5;/' | grep -v '^#'
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index 15318a6fa7..2c18edf67a 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -20,6 +20,7 @@ hexagon_ss = ss.source_set()
 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'
+idef_parser_dir = meson.current_source_dir() / 'idef-parser'
 
 #
 #  Step 1
@@ -188,4 +189,21 @@ hexagon_ss.add(files(
     'conv_emu.c',
 ))
 
+idef_parser_input_generated = custom_target(
+    'idef_parser_input.h.inc',
+    output: 'idef_parser_input.h.inc',
+    input: 'gen_idef_parser_funcs.py',
+    depend_files: [hex_common_py],
+    command: [python, '@INPUT@', semantics_generated, attribs_def, gen_tcg_h, '@OUTPUT@'],
+)
+
+idef_parser_input_generated_prep = custom_target(
+    'idef_parser_input.preprocessed.h.inc',
+    output: 'idef_parser_input.preprocessed.h.inc',
+    input: idef_parser_input_generated,
+    capture: true,
+    depend_files: [hex_common_py],
+    command: [idef_parser_dir / 'prepare', '@INPUT@', '-I' + idef_parser_dir],
+)
+
 target_arch += {'hexagon': hexagon_ss}
-- 
2.30.1



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

* [PATCH v2 07/10] target/hexagon: import lexer for idef-parser
  2021-02-25 15:18 [PATCH v2 00/10] target/hexagon: introduce idef-parser Alessandro Di Federico via
                   ` (5 preceding siblings ...)
  2021-02-25 15:18 ` [PATCH v2 06/10] target/hexagon: prepare input for the idef-parser Alessandro Di Federico via
@ 2021-02-25 15:18 ` Alessandro Di Federico via
  2021-02-25 22:24   ` Richard Henderson
  2021-02-25 15:18 ` [PATCH v2 08/10] target/hexagon: import parser " Alessandro Di Federico via
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 30+ messages in thread
From: Alessandro Di Federico via @ 2021-02-25 15:18 UTC (permalink / raw)
  To: qemu-devel
  Cc: tsimpson, bcain, babush, nizzo, philmd, richard.henderson,
	Alessandro Di Federico

From: Paolo Montesel <babush@rev.ng>

Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Paolo Montesel <babush@rev.ng>
---
 target/hexagon/idef-parser/idef-parser.h      | 245 +++++++
 target/hexagon/idef-parser/idef-parser.lex    | 647 ++++++++++++++++++
 target/hexagon/meson.build                    |   4 +
 tests/docker/dockerfiles/alpine.docker        |   1 +
 tests/docker/dockerfiles/centos7.docker       |   1 +
 tests/docker/dockerfiles/centos8.docker       |   1 +
 tests/docker/dockerfiles/debian10.docker      |   1 +
 .../dockerfiles/fedora-i386-cross.docker      |   1 +
 .../dockerfiles/fedora-win32-cross.docker     |   1 +
 .../dockerfiles/fedora-win64-cross.docker     |   1 +
 tests/docker/dockerfiles/fedora.docker        |   1 +
 tests/docker/dockerfiles/opensuse-leap.docker |   1 +
 tests/docker/dockerfiles/ubuntu.docker        |   1 +
 tests/docker/dockerfiles/ubuntu1804.docker    |   1 +
 tests/docker/dockerfiles/ubuntu2004.docker    |   3 +-
 15 files changed, 909 insertions(+), 1 deletion(-)
 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..d08b9c80ea
--- /dev/null
+++ b/target/hexagon/idef-parser/idef-parser.h
@@ -0,0 +1,245 @@
+/*
+ * Copyright(c) 2019-2020 rev.ng Srls. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef IDEF_PARSER_H
+#define IDEF_PARSER_H
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdbool.h>
+
+#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 {                                                             \
+        (c)->out_c += snprintf((c)->out_buffer + (c)->out_c,         \
+                               OUT_BUF_LEN - (c)->out_c,             \
+                               __VA_ARGS__);                         \
+    } while (0)
+
+#define EMIT_SIG(c, ...)                                                       \
+    do {                                                                       \
+        (c)->signature_c += snprintf((c)->signature_buffer + (c)->signature_c, \
+                                     SIGNATURE_BUF_LEN - (c)->signature_c,     \
+                                     __VA_ARGS__);                             \
+    } while (0)
+
+#define EMIT_HEAD(c, ...)                                                      \
+    do {                                                                       \
+        (c)->header_c += snprintf((c)->header_buffer + (c)->header_c,          \
+                                     SIGNATURE_BUF_LEN - (c)->header_c,        \
+                                     __VA_ARGS__);                             \
+    } while (0)
+
+/**
+ * Type of register, assigned to the HexReg.type field
+ */
+typedef enum {GENERAL_PURPOSE, CONTROL, MODIFIER, DOTNEW} RegType;
+
+/**
+ * Types of control registers, assigned to the HexReg.id field
+ */
+typedef enum {SP, FP, LR, GP, LC0, LC1, SA0, SA1} CregType;
+
+/**
+ * Identifier string of the control registers, indexed by the CregType enum
+ */
+extern const char *creg_str[];
+
+/**
+ * Semantic record of the REG tokens, identifying registers
+ */
+typedef struct HexReg {
+    CregType id;            /**< Identifier of the register                  */
+    RegType type;           /**< Type of the register                        */
+    unsigned bit_width;     /**< Bit width of the reg, 32 or 64 bits         */
+} HexReg;
+
+/**
+ * Data structure, identifying a TCGv temporary value
+ */
+typedef struct HexTmp {
+    int index;              /**< Index of the TCGv temporary value    */
+} HexTmp;
+
+/**
+ * Enum of the possible immediated, an immediate is a value which is known
+ * at tinycode generation time, e.g. an integer value, not a TCGv
+ */
+enum ImmUnionTag {I, VARIABLE, VALUE, QEMU_TMP, IMM_PC, IMM_CONSTEXT};
+
+/**
+ * Semantic record of the IMM token, identifying an immediate constant
+ */
+typedef struct HexImm {
+    union {
+        char id;            /**< Identifier of the immediate                 */
+        uint64_t value;     /**< Immediate value (for VALUE type immediates) */
+        uint64_t index;     /**< Index of the immediate (for int temp vars)  */
+    };
+    enum ImmUnionTag type;  /**< Type of the immediate                      */
+} HexImm;
+
+/**
+ * Semantic record of the PRE token, identifying a predicate
+ */
+typedef struct HexPre {
+    char id;                /**< Identifier of the predicate                 */
+} HexPre;
+
+/**
+ * Semantic record of the SAT token, identifying the saturate operator
+ */
+typedef struct HexSat {
+    bool set_overflow;      /**< Set-overflow feature for the sat operator   */
+    bool is_unsigned;       /**< Unsigned flag for the saturate operator     */
+} HexSat;
+
+/**
+ * Semantic record of the CAST token, identifying the cast operator
+ */
+typedef struct HexCast {
+    int bit_width;          /**< Bit width of the cast operator              */
+    bool is_unsigned;       /**< Unsigned flag for the cast operator         */
+} HexCast;
+
+/**
+ * Semantic record of the EXTRACT token, identifying the cast operator
+ */
+typedef struct HexExtract {
+    int bit_width;          /**< Bit width of the extract operator           */
+    int storage_bit_width;  /**< Actual bit width of the extract operator    */
+    bool is_unsigned;       /**< Unsigned flag for the extract operator      */
+} HexExtract;
+
+/**
+ * Semantic record of the MPY token, identifying the fMPY multiplication
+ * operator
+ */
+typedef struct HexMpy {
+    int first_bit_width;    /**< Bit width of the first operand of fMPY op   */
+    int second_bit_width;   /**< Bit width of the second operand of fMPY     */
+    bool first_unsigned;    /**< Unsigned flag for the first operand of fMPY */
+    bool second_unsigned;   /**< Unsigned flag for second operand of fMPY    */
+} HexMpy;
+
+/**
+ * Semantic record of the VARID token, identifying automatic variables
+ * of the input language
+ */
+typedef struct HexVar {
+    char *name;             /**< Name of the VARID automatic variable        */
+} HexVar;
+
+/**
+ * Data structure uniquely identifying an automatic 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 {
+    char *name;             /**< Name of the VARID automatic variable        */
+    uint8_t bit_width;      /**< Bit width of the VARID automatic variable   */
+    bool is_unsigned;       /**< Unsigned flag for the VARID automatic var   */
+} Var;
+
+/**
+ * Enum of the possible rvalue types, used in the HexValue.type field
+ */
+enum RvalueUnionTag {REGISTER, TEMP, IMMEDIATE, PREDICATE, VARID};
+
+/**
+ * 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                    */
+        HexPre pre;      /**< rvalue of predicate type                    */
+        HexVar var;      /**< rvalue of automatic variable type           */
+    };
+    enum RvalueUnionTag type; /**< Type of the rvalue                        */
+    unsigned bit_width;     /**< Bit width of the rvalue                     */
+    bool is_unsigned;       /**< 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;
+
+/**
+ * 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
+ */
+enum OpType {ADD_OP, SUB_OP, MUL_OP, DIV_OP, ASL_OP, ASR_OP, LSR_OP, ANDB_OP,
+             ORB_OP, XORB_OP, ANDL_OP, MINI_OP, MAXI_OP, MOD_OP};
+
+/**
+ * Data structure including instruction specific information, to be cleared
+ * out after the compilation of each instruction
+ */
+typedef struct Inst {
+    char *name;                   /**< Name of the compiled instruction      */
+    char *code_begin;             /**< Beginning of instruction input code   */
+    char *code_end;               /**< End of instruction input code         */
+    int tmp_count;                /**< Index of the last declared TCGv temp  */
+    int qemu_tmp_count;           /**< Index of the last declared int temp   */
+    int if_count;                 /**< Index of the last declared if label   */
+    int error_count;              /**< Number of generated errors            */
+    Var allocated[ALLOC_LIST_LEN]; /**< Allocated VARID automatic vars       */
+    int allocated_count;          /**< Elements contained in allocated[]     */
+    HexValue init_list[INIT_LIST_LEN]; /**< List of initialized registers    */
+    int init_count;               /**< Number of members of init_list        */
+} 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      */
+    char *out_buffer;             /**< Buffer containing the output code     */
+    int out_c;                    /**< Characters emitted into out_buffer    */
+    char *signature_buffer;       /**< Buffer containing the signatures code */
+    int signature_c;              /**< Characters emitted into sig..._buffer */
+    char *header_buffer;          /**< Buffer containing the output code     */
+    int header_c;                 /**< Characters emitted into header buffer */
+    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    */
+    int total_insn;               /**< Number of instructions in input file  */
+    int implemented_insn;         /**< Instruction compiled without errors   */
+    Inst inst;                  /**< Parsing data of the current inst      */
+} Context;
+
+#endif /* IDEF_PARSER_H */
diff --git a/target/hexagon/idef-parser/idef-parser.lex b/target/hexagon/idef-parser/idef-parser.lex
new file mode 100644
index 0000000000..db27e9035f
--- /dev/null
+++ b/target/hexagon/idef-parser/idef-parser.lex
@@ -0,0 +1,647 @@
+%option noyywrap noinput nounput
+%option 8bit reentrant bison-bridge
+%option warn nodefault
+%option bison-locations
+
+%{
+/*
+ * Copyright(c) 2019-2020 rev.ng Srls. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <stdbool.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
+LOWER_PRE                d|s|t|u|v|e|x|x
+ZERO_ONE                 0|1
+IMM_ID                   r|s|S|u|U
+VAR_ID                   [a-zA-Z_][a-zA-Z0-9_]*
+SIGN_ID                  s|u
+
+/* Tokens */
+%%
+
+[ \t\f\v]+                { /* Ignore whitespaces. */ }
+[\n\r]+                   { /* Ignore newlines. */ }
+
+{INST_NAME}               { yylval->string = strdup(yytext);
+                            return INAME; }
+"fFLOAT"                 |
+"fUNFLOAT"               |
+"fDOUBLE"                |
+"fUNDOUBLE"              |
+"0.0"                    |
+"0x1.0p52"               |
+"0x1.0p-52"              { return FAIL; }
+"R"{REG_ID_32}"V" {
+                           yylval->rvalue.type = REGISTER;
+                           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;
+                           return REG; }
+"R"{REG_ID_32}"N" {
+                           yylval->rvalue.type = REGISTER;
+                           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;
+                           return REG; }
+"R"{REG_ID_64}"V" {
+                           yylval->rvalue.type = REGISTER;
+                           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;
+                           return REG; }
+"R"{REG_ID_64}"N" {
+                           yylval->rvalue.type = REGISTER;
+                           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;
+                           return REG; }
+"MuV" {
+                           yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = MODIFIER;
+                           yylval->rvalue.reg.id = 'u';
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           return REG; }
+"C"{REG_ID_32}"V" {
+                           yylval->rvalue.type = REGISTER;
+                           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;
+                           return REG; }
+"C"{REG_ID_64}"V" {
+                           yylval->rvalue.type = REGISTER;
+                           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;
+                           return REG; }
+{IMM_ID}"iV" {
+                           yylval->rvalue.type = IMMEDIATE;
+                           yylval->rvalue.is_unsigned = false;
+                           yylval->rvalue.imm.type = VARIABLE;
+                           yylval->rvalue.imm.id = yytext[0];
+                           yylval->rvalue.is_dotnew = false;
+                           return IMM; }
+"P"{LOWER_PRE}"V" {
+                           yylval->rvalue.type = PREDICATE;
+                           yylval->rvalue.pre.id = yytext[1];
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.is_dotnew = false;
+                           return PRE; }
+"P"{LOWER_PRE}"N" {
+                           yylval->rvalue.type = PREDICATE;
+                           yylval->rvalue.pre.id = yytext[1];
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.is_dotnew = true;
+                           return PRE; }
+"in R"{REG_ID_32}"V" {
+                           yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = GENERAL_PURPOSE;
+                           yylval->rvalue.reg.id = yytext[4];
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.is_dotnew = false;
+                           return RREG; }
+"in R"{REG_ID_64}"V" {
+                           yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = GENERAL_PURPOSE;
+                           yylval->rvalue.reg.id = yytext[4];
+                           yylval->rvalue.reg.bit_width = 64;
+                           yylval->rvalue.bit_width = 64;
+                           yylval->rvalue.is_dotnew = false;
+                           return RREG; }
+"in N"{REG_ID_32}"N" {
+                           yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = DOTNEW;
+                           yylval->rvalue.reg.id = yytext[4];
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.is_dotnew = true;
+                           return RREG; }
+"in N"{REG_ID_64}"N" {
+                           yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = DOTNEW;
+                           yylval->rvalue.reg.id = yytext[4];
+                           yylval->rvalue.reg.bit_width = 64;
+                           yylval->rvalue.bit_width = 64;
+                           yylval->rvalue.is_dotnew = true;
+                           return RREG; }
+"in P"{LOWER_PRE}"V" {
+                           yylval->rvalue.type = PREDICATE;
+                           yylval->rvalue.pre.id = yytext[4];
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.is_dotnew = false;
+                           return RPRE; }
+"in P"{LOWER_PRE}"N" {
+                           yylval->rvalue.type = PREDICATE;
+                           yylval->rvalue.pre.id = yytext[4];
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.is_dotnew = true;
+                           return RPRE; }
+"in MuV" {
+                           yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = MODIFIER;
+                           yylval->rvalue.reg.id = 'u';
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           return RREG; }
+"in C"{REG_ID_32}"V" {
+                           yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = CONTROL;
+                           yylval->rvalue.reg.id = yytext[4];
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.is_dotnew = false;
+                           return RREG; }
+"in C"{REG_ID_64}"V" {
+                           yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = CONTROL;
+                           yylval->rvalue.reg.id = yytext[4];
+                           yylval->rvalue.reg.bit_width = 64;
+                           yylval->rvalue.bit_width = 64;
+                           yylval->rvalue.is_dotnew = false;
+                           return RREG; }
+"fGEN_TCG_"{INST_NAME}"(" { return FWRAP; }
+"(unsigned int)"         { /* Skip c-style casts */ }
+"{"                      { return LBR; }
+"}"                      { return RBR; }
+"["                      { return LSQ; }
+"]"                      { return RSQ; }
+"("                      { return LPAR; }
+")"                      { return RPAR; }
+"IV1DEAD()"              |
+"fPAUSE(uiV);"           |
+";"                      { return SEMI; }
+":"                      { return COLON; }
+"+"                      { return PLUS; }
+"-"                      { return MINUS; }
+"*"                      { return MUL; }
+"**"                     { return POW; }
+"/"                      { return DIV; }
+"%"                      { return MOD; }
+"&"                      { return AND; }
+"|"                      { return OR; }
+"^"                      { return XOR; }
+"~"                      { return NOT; }
+"="                      { return ASSIGN; }
+"+="                     { return INC; }
+"-="                     { return DEC; }
+"++"                     { return PLUSPLUS; }
+"&="                     { return ANDA; }
+"|="                     { return ORA; }
+"^="                     { return XORA; }
+"<"                      { return LT; }
+">"                      { return GT; }
+"<<"                     { return ASL; }
+">>"                     { return ASR; }
+">>>"                    { return LSR; }
+"=="                     { return EQ; }
+"!="                     { return NEQ; }
+"<="                     { return LTE; }
+">="                     { return GTE; }
+"&&"                     { return ANDL; }
+"||"                     { return ORL; }
+"!"                      { return NOTL; }
+","                      { return COMMA; }
+"else"                   { return ELSE; }
+"for"                    { return FOR; }
+"fREAD_IREG"             { return ICIRC; }
+"fPART1"                 { return PART1; }
+"if"                     { return IF; }
+"fFRAME_SCRAMBLE"        { return FSCR; }
+"fFRAME_UNSCRAMBLE"      { return FSCR; }
+"fFRAMECHECK"            { return FCHK; }
+"Constant_extended"      { return CONSTEXT; }
+"fCL1_"{DIGIT}           { return LOCNT; }
+"fBREV_8"                { return BREV_8; }
+"fBREV_4"                { return BREV_4; }
+"fbrev"                  { return BREV; }
+"fSXTN"                  { return SXT; }
+"fZXTN"                  { return ZXT; }
+"fDF_MAX"                |
+"fSF_MAX"                |
+"fMAX"                   { return MAX; }
+"fDF_MIN"                |
+"fSF_MIN"                |
+"fMIN"                   { return MIN; }
+"fABS"                   { return ABS; }
+"fRNDN"                  { return ROUND; }
+"fCRND"                  { return CROUND; }
+"fCRNDN"                 { return CROUND; }
+"fPM_CIRI"               { return CIRCADD; }
+"fPM_CIRR"               { return CIRCADD; }
+"fCOUNTONES_"{DIGIT}     { return COUNTONES; }
+"fSATN"                  { yylval->sat.set_overflow = false;
+                           yylval->sat.is_unsigned = false;
+                           return SAT; }
+"fVSATN"                 { yylval->sat.set_overflow = true;
+                           yylval->sat.is_unsigned = false;
+                           return SAT; }
+"fSATUN"                 { yylval->sat.set_overflow = false;
+                           yylval->sat.is_unsigned = true;
+                           return SAT; }
+"fVSATUN"                { yylval->sat.set_overflow = true;
+                           yylval->sat.is_unsigned = true;
+                           return SAT; }
+"fSE32_64"               { yylval->cast.bit_width = 64;
+                           yylval->cast.is_unsigned = false;
+                           return CAST; }
+"fCAST4_4u"              { yylval->cast.bit_width = 32;
+                           yylval->cast.is_unsigned = true;
+                           return CAST; }
+"fCAST4_8s"              { yylval->cast.bit_width = 64;
+                           yylval->cast.is_unsigned = false;
+                           return CAST; }
+"fCAST4_8u"              { return CAST4_8U; }
+"fCAST4u"                { yylval->cast.bit_width = 32;
+                           yylval->cast.is_unsigned = true;
+                           return CAST; }
+"fCAST4s"                { yylval->cast.bit_width = 32;
+                           yylval->cast.is_unsigned = false;
+                           return CAST; }
+"fCAST8_8u"              { yylval->cast.bit_width = 64;
+                           yylval->cast.is_unsigned = true;
+                           return CAST; }
+"fCAST8u"                { yylval->cast.bit_width = 64;
+                           yylval->cast.is_unsigned = true;
+                           return CAST; }
+"fCAST8s"                { yylval->cast.bit_width = 64;
+                           yylval->cast.is_unsigned = false;
+                           return CAST; }
+"fGETBIT"                { yylval->extract.bit_width = 1;
+                           yylval->extract.storage_bit_width = 1;
+                           yylval->extract.is_unsigned = true;
+                           return EXTRACT; }
+"fGETBYTE"               { yylval->extract.bit_width = 8;
+                           yylval->extract.storage_bit_width = 8;
+                           yylval->extract.is_unsigned = false;
+                           return EXTRACT; }
+"fGETUBYTE"              { yylval->extract.bit_width = 8;
+                           yylval->extract.storage_bit_width = 8;
+                           yylval->extract.is_unsigned = true;
+                           return EXTRACT; }
+"fGETHALF"               { yylval->extract.bit_width = 16;
+                           yylval->extract.storage_bit_width = 16;
+                           yylval->extract.is_unsigned = false;
+                           return EXTRACT; }
+"fGETUHALF"              { yylval->extract.bit_width = 16;
+                           yylval->extract.storage_bit_width = 16;
+                           yylval->extract.is_unsigned = true;
+                           return EXTRACT; }
+"fGETWORD"               { yylval->extract.bit_width = 32;
+                           yylval->extract.storage_bit_width = 64;
+                           yylval->extract.is_unsigned = false;
+                           return EXTRACT; }
+"fGETUWORD"              { yylval->extract.bit_width = 32;
+                           yylval->extract.storage_bit_width = 64;
+                           yylval->extract.is_unsigned = true;
+                           return EXTRACT; }
+"fEXTRACTU_BITS"         { return EXTBITS; }
+"fEXTRACTU_RANGE"        { return EXTRANGE; }
+"fSETBIT"                { yylval->cast.bit_width = 1;
+                           yylval->cast.is_unsigned = false;
+                           return DEPOSIT; }
+"fSETBYTE"               { yylval->cast.bit_width = 8;
+                           yylval->cast.is_unsigned = false;
+                           return DEPOSIT; }
+"fSETHALF"               { yylval->cast.bit_width = 16;
+                           yylval->cast.is_unsigned = false;
+                           return SETHALF; }
+"fSETWORD"               { yylval->cast.bit_width = 32;
+                           yylval->cast.is_unsigned = false;
+                           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_unsigned = true;
+                           yylval->mpy.second_unsigned = true;
+                           return MPY; }
+"fMPY8US"                { yylval->mpy.first_bit_width = 8;
+                           yylval->mpy.second_bit_width = 8;
+                           yylval->mpy.first_unsigned = true;
+                           yylval->mpy.second_unsigned = false;
+                           return MPY; }
+"fMPY8SU"                { yylval->mpy.first_bit_width = 8;
+                           yylval->mpy.second_bit_width = 8;
+                           yylval->mpy.first_unsigned = false;
+                           yylval->mpy.second_unsigned = true;
+                           return MPY; }
+"fMPY8SS"                { yylval->mpy.first_bit_width = 8;
+                           yylval->mpy.second_bit_width = 8;
+                           yylval->mpy.first_unsigned = false;
+                           yylval->mpy.second_unsigned = false;
+                           return MPY; }
+"fMPY16UU"               { yylval->mpy.first_bit_width = 16;
+                           yylval->mpy.second_bit_width = 16;
+                           yylval->mpy.first_unsigned = true;
+                           yylval->mpy.second_unsigned = true;
+                           return MPY; }
+"fMPY16US"               { yylval->mpy.first_bit_width = 16;
+                           yylval->mpy.second_bit_width = 16;
+                           yylval->mpy.first_unsigned = true;
+                           yylval->mpy.second_unsigned = false;
+                           return MPY; }
+"fMPY16SU"               { yylval->mpy.first_bit_width = 16;
+                           yylval->mpy.second_bit_width = 16;
+                           yylval->mpy.first_unsigned = false;
+                           yylval->mpy.second_unsigned = true;
+                           return MPY; }
+"fMPY16SS"               { yylval->mpy.first_bit_width = 16;
+                           yylval->mpy.second_bit_width = 16;
+                           yylval->mpy.first_unsigned = false;
+                           yylval->mpy.second_unsigned = false;
+                           return MPY; }
+"fMPY32UU"               { yylval->mpy.first_bit_width = 32;
+                           yylval->mpy.second_bit_width = 32;
+                           yylval->mpy.first_unsigned = true;
+                           yylval->mpy.second_unsigned = true;
+                           return MPY; }
+"fMPY32US"               { yylval->mpy.first_bit_width = 32;
+                           yylval->mpy.second_bit_width = 32;
+                           yylval->mpy.first_unsigned = true;
+                           yylval->mpy.second_unsigned = false;
+                           return MPY; }
+"fMPY32SU"               { yylval->mpy.first_bit_width = 32;
+                           yylval->mpy.second_bit_width = 32;
+                           yylval->mpy.first_unsigned = false;
+                           yylval->mpy.second_unsigned = true;
+                           return MPY; }
+"fSFMPY"                 |
+"fMPY32SS"               { yylval->mpy.first_bit_width = 32;
+                           yylval->mpy.second_bit_width = 32;
+                           yylval->mpy.first_unsigned = false;
+                           yylval->mpy.second_unsigned = false;
+                           return MPY; }
+"fMPY3216SS"             { yylval->mpy.first_bit_width = 32;
+                           yylval->mpy.second_bit_width = 16;
+                           yylval->mpy.first_unsigned = false;
+                           yylval->mpy.second_unsigned = false;
+                           return MPY; }
+"fMPY3216SU"             { yylval->mpy.first_bit_width = 32;
+                           yylval->mpy.second_bit_width = 16;
+                           yylval->mpy.first_unsigned = false;
+                           yylval->mpy.second_unsigned = true;
+                           return MPY; }
+"fNEWREG"                |
+"fNEWREG_ST"             |
+"fIMMEXT"                |
+"fMUST_IMMEXT"           |
+"fCAST2_2s"              |
+"fCAST2_2u"              |
+"fCAST4_4s"              |
+"fCAST8_8s"              |
+"fZE8_16"                |
+"fSE8_16"                |
+"fZE16_32"               |
+"fSE16_32"               |
+"fZE32_64"               |
+"fPASS"                  |
+"fECHO"                  { return IDENTITY; }
+"(size8"[us]"_t)"        { yylval->cast.bit_width = 8;
+                           yylval->cast.is_unsigned = ((yytext[6]) == 'u');
+                           return CAST; }
+"(size16"[us]"_t)"       { yylval->cast.bit_width = 16;
+                           yylval->cast.is_unsigned = ((yytext[7]) == 'u');
+                           return CAST; }
+"(int)"                  { yylval->cast.bit_width = 32;
+                           yylval->cast.is_unsigned = false;
+                           return CAST; }
+"?"                      { return QMARK; }
+"fREAD_PC()"             |
+"PC"                     { return PC; }
+"fREAD_NPC()"            |
+"NPC"                    { return NPC; }
+"fGET_LPCFG"             |
+"USR.LPCFG"              { return LPCFG; }
+"LOAD_CANCEL(EA)"        |
+"STORE_CANCEL(EA)"       |
+"CANCEL"                 { return CANC; }
+"N"{LOWER_ID}            { yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = GENERAL_PURPOSE;
+                           yylval->rvalue.reg.id = yytext[1];
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           return REG; }
+"N"{LOWER_ID}"N"         { yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = DOTNEW;
+                           yylval->rvalue.reg.id = yytext[1];
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           return REG; }
+[rR]{DIGIT}+             { yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = GENERAL_PURPOSE;
+                           yylval->rvalue.reg.id = atoi(yytext + 1);
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           return REG; }
+"fREAD_SP()"             |
+"SP"                     { yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = CONTROL;
+                           yylval->rvalue.reg.id = SP;
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           return REG; }
+"fREAD_FP()"             |
+"FP"                     { yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = CONTROL;
+                           yylval->rvalue.reg.id = FP;
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           return REG; }
+"fREAD_LR()"             |
+"LR"                     { yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = CONTROL;
+                           yylval->rvalue.reg.id = LR;
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           return REG; }
+"GP"                     { yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = CONTROL;
+                           yylval->rvalue.reg.id = GP;
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           return REG; }
+"fREAD_LC"{ZERO_ONE}     { yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = CONTROL;
+                           yylval->rvalue.reg.id = LC0 + atoi(yytext + 8);
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           return REG; }
+"LC"{ZERO_ONE}           { yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = CONTROL;
+                           yylval->rvalue.reg.id = LC0 + atoi(yytext + 2);
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           return REG; }
+"fREAD_SA"{ZERO_ONE}     { yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = CONTROL;
+                           yylval->rvalue.reg.id = SA0 + atoi(yytext + 8);
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           return REG; }
+"SA"{ZERO_ONE}           { yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = CONTROL;
+                           yylval->rvalue.reg.id = SA0 + atoi(yytext + 2);
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           return REG; }
+"MuN"                    { return MUN; }
+"fREAD_P0()"             { yylval->rvalue.type = PREDICATE;
+                           yylval->rvalue.pre.id = '0';
+                           yylval->rvalue.bit_width = 32;
+                           return PRE; }
+[pP]{DIGIT}              { yylval->rvalue.type = PREDICATE;
+                           yylval->rvalue.pre.id = yytext[1];
+                           yylval->rvalue.bit_width = 32;
+                           return PRE; }
+"fLSBNEW(P"{LOWER_PRE}"N)" { yylval->rvalue.type = PREDICATE;
+                           yylval->rvalue.pre.id = yytext[9];
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.is_dotnew = true;
+                           return PRE; }
+"fLSBNEW0"               { yylval->rvalue.type = PREDICATE;
+                           yylval->rvalue.pre.id = '0';
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.is_dotnew = true;
+                           return PRE; }
+"fLSBNEW1"               { yylval->rvalue.type = PREDICATE;
+                           yylval->rvalue.pre.id = '1';
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.is_dotnew = true;
+                           return PRE; }
+"fLSBNEW1NOT"            { yylval->rvalue.type = PREDICATE;
+                           yylval->rvalue.pre.id = '1';
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.is_dotnew = true;
+                           return PRE; }
+"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.imm.type = I;
+                           return IMM; }
+{SIGN_ID}                { yylval->is_unsigned = (yytext[0] == 'u');
+                           return SIGN;
+                         }
+"fSF_BIAS()"             { yylval->rvalue.type = IMMEDIATE;
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.is_unsigned = false;
+                           yylval->rvalue.imm.type = VALUE;
+                           yylval->rvalue.imm.value = 127;
+                           return IMM; }
+{DIGIT}+                 { yylval->rvalue.type = IMMEDIATE;
+                           yylval->rvalue.bit_width = 64;
+                           yylval->rvalue.is_unsigned = false;
+                           yylval->rvalue.imm.type = VALUE;
+                           yylval->rvalue.imm.value = atoi(yytext);
+                           return IMM; }
+{DIGIT}+"LL"             { yylval->rvalue.type = IMMEDIATE;
+                           yylval->rvalue.bit_width = 64;
+                           yylval->rvalue.is_unsigned = false;
+                           yylval->rvalue.imm.type = VALUE;
+                           yylval->rvalue.imm.value = atoi(yytext);
+                           return IMM; }
+"0x"{HEX_DIGIT}+         { yylval->rvalue.type = IMMEDIATE;
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.is_unsigned = false;
+                           yylval->rvalue.imm.type = VALUE;
+                           yylval->rvalue.imm.value = strtol(yytext, NULL, 16);
+                           return IMM; }
+"0x"{HEX_DIGIT}+"LL"     { yylval->rvalue.type = IMMEDIATE;
+                           yylval->rvalue.bit_width = 64;
+                           yylval->rvalue.is_unsigned = false;
+                           yylval->rvalue.imm.type = VALUE;
+                           yylval->rvalue.imm.value = strtol(yytext, NULL, 16);
+                           return IMM; }
+"0x"{HEX_DIGIT}+"ULL"    { yylval->rvalue.type = IMMEDIATE;
+                           yylval->rvalue.bit_width = 64;
+                           yylval->rvalue.is_unsigned = true;
+                           yylval->rvalue.imm.type = VALUE;
+                           yylval->rvalue.imm.value = strtoul(yytext, NULL, 16);
+                           return IMM; }
+"fCONSTLL"               { return CONSTLL; }
+"fCONSTULL"              { return CONSTULL; }
+"fLOAD"                  { return LOAD; }
+"fSTORE"                 { return STORE; }
+"fROTL"                  { return ROTL; }
+"fSET_OVERFLOW"          { return SETOVF; }
+"fDEINTERLEAVE"          { return DEINTERLEAVE; }
+"fINTERLEAVE"            { return INTERLEAVE; }
+{VAR_ID}                 { /* Variable name, we adopt the C names convention */
+                           yylval->rvalue.type = VARID;
+                           yylval->rvalue.var.name = strndup(yytext,
+                                                             ALLOC_NAME_SIZE);
+                           /* Default types are int */
+                           yylval->rvalue.bit_width = 32;
+                           if (yylval->rvalue.var.name == NULL) {
+                               fprintf(stderr,
+                                       "Error: failed to duplicate var name: "
+                                       "\"%s\"\n",
+                                       yytext);
+                               error_count++;
+                               return -1; /* invalid token */
+                           }
+                           return VAR; }
+"fHINTJR(RsV)"           { /* Emit no token */ }
+.                        { fprintf(stderr,
+                                   "Error: unexpected token \"%s\"\n",
+                                   yytext);
+                           error_count++;
+                           return -1; /* invalid token */
+                         }
+
+%%
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index 2c18edf67a..5dda04dc29 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -206,4 +206,8 @@ idef_parser_input_generated_prep = custom_target(
     command: [idef_parser_dir / 'prepare', '@INPUT@', '-I' + idef_parser_dir],
 )
 
+flex = generator(find_program('flex'),
+                 output: ['@BASENAME@.yy.c', '@BASENAME@.yy.h'],
+                 arguments: ['-o', '@OUTPUT0@', '--header-file=@OUTPUT1@', '@INPUT@'])
+
 target_arch += {'hexagon': hexagon_ss}
diff --git a/tests/docker/dockerfiles/alpine.docker b/tests/docker/dockerfiles/alpine.docker
index d63a269aef..1120e8555d 100644
--- a/tests/docker/dockerfiles/alpine.docker
+++ b/tests/docker/dockerfiles/alpine.docker
@@ -11,6 +11,7 @@ ENV PACKAGES \
 	binutils \
 	coreutils \
 	curl-dev \
+	flex \
 	g++ \
 	gcc \
 	git \
diff --git a/tests/docker/dockerfiles/centos7.docker b/tests/docker/dockerfiles/centos7.docker
index 75fdb53c7c..95966ea7e6 100644
--- a/tests/docker/dockerfiles/centos7.docker
+++ b/tests/docker/dockerfiles/centos7.docker
@@ -10,6 +10,7 @@ ENV PACKAGES \
     ccache \
     csnappy-devel \
     dbus-daemon \
+    flex \
     gcc-c++ \
     gcc \
     gettext \
diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker
index a763d55730..5919aa0697 100644
--- a/tests/docker/dockerfiles/centos8.docker
+++ b/tests/docker/dockerfiles/centos8.docker
@@ -7,6 +7,7 @@ ENV PACKAGES \
     bzip2-devel \
     dbus-daemon \
     diffutils \
+    flex \
     gcc \
     gcc-c++ \
     genisoimage \
diff --git a/tests/docker/dockerfiles/debian10.docker b/tests/docker/dockerfiles/debian10.docker
index 9d42b5a4b8..5a1c902d45 100644
--- a/tests/docker/dockerfiles/debian10.docker
+++ b/tests/docker/dockerfiles/debian10.docker
@@ -23,6 +23,7 @@ RUN apt update && \
         ccache \
         clang \
         dbus \
+        flex \
         gdb-multiarch \
         gettext \
         git \
diff --git a/tests/docker/dockerfiles/fedora-i386-cross.docker b/tests/docker/dockerfiles/fedora-i386-cross.docker
index a6e411291b..768bc1c9df 100644
--- a/tests/docker/dockerfiles/fedora-i386-cross.docker
+++ b/tests/docker/dockerfiles/fedora-i386-cross.docker
@@ -3,6 +3,7 @@ ENV PACKAGES \
     bzip2 \
     diffutils \
     findutils \
+    flex \
     gcc \
     git \
     libtasn1-devel.i686 \
diff --git a/tests/docker/dockerfiles/fedora-win32-cross.docker b/tests/docker/dockerfiles/fedora-win32-cross.docker
index 087df598a0..f75aea6c22 100644
--- a/tests/docker/dockerfiles/fedora-win32-cross.docker
+++ b/tests/docker/dockerfiles/fedora-win32-cross.docker
@@ -6,6 +6,7 @@ ENV PACKAGES \
     bzip2 \
     diffutils \
     findutils \
+    flex \
     gcc \
     gettext \
     git \
diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker
index d5d2f5f00d..e9b9e19be7 100644
--- a/tests/docker/dockerfiles/fedora-win64-cross.docker
+++ b/tests/docker/dockerfiles/fedora-win64-cross.docker
@@ -6,6 +6,7 @@ ENV PACKAGES \
     bzip2 \
     diffutils \
     findutils \
+    flex \
     gcc \
     gettext \
     git \
diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker
index 0d7602abbe..b656d8bab8 100644
--- a/tests/docker/dockerfiles/fedora.docker
+++ b/tests/docker/dockerfiles/fedora.docker
@@ -14,6 +14,7 @@ ENV PACKAGES \
     device-mapper-multipath-devel \
     diffutils \
     findutils \
+    flex \
     gcc \
     gcc-c++ \
     genisoimage \
diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker
index 0e64893e4a..ce1db959a2 100644
--- a/tests/docker/dockerfiles/opensuse-leap.docker
+++ b/tests/docker/dockerfiles/opensuse-leap.docker
@@ -6,6 +6,7 @@ ENV PACKAGES \
     brlapi-devel \
     bzip2 \
     cyrus-sasl-devel \
+    flex \
     gcc \
     gcc-c++ \
     mkisofs \
diff --git a/tests/docker/dockerfiles/ubuntu.docker b/tests/docker/dockerfiles/ubuntu.docker
index b5ef7a8198..e2f55eb892 100644
--- a/tests/docker/dockerfiles/ubuntu.docker
+++ b/tests/docker/dockerfiles/ubuntu.docker
@@ -14,6 +14,7 @@ ENV PACKAGES \
     ccache \
     clang \
     dbus \
+    flex \
     gcc \
     gettext \
     git \
diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker
index 9b0a19ba5e..2068118180 100644
--- a/tests/docker/dockerfiles/ubuntu1804.docker
+++ b/tests/docker/dockerfiles/ubuntu1804.docker
@@ -2,6 +2,7 @@ FROM ubuntu:18.04
 ENV PACKAGES \
     ccache \
     clang \
+    flex \
     gcc \
     gettext \
     git \
diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker
index 9750016e51..13d43a7b90 100644
--- a/tests/docker/dockerfiles/ubuntu2004.docker
+++ b/tests/docker/dockerfiles/ubuntu2004.docker
@@ -1,8 +1,9 @@
 FROM ubuntu:20.04
-ENV PACKAGES flex bison \
+ENV PACKAGES bison \
     bsdmainutils \
     ccache \
     clang-10\
+    flex \
     gcc \
     gcovr \
     genisoimage \
-- 
2.30.1



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

* [PATCH v2 08/10] target/hexagon: import parser for idef-parser
  2021-02-25 15:18 [PATCH v2 00/10] target/hexagon: introduce idef-parser Alessandro Di Federico via
                   ` (6 preceding siblings ...)
  2021-02-25 15:18 ` [PATCH v2 07/10] target/hexagon: import lexer for idef-parser Alessandro Di Federico via
@ 2021-02-25 15:18 ` Alessandro Di Federico via
  2021-02-26  3:30   ` Richard Henderson
  2021-02-25 15:18 ` [PATCH v2 09/10] target/hexagon: call idef-parser functions Alessandro Di Federico via
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 30+ messages in thread
From: Alessandro Di Federico via @ 2021-02-25 15:18 UTC (permalink / raw)
  To: qemu-devel
  Cc: tsimpson, bcain, babush, nizzo, philmd, richard.henderson,
	Alessandro Di Federico

From: Paolo Montesel <babush@rev.ng>

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

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



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

* [PATCH v2 09/10] target/hexagon: call idef-parser functions
  2021-02-25 15:18 [PATCH v2 00/10] target/hexagon: introduce idef-parser Alessandro Di Federico via
                   ` (7 preceding siblings ...)
  2021-02-25 15:18 ` [PATCH v2 08/10] target/hexagon: import parser " Alessandro Di Federico via
@ 2021-02-25 15:18 ` Alessandro Di Federico via
  2021-02-26  3:47   ` Richard Henderson
  2021-02-25 15:18 ` [PATCH v2 10/10] target/hexagon: import additional tests Alessandro Di Federico via
  2021-02-25 16:03 ` [PATCH v2 00/10] target/hexagon: introduce idef-parser no-reply
  10 siblings, 1 reply; 30+ messages in thread
From: Alessandro Di Federico via @ 2021-02-25 15:18 UTC (permalink / raw)
  To: qemu-devel
  Cc: tsimpson, bcain, babush, nizzo, philmd, richard.henderson,
	Alessandro Di Federico

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.

Signed-off-by: Alessandro Di Federico <ale@rev.ng>
---
 target/hexagon/gen_tcg_funcs.py | 28 ++++++++++++++++++++++++++--
 target/hexagon/hex_common.py    | 10 ++++++++++
 target/hexagon/meson.build      | 24 ++++++++++++++----------
 3 files changed, 50 insertions(+), 12 deletions(-)

diff --git a/target/hexagon/gen_tcg_funcs.py b/target/hexagon/gen_tcg_funcs.py
index fe4d8e5730..c3f04949a0 100755
--- a/target/hexagon/gen_tcg_funcs.py
+++ b/target/hexagon/gen_tcg_funcs.py
@@ -394,7 +394,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
@@ -455,12 +477,14 @@ def main():
     hex_common.read_attribs_file(sys.argv[2])
     hex_common.read_overrides_file(sys.argv[3])
     hex_common.calculate_attribs()
+    hex_common.read_idef_parser_enabled_file(sys.argv[4])
     tagregs = hex_common.get_tagregs()
     tagimms = hex_common.get_tagimms()
 
-    with open(sys.argv[4], 'w') as f:
+    with open(sys.argv[5], 'w') as f:
         f.write("#ifndef HEXAGON_TCG_FUNCS_H\n")
         f.write("#define HEXAGON_TCG_FUNCS_H\n\n")
+        f.write("#include \"idef-generated-emitter.h.inc\"\n\n")
 
         for tag in hex_common.tags:
             ## Skip the priv instructions
diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py
index b3b534057d..648ad29e94 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.
@@ -201,6 +202,9 @@ def need_ea(tag):
 def skip_qemu_helper(tag):
     return tag in overrides.keys()
 
+def is_idef_parser_enabled(tag):
+    return tag in idef_parser_enabled
+
 def imm_name(immlett):
     return "%siV" % immlett
 
@@ -232,3 +236,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 e6abcc472f..8809954883 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -72,16 +72,6 @@ helper_protos_generated = custom_target(
 )
 hexagon_ss.add(helper_protos_generated)
 
-tcg_funcs_generated = custom_target(
-    'tcg_funcs_generated.c.inc',
-    output: 'tcg_funcs_generated.c.inc',
-    input: 'gen_tcg_funcs.py',
-    depends: [semantics_generated],
-    depend_files: [hex_common_py, attribs_def, gen_tcg_h],
-    command: [python, '@INPUT@', semantics_generated, attribs_def, gen_tcg_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',
@@ -231,4 +221,18 @@ idef_generated_tcg = custom_target(
     command: [idef_parser, '@INPUT@', '@OUTPUT0@', '@OUTPUT1@', '@OUTPUT2@'],
 )
 
+idef_generated_list = idef_generated_tcg[2].full_path()
+
+hexagon_ss.add(idef_generated_tcg)
+
+tcg_funcs_generated = custom_target(
+    'tcg_funcs_generated.c.inc',
+    output: 'tcg_funcs_generated.c.inc',
+    input: 'gen_tcg_funcs.py',
+    depends: [semantics_generated, idef_generated_tcg],
+    depend_files: [hex_common_py, attribs_def, gen_tcg_h],
+    command: [python, '@INPUT@', semantics_generated, attribs_def, gen_tcg_h, idef_generated_list, '@OUTPUT@'],
+)
+hexagon_ss.add(tcg_funcs_generated)
+
 target_arch += {'hexagon': hexagon_ss}
-- 
2.30.1



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

* [PATCH v2 10/10] target/hexagon: import additional tests
  2021-02-25 15:18 [PATCH v2 00/10] target/hexagon: introduce idef-parser Alessandro Di Federico via
                   ` (8 preceding siblings ...)
  2021-02-25 15:18 ` [PATCH v2 09/10] target/hexagon: call idef-parser functions Alessandro Di Federico via
@ 2021-02-25 15:18 ` Alessandro Di Federico via
  2021-02-26  3:52   ` Richard Henderson
  2021-02-25 16:03 ` [PATCH v2 00/10] target/hexagon: introduce idef-parser no-reply
  10 siblings, 1 reply; 30+ messages in thread
From: Alessandro Di Federico via @ 2021-02-25 15:18 UTC (permalink / raw)
  To: qemu-devel
  Cc: tsimpson, bcain, babush, nizzo, philmd, richard.henderson,
	Alessandro Di Federico

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

Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Niccolò Izzo <nizzo@rev.ng>
---
 tests/tcg/hexagon/Makefile.target  | 35 ++++++++++++++++-
 tests/tcg/hexagon/crt.S            | 28 +++++++++++++
 tests/tcg/hexagon/first.S          | 24 ++++++------
 tests/tcg/hexagon/test_abs.S       | 20 ++++++++++
 tests/tcg/hexagon/test_add.S       | 20 ++++++++++
 tests/tcg/hexagon/test_andp.S      | 23 +++++++++++
 tests/tcg/hexagon/test_bitcnt.S    | 42 ++++++++++++++++++++
 tests/tcg/hexagon/test_bitsplit.S  | 25 ++++++++++++
 tests/tcg/hexagon/test_call.S      | 63 ++++++++++++++++++++++++++++++
 tests/tcg/hexagon/test_clobber.S   | 35 +++++++++++++++++
 tests/tcg/hexagon/test_cmp.S       | 34 ++++++++++++++++
 tests/tcg/hexagon/test_cmpy.S      | 31 +++++++++++++++
 tests/tcg/hexagon/test_djump.S     | 24 ++++++++++++
 tests/tcg/hexagon/test_dotnew.S    | 39 ++++++++++++++++++
 tests/tcg/hexagon/test_dstore.S    | 29 ++++++++++++++
 tests/tcg/hexagon/test_ext.S       | 18 +++++++++
 tests/tcg/hexagon/test_fibonacci.S | 33 ++++++++++++++++
 tests/tcg/hexagon/test_hello.S     | 21 ++++++++++
 tests/tcg/hexagon/test_hl.S        | 19 +++++++++
 tests/tcg/hexagon/test_hwloops.S   | 25 ++++++++++++
 tests/tcg/hexagon/test_jmp.S       | 25 ++++++++++++
 tests/tcg/hexagon/test_lsr.S       | 39 ++++++++++++++++++
 tests/tcg/hexagon/test_mpyi.S      | 20 ++++++++++
 tests/tcg/hexagon/test_packet.S    | 26 ++++++++++++
 tests/tcg/hexagon/test_reorder.S   | 31 +++++++++++++++
 tests/tcg/hexagon/test_round.S     | 31 +++++++++++++++
 tests/tcg/hexagon/test_vavgw.S     | 33 ++++++++++++++++
 tests/tcg/hexagon/test_vcmpb.S     | 32 +++++++++++++++
 tests/tcg/hexagon/test_vcmpw.S     | 29 ++++++++++++++
 tests/tcg/hexagon/test_vcmpy.S     | 50 ++++++++++++++++++++++++
 tests/tcg/hexagon/test_vlsrw.S     | 23 +++++++++++
 tests/tcg/hexagon/test_vmaxh.S     | 37 ++++++++++++++++++
 tests/tcg/hexagon/test_vminh.S     | 37 ++++++++++++++++++
 tests/tcg/hexagon/test_vpmpyh.S    | 30 ++++++++++++++
 tests/tcg/hexagon/test_vspliceb.S  | 33 ++++++++++++++++
 35 files changed, 1051 insertions(+), 13 deletions(-)
 create mode 100644 tests/tcg/hexagon/crt.S
 create mode 100644 tests/tcg/hexagon/test_abs.S
 create mode 100644 tests/tcg/hexagon/test_add.S
 create mode 100644 tests/tcg/hexagon/test_andp.S
 create mode 100644 tests/tcg/hexagon/test_bitcnt.S
 create mode 100644 tests/tcg/hexagon/test_bitsplit.S
 create mode 100644 tests/tcg/hexagon/test_call.S
 create mode 100644 tests/tcg/hexagon/test_clobber.S
 create mode 100644 tests/tcg/hexagon/test_cmp.S
 create mode 100644 tests/tcg/hexagon/test_cmpy.S
 create mode 100644 tests/tcg/hexagon/test_djump.S
 create mode 100644 tests/tcg/hexagon/test_dotnew.S
 create mode 100644 tests/tcg/hexagon/test_dstore.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_hello.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_vcmpy.S
 create mode 100644 tests/tcg/hexagon/test_vlsrw.S
 create mode 100644 tests/tcg/hexagon/test_vmaxh.S
 create mode 100644 tests/tcg/hexagon/test_vminh.S
 create mode 100644 tests/tcg/hexagon/test_vpmpyh.S
 create mode 100644 tests/tcg/hexagon/test_vspliceb.S

diff --git a/tests/tcg/hexagon/Makefile.target b/tests/tcg/hexagon/Makefile.target
index 616af697fe..f4a774cda1 100644
--- a/tests/tcg/hexagon/Makefile.target
+++ b/tests/tcg/hexagon/Makefile.target
@@ -32,7 +32,7 @@ CFLAGS += -Wno-incompatible-pointer-types -Wno-undefined-internal
 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
@@ -43,4 +43,37 @@ HEX_TESTS += mem_noshuf
 HEX_TESTS += atomics
 HEX_TESTS += fpstuff
 
+HEX_TESTS += test_abs
+HEX_TESTS += test_add
+HEX_TESTS += test_andp
+HEX_TESTS += test_bitcnt
+HEX_TESTS += test_bitsplit
+HEX_TESTS += test_call
+HEX_TESTS += test_clobber
+HEX_TESTS += test_cmp
+HEX_TESTS += test_cmpy
+HEX_TESTS += test_djump
+HEX_TESTS += test_dotnew
+HEX_TESTS += test_dstore
+HEX_TESTS += test_ext
+HEX_TESTS += test_fibonacci
+HEX_TESTS += test_hello
+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_vcmpy
+HEX_TESTS += test_vlsrw
+HEX_TESTS += test_vmaxh
+HEX_TESTS += test_vminh
+HEX_TESTS += test_vpmpyh
+HEX_TESTS += test_vspliceb
+
 TESTS += $(HEX_TESTS)
diff --git a/tests/tcg/hexagon/crt.S b/tests/tcg/hexagon/crt.S
new file mode 100644
index 0000000000..2c10577470
--- /dev/null
+++ b/tests/tcg/hexagon/crt.S
@@ -0,0 +1,28 @@
+#define SYS_exit_group           94
+
+    .text
+    .globl init
+init:
+    {
+        allocframe(r29,#0):raw
+    }
+    {
+        r0=#256
+    }
+    {
+        dealloc_return
+    }
+
+    .space 240
+
+    .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/first.S b/tests/tcg/hexagon/first.S
index e9f2d963ec..7f96b4332e 100644
--- a/tests/tcg/hexagon/first.S
+++ b/tests/tcg/hexagon/first.S
@@ -21,24 +21,24 @@
 
 #define FD_STDOUT                1
 
-	.type	str,@object
-	.section	.rodata
+    .type	str,@object
+    .section	.rodata
 str:
-	.string	"Hello!\n"
-	.size	str, 8
+    .string	"Hello!\n"
+    .size	str, 8
 
 .text
 .global _start
 _start:
-	r6 = #SYS_write
-	r0 = #FD_STDOUT
-	r1 = ##str
-	r2 = #7
-	trap0(#1)
+    r6 = #SYS_write
+    r0 = #FD_STDOUT
+    r1 = ##str
+    r2 = #7
+    trap0(#1)
 
-	r0 = #0
-	r6 = #SYS_exit_group
-	trap0(#1)
+    r0 = #0
+    r6 = #SYS_exit_group
+    trap0(#1)
 
 .section ".note.ABI-tag", "a"
 .align 4
diff --git a/tests/tcg/hexagon/test_abs.S b/tests/tcg/hexagon/test_abs.S
new file mode 100644
index 0000000000..880b2886b5
--- /dev/null
+++ b/tests/tcg/hexagon/test_abs.S
@@ -0,0 +1,20 @@
+/* Purpose: test example, verify the soundness of the abs operation */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r1=#-2
+        r2=#2
+    }
+    {
+        r3=abs(r1)
+    }
+    {
+        p0 = cmp.eq(r3, r2); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_add.S b/tests/tcg/hexagon/test_add.S
new file mode 100644
index 0000000000..e8de34520f
--- /dev/null
+++ b/tests/tcg/hexagon/test_add.S
@@ -0,0 +1,20 @@
+/* Purpose: test example, verify the soundness of the add operation */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r1=#0
+        r2=#0
+    }
+    {
+        r3=add(r1,r2)
+    }
+    {
+        p0 = cmp.eq(r3, #0); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_andp.S b/tests/tcg/hexagon/test_andp.S
new file mode 100644
index 0000000000..3c4aa8b2ae
--- /dev/null
+++ b/tests/tcg/hexagon/test_andp.S
@@ -0,0 +1,23 @@
+/* Purpose: test a multiple predicate AND combination */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        r1+=sub(r2,r3)
+        call init
+    }
+    {
+        r0=#0
+        r1=#1
+    }
+    {
+        p0=cmp.gt(r0,r1)
+        p0=cmp.gt(r0,r1)
+        p0=cmp.gt(r1,r0)
+    }
+    {
+        if (!p0) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_bitcnt.S b/tests/tcg/hexagon/test_bitcnt.S
new file mode 100644
index 0000000000..df77fe61e2
--- /dev/null
+++ b/tests/tcg/hexagon/test_bitcnt.S
@@ -0,0 +1,42 @@
+/* Purpose: test example, verify the soundness of the cl[01] operations
+ *
+ * the number 0x000001aa has 23 leading zeroes
+ * they become 55 when considered as 64 bit register
+ * and it has 1 trailing zero
+ */
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#426
+        r1=#0
+    }
+    {
+        r2=cl0(r0)
+    }
+    {
+        p0 = cmp.eq(r2, #23); if (p0.new) jump:t test2
+        jump fail
+    }
+
+test2:
+    {
+        r2=cl0(r1:0)
+    }
+    {
+        p0 = cmp.eq(r2, #55); if (p0.new) jump:t test3
+        jump fail
+    }
+
+test3:
+    {
+        r2=ct0(r0)
+    }
+    {
+        p0 = cmp.eq(r2, #1); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_bitsplit.S b/tests/tcg/hexagon/test_bitsplit.S
new file mode 100644
index 0000000000..787cce72e4
--- /dev/null
+++ b/tests/tcg/hexagon/test_bitsplit.S
@@ -0,0 +1,25 @@
+/* Purpose: test example, verify the soundness of the bitsplit operation */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r1=#187
+    }
+    {
+        r3:2=bitsplit(r1, #3)
+    }
+    {
+        p0 = cmp.eq(r2, #3); if (p0.new) jump:t test2
+        jump fail
+    }
+
+test2:
+    {
+        p0 = cmp.eq(r3, #23); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_call.S b/tests/tcg/hexagon/test_call.S
new file mode 100644
index 0000000000..53a2450522
--- /dev/null
+++ b/tests/tcg/hexagon/test_call.S
@@ -0,0 +1,63 @@
+/* Purpose: test function calls and duplex instructions.
+ * The string "Hello there, I'm a test string!" with the first letter replaced
+ * with a capital L should be printed out.
+ */
+
+    .text
+    .globl    test
+test:
+    {
+        jumpr r31
+        memb(r0+#0)=#76
+    }
+.Lfunc_end0:
+.Ltmp0:
+    .size    test, .Ltmp0-test
+
+    .globl    _start
+_start:
+    {
+        call init
+    }
+    {
+        call test
+        r0=##dummy_buffer
+        allocframe(#0)
+    }
+    {
+        call write
+    }
+    {
+        jump pass
+    }
+    {
+        r31:30=deallocframe(r30):raw
+    }
+.Lfunc_end1:
+.Ltmp1:
+    .size    _start, .Ltmp1-_start
+write:
+    {
+        r2=##dummy_buffer
+    }
+    { r0=r2; }
+    {
+        r2=#256
+    }
+    { r1=r2; }
+    { trap0(#7); }
+    {
+        jumpr r31
+    }
+.Lfunc_end2:
+.Ltmp2:
+    .size    write, .Ltmp2-write
+
+    .type    dummy_buffer,@object
+    .data
+    .globl    dummy_buffer
+    .p2align    3
+dummy_buffer:
+    .string    "Hello there, I'm a test string!\n"
+    .space 223
+    .size    dummy_buffer, 256
diff --git a/tests/tcg/hexagon/test_clobber.S b/tests/tcg/hexagon/test_clobber.S
new file mode 100644
index 0000000000..198817ebd5
--- /dev/null
+++ b/tests/tcg/hexagon/test_clobber.S
@@ -0,0 +1,35 @@
+/* Purpose: demonstrate the succesful operation of the register save mechanism,
+ * in which the caller saves the registers that will be clobbered, and restores
+ * them after the call.
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r16=#47
+        r17=#155
+    }
+    {
+        memd(r29+#-16)=r17:16; allocframe(#8)
+    }
+    {
+        r16=#255
+        r17=#42
+    }
+    {
+        r17:16=memd(r29+#0); deallocframe
+    }
+    {
+        r3=add(r16,r17)
+    }
+    {
+        p0 = cmp.eq(r3, #202); if (p0.new) jump:t pass
+    }
+    {
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_cmp.S b/tests/tcg/hexagon/test_cmp.S
new file mode 100644
index 0000000000..31ee9565fe
--- /dev/null
+++ b/tests/tcg/hexagon/test_cmp.S
@@ -0,0 +1,34 @@
+/* Purpose: test a signed and unsigned comparison */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        jump signed
+    }
+
+    .globl signed
+signed:
+    {
+        r0=#-2
+        r1=#0
+    }
+    {
+        p0 = cmp.lt(r0, r1); if (p0.new) jump:t unsigned
+        jump fail
+    }
+
+    .globl unsigned
+unsigned:
+    {
+        r0=#-2
+        r1=#0
+    }
+    {
+        p0 = cmp.gtu(r0, r1); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_cmpy.S b/tests/tcg/hexagon/test_cmpy.S
new file mode 100644
index 0000000000..0b3dfb95de
--- /dev/null
+++ b/tests/tcg/hexagon/test_cmpy.S
@@ -0,0 +1,31 @@
+/* Purpose: test example, verify the soundness of the cmpy operation
+ *
+ *  3j+5 * 2j+4 = 22j+14
+ *
+ * the complex multiply between 0x00030005 and 0x00020004 is 0x000000160000000e
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#196613
+        r1=#131076
+    }
+    {
+        r3:2=cmpy(r0, r1):sat
+    }
+    {
+        p0 = cmp.eq(r2, #14); if (p0.new) jump:t test2
+        jump fail
+    }
+
+test2:
+    {
+        p0 = cmp.eq(r3, #22); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_djump.S b/tests/tcg/hexagon/test_djump.S
new file mode 100644
index 0000000000..dbad7eb0a1
--- /dev/null
+++ b/tests/tcg/hexagon/test_djump.S
@@ -0,0 +1,24 @@
+/* Purpose: show dual jumps actually work. This program features a packet where
+ * two jumps should (in theory) be performed if !P0. However, we correctly
+ * handle the situation by performing only the first one and ignoring the second
+ * one. This can be verified by checking that the CPU dump contains 0xDEADBEEF
+ * in R2.
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r1 = #255;
+    }
+    {
+        p0 = r1;
+    }
+    {
+        if (p0) 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..3897c6bc96
--- /dev/null
+++ b/tests/tcg/hexagon/test_dotnew.S
@@ -0,0 +1,39 @@
+/* Purpose: test the .new operator while performing memory stores.
+ * In the final CPU dump R0 should contain 3, R1 should contain 2 and R2 should
+ * contain 1.
+ */
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#1
+        memw(sp+#0)=r0.new
+    }
+    {
+        r1=#2
+        memw(sp+#4)=r1.new
+    }
+    {
+        r2=#3
+        memw(sp+#8)=r2.new
+    }
+    {
+        r0=memw(sp+#8)
+    }
+    {
+        r1=memw(sp+#4)
+    }
+    {
+        r2=memw(sp+#0)
+    }
+    {
+        r3=mpyi(r1,r2)
+    }
+    {
+        p0 = cmp.eq(r3, #2); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_dstore.S b/tests/tcg/hexagon/test_dstore.S
new file mode 100644
index 0000000000..62c4301eb1
--- /dev/null
+++ b/tests/tcg/hexagon/test_dstore.S
@@ -0,0 +1,29 @@
+/* Purpose: test dual stores correctness.
+ * In this example the values 1 and 2 are both written on the top of the stack
+ * in a single packet.
+ * The value is then read back in R3, which should contain only the latest value
+ * written (2).
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#1
+        r1=#2
+    }
+    {
+        memw(sp+#0)=r0
+        memw(sp+#0)=r1
+    }
+    {
+        r3=memw(sp+#0)
+    }
+    {
+        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..0f6e21593a
--- /dev/null
+++ b/tests/tcg/hexagon/test_ext.S
@@ -0,0 +1,18 @@
+/* Purpose: test immediate extender instructions.
+ * In the CPU dump R0 should contain 0xDEADBEEF.
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r2=##-559038737
+    }
+    {
+        p0 = cmp.eq(r2, ##-559038737); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_fibonacci.S b/tests/tcg/hexagon/test_fibonacci.S
new file mode 100644
index 0000000000..41cb1517cb
--- /dev/null
+++ b/tests/tcg/hexagon/test_fibonacci.S
@@ -0,0 +1,33 @@
+/* Purpose: computes the Fibonacci series up to a constant number. */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r2=#100
+    }
+    {
+        p0=cmp.gt(r2,#0); if (!p0.new) jump:nt .LBB0_3
+    }
+    {
+        r3=#0
+        r4=#1
+    }
+.LBB0_2:
+    {
+        r5=r4
+    }
+    {
+        p0=cmp.gt(r2,r5); if (p0.new) jump:nt .LBB0_2
+        r4=add(r3,r4)
+        r3=r5
+    }
+.LBB0_3:
+    {
+        p0 = cmp.eq(r3, #144); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_hello.S b/tests/tcg/hexagon/test_hello.S
new file mode 100644
index 0000000000..89c7da677f
--- /dev/null
+++ b/tests/tcg/hexagon/test_hello.S
@@ -0,0 +1,21 @@
+/* Purpose: simple hello world program. */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    { r0=#4; }
+    {
+        r1=##.L.str
+    }
+    { trap0(#0); }
+    {
+        jump pass
+    }
+
+.L.str:
+    .string    "Hello world!\n"
+    .size    .L.str, 14
diff --git a/tests/tcg/hexagon/test_hl.S b/tests/tcg/hexagon/test_hl.S
new file mode 100644
index 0000000000..217b3143e2
--- /dev/null
+++ b/tests/tcg/hexagon/test_hl.S
@@ -0,0 +1,19 @@
+/* Purpose: test example, verify the soundness of the high/low assignment */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0.H=#42
+    }
+    {
+        r0.L=#69
+    }
+    {
+        p0 = cmp.eq(r0, #2752581); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_hwloops.S b/tests/tcg/hexagon/test_hwloops.S
new file mode 100644
index 0000000000..8337083d8e
--- /dev/null
+++ b/tests/tcg/hexagon/test_hwloops.S
@@ -0,0 +1,25 @@
+/* Purpose: simple C Program to test hardware loops.
+ * It should print numbersfrom 0 to 9.
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        loop0(.LBB0_1,#10)
+        r2=#0
+    }
+.Ltmp0:
+.LBB0_1:
+    {
+        r2=add(r2,#1)
+        nop
+    }:endloop0
+    {
+        p0 = cmp.eq(r2, #10); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_jmp.S b/tests/tcg/hexagon/test_jmp.S
new file mode 100644
index 0000000000..9bf6ea34e5
--- /dev/null
+++ b/tests/tcg/hexagon/test_jmp.S
@@ -0,0 +1,25 @@
+/* Purpose: test example, verify the soundness of the add operation */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r1=#0
+        r2=#0
+    }
+    {
+        r3=add(r1,r2)
+    }
+    {
+        p0 = cmp.eq(r3, #0)
+    }
+    {
+        if (p0) jump:t pass
+    }
+    {
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_lsr.S b/tests/tcg/hexagon/test_lsr.S
new file mode 100644
index 0000000000..202eb4aec7
--- /dev/null
+++ b/tests/tcg/hexagon/test_lsr.S
@@ -0,0 +1,39 @@
+/* Purpose: test the soundness of the lsr operation */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#-56984
+        r1=#2147483647
+    }
+    {
+        r2=#0x19
+    }
+    {
+        r0&=lsr(r1, r2)
+    }
+    {
+        p0 = cmp.eq(r0, #0x28); if (p0.new) jump:t test2
+        jump fail
+    }
+
+test2:
+    {
+        r0=#0x0000000a
+        r1=#0x00000000
+    }
+    {
+        r2=#-1
+    }
+    {
+        r1:0=lsl(r1:0, r2)
+    }
+    {
+        p0 = cmp.eq(r0, #0x5); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_mpyi.S b/tests/tcg/hexagon/test_mpyi.S
new file mode 100644
index 0000000000..b8e0d50b68
--- /dev/null
+++ b/tests/tcg/hexagon/test_mpyi.S
@@ -0,0 +1,20 @@
+/* Purpose: test a simple multiplication operation */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r1=#4
+        r2=#6
+    }
+    {
+        r3=mpyi(r1,r2)
+    }
+    {
+        p0 = cmp.eq(r3, #24); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_packet.S b/tests/tcg/hexagon/test_packet.S
new file mode 100644
index 0000000000..d26e284be9
--- /dev/null
+++ b/tests/tcg/hexagon/test_packet.S
@@ -0,0 +1,26 @@
+/* Purpose: test that writes of a register in a packet are performed only after
+ * that packet has finished its execution.
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r2=#4
+        r3=#6
+    }
+    {
+        memw(sp+#0)=r2
+    }
+    {
+        r3=memw(sp+#0)
+        r0=add(r2,r3)
+    }
+    {
+        p0 = cmp.eq(r0, #10); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_reorder.S b/tests/tcg/hexagon/test_reorder.S
new file mode 100644
index 0000000000..508d5302f9
--- /dev/null
+++ b/tests/tcg/hexagon/test_reorder.S
@@ -0,0 +1,31 @@
+/* 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.
+ * A successful run of the program will show R2 retaining the 0xDEADBEEF value
+ * in the CPU dump.
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    { r2=#-559038737 }
+    { r4=#1 }
+    {
+        if (p0.new) jump:nt skip
+        p0=r4;
+    }
+
+fallthrough:
+    { r2=#0 }
+
+skip:
+    {
+        p0 = cmp.eq(r2, #-559038737); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_round.S b/tests/tcg/hexagon/test_round.S
new file mode 100644
index 0000000000..2becd62c4c
--- /dev/null
+++ b/tests/tcg/hexagon/test_round.S
@@ -0,0 +1,31 @@
+/* Purpose: test example, verify the soundness of the cround operation
+ * 106 = 0b1101010 with the comma at third digit is 12.5 which is crounded to 12
+ * but rounded to 13
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r1=#200
+    }
+    {
+        r2=round(r1, #4)
+    }
+    {
+        p0 = cmp.eq(r2, #13); if (p0.new) jump:t test2
+        jump fail
+    }
+
+test2:
+    {
+        r2=cround(r1, #4)
+    }
+    {
+        p0 = cmp.eq(r2, #12); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_vavgw.S b/tests/tcg/hexagon/test_vavgw.S
new file mode 100644
index 0000000000..8f67238900
--- /dev/null
+++ b/tests/tcg/hexagon/test_vavgw.S
@@ -0,0 +1,33 @@
+/* Purpose: test example, verify the soundness of the vavgw operation
+ *
+ * 0x00030001 averaged with 0x00010003 results 0x00020002
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#3
+        r1=#1
+    }
+    {
+        r2=#1
+        r3=#3
+    }
+    {
+        r1:0=vavgw(r1:0, r3:2):crnd
+    }
+    {
+        p0 = cmp.eq(r0, #2); if (p0.new) jump:t test2
+        jump fail
+    }
+
+test2:
+    {
+        p0 = cmp.eq(r1, #2); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_vcmpb.S b/tests/tcg/hexagon/test_vcmpb.S
new file mode 100644
index 0000000000..3c6700a63a
--- /dev/null
+++ b/tests/tcg/hexagon/test_vcmpb.S
@@ -0,0 +1,32 @@
+/* Purpose: test example, verify the soundness of the vector compare bytes
+ * operation
+ *
+ * Vector word comparison between 0x1234567887654321 and 0x1234567800000000
+ * should result in 0x11110000
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#305419896
+        r1=#-2023406815
+    }
+    {
+        r2=#305419896
+        r3=#0
+    }
+    {
+        p2=vcmpb.eq(r1:0, r3:2)
+    }
+    {
+        r4=p2
+    }
+    {
+        p0 = cmp.eq(r4, #15); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_vcmpw.S b/tests/tcg/hexagon/test_vcmpw.S
new file mode 100644
index 0000000000..112f08c92f
--- /dev/null
+++ b/tests/tcg/hexagon/test_vcmpw.S
@@ -0,0 +1,29 @@
+/* Purpose: test example, verify the soundness of the vector compare words
+ * operation
+ *
+ * Vector word comparison between 0x1234567887654321 and 0x1234567800000000
+ * should result in 0x11110000
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#305419896
+        r1=#-2023406815
+    }
+    {
+        r2=#305419896
+        r3=#0
+    }
+    {
+        p2=vcmpw.eq(r1:0, r3:2)
+    }
+    {
+        if (p2) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_vcmpy.S b/tests/tcg/hexagon/test_vcmpy.S
new file mode 100644
index 0000000000..df379f9186
--- /dev/null
+++ b/tests/tcg/hexagon/test_vcmpy.S
@@ -0,0 +1,50 @@
+/* Purpose: test example, verify the soundness of the vcmpy operation
+ * this operation is a complex multiply and accumulate on vectors of two values
+ *
+ *     (3j+5 * 2j+4) + (4j+6 * 5j+2) = 22j+14
+ *
+ * the complex multiply between  0x00030005 and 0x00020004 is 0x000000160000000e
+ * the complex multiply between  0x00040006 and 0x00050002 is 0x000000160000000e
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#196613
+        r1=#131076
+    }
+    {
+        r2=#262150
+        r3=#327682
+    }
+    {
+        r5:4=vcmpyr(r1:0, r3:2):sat
+        r7:6=vcmpyi(r1:0, r3:2):sat
+    }
+    {
+        p0 = cmp.eq(r4, #18); if (p0.new) jump:t test2
+        jump fail
+    }
+
+test2:
+    {
+        p0 = cmp.eq(r5, #-2); if (p0.new) jump:t test3
+        jump fail
+    }
+
+test3:
+    {
+        p0 = cmp.eq(r6, #38); if (p0.new) jump:t test4
+        jump fail
+    }
+
+test4:
+    {
+        p0 = cmp.eq(r7, #24); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_vlsrw.S b/tests/tcg/hexagon/test_vlsrw.S
new file mode 100644
index 0000000000..962ec99543
--- /dev/null
+++ b/tests/tcg/hexagon/test_vlsrw.S
@@ -0,0 +1,23 @@
+/* Purpose: test the soundness of the vlsrw operation */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#0x00000001
+        r1=#0x00000001
+    }
+    {
+        r1:0=vlsrw(r1:0, #1)
+    }
+    {
+        r0 = add(r0, r1)
+    }
+    {
+        p0 = cmp.eq(r0, #0); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_vmaxh.S b/tests/tcg/hexagon/test_vmaxh.S
new file mode 100644
index 0000000000..1fce935e35
--- /dev/null
+++ b/tests/tcg/hexagon/test_vmaxh.S
@@ -0,0 +1,37 @@
+/* Purpose: test example, verify the soundness of the vrmaxh operation
+ *
+ * the maximum between  0x0002000300010005 and 0x0003000200020007 is
+ * 0x0003000300020007.
+ *
+ *                      r1=0x00010003 r0=0x00010005 r3=0x00030002 r2=0x00020007
+ *     result:          r1=0x00030003 r0=0x00020007
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#65541
+        r1=#65539
+    }
+    {
+        r2=#131079
+        r3=#196610
+    }
+    {
+        r1:0=vmaxh(r1:0, r3:2)
+    }
+    {
+        p0 = cmp.eq(r0, #131079); if (p0.new) jump:t test2
+        jump fail
+    }
+
+test2:
+    {
+        p0 = cmp.eq(r1, #196611); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_vminh.S b/tests/tcg/hexagon/test_vminh.S
new file mode 100644
index 0000000000..6c6d18c673
--- /dev/null
+++ b/tests/tcg/hexagon/test_vminh.S
@@ -0,0 +1,37 @@
+/* Purpose: test example, verify the soundness of the vrmaxh operation
+ *
+ * the minimum between  0x0002000300010005 and 0x0003000200020007 is
+ * 0x0003000300020007
+ *
+ *                      r1=0x00010003 r0=0x00010005 r3=0x00030002 r2=0x00020007
+ *     result:          r1=0x00010002 r0=0x00010005
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#65541
+        r1=#65539
+    }
+    {
+        r2=#131079
+        r3=#196610
+    }
+    {
+        r1:0=vminh(r1:0, r3:2)
+    }
+    {
+        p0 = cmp.eq(r0, #65541); if (p0.new) jump:t test2
+        jump fail
+    }
+
+test2:
+    {
+        p0 = cmp.eq(r1, #65538); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_vpmpyh.S b/tests/tcg/hexagon/test_vpmpyh.S
new file mode 100644
index 0000000000..942d691da4
--- /dev/null
+++ b/tests/tcg/hexagon/test_vpmpyh.S
@@ -0,0 +1,30 @@
+/* Purpose: test example, verify the soundness of the vpmpyh operator
+ *
+ * 0x01020304 vector polynomial multiplied with 0x04030201 results
+ * 0x000400060b060b04
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#16909060
+        r1=#67305985
+    }
+    {
+        r1:0=vpmpyh(r0, r1)
+    }
+    {
+        p0 = cmp.eq(r0, #184945412); if (p0.new) jump:t test2
+        jump fail
+    }
+
+test2:
+    {
+        p0 = cmp.eq(r1, #262150); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_vspliceb.S b/tests/tcg/hexagon/test_vspliceb.S
new file mode 100644
index 0000000000..bae2a9c163
--- /dev/null
+++ b/tests/tcg/hexagon/test_vspliceb.S
@@ -0,0 +1,33 @@
+/* Purpose: test example, verify the soundness of the vspliceb operation
+ * the operation is a binary splice of two 64bit operators
+ *
+ *  vspliceb(0xffffffffffffffff,0x0000000000000000,5) = 0x000000000000001f
+ */
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#-1
+        r1=#-1
+    }
+    {
+        r2=#0
+        r3=#0
+    }
+    {
+        r5:4=vspliceb(r1:0, r3:2, #5)
+    }
+    {
+        p0 = cmp.eq(r4, #-1); if (p0.new) jump:t test2
+        jump fail
+    }
+
+test2:
+    {
+        p0 = cmp.eq(r5, #255); if (p0.new) jump:t pass
+        jump fail
+    }
-- 
2.30.1



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

* Re: [PATCH v2 00/10] target/hexagon: introduce idef-parser
  2021-02-25 15:18 [PATCH v2 00/10] target/hexagon: introduce idef-parser Alessandro Di Federico via
                   ` (9 preceding siblings ...)
  2021-02-25 15:18 ` [PATCH v2 10/10] target/hexagon: import additional tests Alessandro Di Federico via
@ 2021-02-25 16:03 ` no-reply
  10 siblings, 0 replies; 30+ messages in thread
From: no-reply @ 2021-02-25 16:03 UTC (permalink / raw)
  To: qemu-devel
  Cc: ale, bcain, richard.henderson, qemu-devel, babush, tsimpson,
	nizzo, philmd

Patchew URL: https://patchew.org/QEMU/20210225151856.3284701-1-ale.qemu@rev.ng/



Hi,

This series seems to have some coding style problems. See output below for
more information:

Type: series
Message-id: 20210225151856.3284701-1-ale.qemu@rev.ng
Subject: [PATCH v2 00/10] target/hexagon: introduce idef-parser

=== TEST SCRIPT BEGIN ===
#!/bin/bash
git rev-parse base > /dev/null || exit 0
git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram
./scripts/checkpatch.pl --mailback base..
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
From https://github.com/patchew-project/qemu
 - [tag update]      patchew/20210225091435.644762-1-eric.auger@redhat.com -> patchew/20210225091435.644762-1-eric.auger@redhat.com
 * [new tag]         patchew/20210225151856.3284701-1-ale.qemu@rev.ng -> patchew/20210225151856.3284701-1-ale.qemu@rev.ng
Switched to a new branch 'test'
739bb05 target/hexagon: import additional tests
c412a0e target/hexagon: call idef-parser functions
41c3d34 target/hexagon: import parser for idef-parser
6fbf5f9 target/hexagon: import lexer for idef-parser
b35ce32 target/hexagon: prepare input for the idef-parser
bfa9eac target/hexagon: expose next PC in DisasContext
3a44618 target/hexagon: introduce new helper functions
df56633 target/hexagon: make helper functions non-static
e829131 target/hexagon: import README for idef-parser
44c5544 target/hexagon: update MAINTAINERS for idef-parser

=== OUTPUT BEGIN ===
1/10 Checking commit 44c554486189 (target/hexagon: update MAINTAINERS for idef-parser)
2/10 Checking commit e829131d737c (target/hexagon: import README for idef-parser)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#38: 
new file mode 100644

total: 0 errors, 1 warnings, 464 lines checked

Patch 2/10 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
3/10 Checking commit df5663383efb (target/hexagon: make helper functions non-static)
4/10 Checking commit 3a44618adb7c (target/hexagon: introduce new helper functions)
5/10 Checking commit bfa9eacded62 (target/hexagon: expose next PC in DisasContext)
6/10 Checking commit b35ce3214587 (target/hexagon: prepare input for the idef-parser)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#20: 
new file mode 100644

total: 0 errors, 1 warnings, 341 lines checked

Patch 6/10 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
7/10 Checking commit 6fbf5f96ef69 (target/hexagon: import lexer for idef-parser)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#29: 
new file mode 100644

total: 0 errors, 1 warnings, 987 lines checked

Patch 7/10 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
8/10 Checking commit 41c3d34a00e0 (target/hexagon: import parser for idef-parser)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#30: 
new file mode 100644

ERROR: suspicious ; after while (0)
#3320: FILE: target/hexagon/idef-parser/parser-helpers.h:99:
+    } while (0);

total: 1 errors, 1 warnings, 3583 lines checked

Patch 8/10 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

9/10 Checking commit c412a0e3f999 (target/hexagon: call idef-parser functions)
10/10 Checking commit 739bb05d384e (target/hexagon: import additional tests)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#100: 
new file mode 100644

total: 0 errors, 1 warnings, 1086 lines checked

Patch 10/10 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
=== OUTPUT END ===

Test command exited with code: 1


The full log is available at
http://patchew.org/logs/20210225151856.3284701-1-ale.qemu@rev.ng/testing.checkpatch/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-devel@redhat.com

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

* Re: [PATCH v2 02/10] target/hexagon: import README for idef-parser
  2021-02-25 15:18 ` [PATCH v2 02/10] target/hexagon: import README " Alessandro Di Federico via
@ 2021-02-25 20:20   ` Richard Henderson
  2021-03-01 14:50     ` Alessandro Di Federico via
  2021-03-10 15:48     ` Taylor Simpson
  0 siblings, 2 replies; 30+ messages in thread
From: Richard Henderson @ 2021-02-25 20:20 UTC (permalink / raw)
  To: Alessandro Di Federico, qemu-devel
  Cc: Alessandro Di Federico, bcain, babush, tsimpson, nizzo, philmd

On 2/25/21 7:18 AM, Alessandro Di Federico wrote:
> +Now let's have a quick look at the generated code, line by line.
> +
> +::
> +
> +   tcg_gen_movi_i32(RdV, 0);
> +
> +This code starts by initializing ``RdV``, since reading from that register
> +without initialization will cause a segmentation fault by QEMU.  This is emitted
> +because a declaration of the ``RdV`` register was parsed, but no reading of the
> +``RdV`` register was found.

This is odd, as is the description of why.  Yes, if RdV is read without
initialization, TCG middle-end will abort (at least with --enable-debug-tcg
enabling the assertions).  But you've just said that "no reading" was found.
So why did you perform this dummy initialization, which will be eliminated later?


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

So, I take it from this that you're emitting tcg directly from within the
parser, and not generating any kind of abstract syntax tree?

A little disappointing, but not critical.  Even what you have is an improvement.

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

I sincerely doubt this is worth it.


r~


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

* Re: [PATCH v2 04/10] target/hexagon: introduce new helper functions
  2021-02-25 15:18 ` [PATCH v2 04/10] target/hexagon: introduce new helper functions Alessandro Di Federico via
@ 2021-02-25 20:45   ` Richard Henderson
  0 siblings, 0 replies; 30+ messages in thread
From: Richard Henderson @ 2021-02-25 20:45 UTC (permalink / raw)
  To: Alessandro Di Federico, qemu-devel
  Cc: Alessandro Di Federico, bcain, babush, tsimpson, nizzo, philmd

On 2/25/21 7:18 AM, Alessandro Di Federico wrote:
> From: Niccolò Izzo <nizzo@rev.ng>
> 
> These helpers will be employed by the idef-parser generated code.
> 
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Niccolò Izzo <nizzo@rev.ng>
> ---
>  target/hexagon/genptr.c | 227 +++++++++++++++++++++++++++++++++++++++-
>  target/hexagon/genptr.h |  19 ++++
>  target/hexagon/macros.h |   2 +-
>  3 files changed, 245 insertions(+), 3 deletions(-)
> 
> diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
> index 97de669f38..78cda032db 100644
> --- a/target/hexagon/genptr.c
> +++ b/target/hexagon/genptr.c
> @@ -40,7 +40,8 @@ TCGv gen_read_preg(TCGv pred, uint8_t num)
>      return pred;
>  }
>  
> -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,
> +                                                unsigned slot)

This change is unrelated to adding new helper functions.
It requires a separate patch and justification.

> +void gen_fbrev(TCGv result, TCGv src)
> +{
> +    TCGv lo = tcg_temp_new();
> +    TCGv tmp1 = tcg_temp_new();
> +    TCGv tmp2 = tcg_temp_new();
> +
> +    /* Bit reversal of low 16 bits */
> +    tcg_gen_extract_tl(lo, src, 0, 16);
> +    tcg_gen_andi_tl(tmp1, lo, 0xaaaa);
> +    tcg_gen_shri_tl(tmp1, tmp1, 1);
> +    tcg_gen_andi_tl(tmp2, lo, 0x5555);
> +    tcg_gen_shli_tl(tmp2, tmp2, 1);
> +    tcg_gen_or_tl(lo, tmp1, tmp2);
> +    tcg_gen_andi_tl(tmp1, lo, 0xcccc);
> +    tcg_gen_shri_tl(tmp1, tmp1, 2);
> +    tcg_gen_andi_tl(tmp2, lo, 0x3333);
> +    tcg_gen_shli_tl(tmp2, tmp2, 2);
> +    tcg_gen_or_tl(lo, tmp1, tmp2);
> +    tcg_gen_andi_tl(tmp1, lo, 0xf0f0);
> +    tcg_gen_shri_tl(tmp1, tmp1, 4);
> +    tcg_gen_andi_tl(tmp2, lo, 0x0f0f);
> +    tcg_gen_shli_tl(tmp2, tmp2, 4);
> +    tcg_gen_or_tl(lo, tmp1, tmp2);
> +    tcg_gen_bswap16_tl(lo, lo);

So far we've kept operations like this as external helper functions, where you
can then use revbit16().  General rule of thumb for a cutoff is about 10-15
ops, and this is right on the edge.

Any particular reason you wanted this inlined?

> +    /* Final tweaks */
> +    tcg_gen_extract_tl(result, src, 16, 16);
> +    tcg_gen_or_tl(result, result, lo);

This is wrong.  You've clobbered your carefully reversed results with the high
16-bits of src.

I'm certain you wanted

   tcg_gen_deposit_tl(result, src, lo, 0, 16);

to replace the low 16 bits of the input with your computation.

> +TCGv gen_set_bit(tcg_target_long i, TCGv result, TCGv src)
> +{
> +    TCGv mask = tcg_const_tl(~(1 << i));
> +    TCGv bit = tcg_temp_new();
> +    tcg_gen_shli_tl(bit, src, i);
> +    tcg_gen_and_tl(result, result, mask);
> +    tcg_gen_or_tl(result, result, bit);
> +    tcg_temp_free(mask);
> +    tcg_temp_free(bit);

  tcg_gen_deposit_tl(result, result, src, i, 1);

> +void gen_cancel(tcg_target_ulong slot)
> +{
> +    TCGv one = tcg_const_tl(1);
> +    tcg_gen_deposit_tl(hex_slot_cancelled, hex_slot_cancelled, one, slot, 1);
> +    tcg_temp_free(one);

  tcg_gen_ori_tl(hex_slot_cancelled, hex_slot_cancelled,
                 1 << slot);

> +void gen_sat_i32(TCGv dest, TCGv source, int width, bool set_overflow)
> +{
> +    TCGv max_val = tcg_const_i32((1 << (width - 1)) - 1);
> +    TCGv min_val = tcg_const_i32(-(1 << (width - 1)));
> +    tcg_gen_movcond_i32(TCG_COND_GT, dest, source, max_val, max_val, source);
> +    tcg_gen_movcond_i32(TCG_COND_LT, dest, source, min_val, min_val, dest);

  tcg_gen_smin_tl(dest, source, max_val);
  tcg_gen_smax_tl(dest, dest, min_val);

> +    /* Set Overflow Bit */
> +    if (set_overflow) {
> +        TCGv ovf = tcg_temp_new();
> +        TCGv one = tcg_const_i32(1);
> +        GET_USR_FIELD(USR_OVF, ovf);
> +        tcg_gen_movcond_i32(TCG_COND_GT, ovf, source, max_val, one, ovf);
> +        tcg_gen_movcond_i32(TCG_COND_LT, ovf, source, min_val, one, ovf);
> +        SET_USR_FIELD(USR_OVF, ovf);

This seems like a complicated way to set overflow.
How about

  tcg_gen_setcond_tl(TCG_COND_NE, ovf, source, dest);
  tcg_gen_shli_tl(ovf, ovf, USR_OVF_SHIFT);
  tcg_gen_or_tl(hex_reg[usr], hex_reg[usr], ovf);


> +        tcg_temp_free_i32(ovf);
> +        tcg_temp_free_i32(one);
> +    }
> +    tcg_temp_free_i32(max_val);
> +    tcg_temp_free_i32(min_val);
> +}
> +
> +void gen_satu_i32(TCGv dest, TCGv source, int width, bool set_overflow)
> +{
> +    TCGv max_val = tcg_const_i32((1 << width) - 1);
> +    tcg_gen_movcond_i32(TCG_COND_GTU, dest, source, max_val, max_val, source);
> +    TCGv_i32 zero = tcg_const_i32(0);
> +    tcg_gen_movcond_i32(TCG_COND_LT, dest, source, zero, zero, dest);

Is this a signed input being saturated to unsigned bounds or not?  Because one
of these two comparisons is wrong.

If it's an unsigned input being saturated to unsigned bounds, then you don't
need the second test at all, and should be using

  tcg_gen_umin_i32(dest, src, max_val);

> +void gen_sat_i64(TCGv_i64 dest, TCGv_i64 source, int width, bool set_overflow)
> +void gen_satu_i64(TCGv_i64 dest, TCGv_i64 source, int width, bool set_overflow)

Similarly.

> diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h
> index 78c4efb5cb..7b6556b07b 100644
> --- a/target/hexagon/macros.h
> +++ b/target/hexagon/macros.h
> @@ -154,7 +154,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, tcg_target_ulong slot_num)

Why in the world would a slot number need to be 64-bits?


r~



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

* Re: [PATCH v2 01/10] target/hexagon: update MAINTAINERS for idef-parser
  2021-02-25 15:18 ` [PATCH v2 01/10] target/hexagon: update MAINTAINERS for idef-parser Alessandro Di Federico via
@ 2021-02-25 20:46   ` Richard Henderson
  0 siblings, 0 replies; 30+ messages in thread
From: Richard Henderson @ 2021-02-25 20:46 UTC (permalink / raw)
  To: Alessandro Di Federico, qemu-devel
  Cc: Alessandro Di Federico, bcain, babush, tsimpson, nizzo, philmd

On 2/25/21 7:18 AM, Alessandro Di Federico wrote:
> From: Alessandro Di Federico <ale@rev.ng>
> 
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> ---
>  MAINTAINERS | 8 ++++++++
>  1 file changed, 8 insertions(+)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


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

* Re: [PATCH v2 03/10] target/hexagon: make helper functions non-static
  2021-02-25 15:18 ` [PATCH v2 03/10] target/hexagon: make helper functions non-static Alessandro Di Federico via
@ 2021-02-25 20:47   ` Richard Henderson
  0 siblings, 0 replies; 30+ messages in thread
From: Richard Henderson @ 2021-02-25 20:47 UTC (permalink / raw)
  To: Alessandro Di Federico, qemu-devel
  Cc: Alessandro Di Federico, bcain, babush, tsimpson, nizzo, philmd

On 2/25/21 7:18 AM, Alessandro Di Federico wrote:
> 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.
> 
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Paolo Montesel <babush@rev.ng>
> ---
>  target/hexagon/genptr.c | 13 ++++++++++---
>  target/hexagon/genptr.h |  7 +++++++
>  2 files changed, 17 insertions(+), 3 deletions(-)

You should mention that gen_read_reg is new.  Otherwise,

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~



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

* Re: [PATCH v2 05/10] target/hexagon: expose next PC in DisasContext
  2021-02-25 15:18 ` [PATCH v2 05/10] target/hexagon: expose next PC in DisasContext Alessandro Di Federico via
@ 2021-02-25 20:48   ` Richard Henderson
  0 siblings, 0 replies; 30+ messages in thread
From: Richard Henderson @ 2021-02-25 20:48 UTC (permalink / raw)
  To: Alessandro Di Federico, qemu-devel
  Cc: Alessandro Di Federico, bcain, babush, tsimpson, nizzo, philmd

On 2/25/21 7:18 AM, Alessandro Di Federico wrote:
> From: Paolo Montesel <babush@rev.ng>
> 
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Paolo Montesel <babush@rev.ng>
> ---
>  target/hexagon/translate.c | 4 +++-
>  target/hexagon/translate.h | 1 +
>  2 files changed, 4 insertions(+), 1 deletion(-)

> +        ctx->base.pc_next = ctx->npc;
> +        ctx->npc = 0;

Any particular reason you're clearing npc?

Otherwise,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


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

* Re: [PATCH v2 06/10] target/hexagon: prepare input for the idef-parser
  2021-02-25 15:18 ` [PATCH v2 06/10] target/hexagon: prepare input for the idef-parser Alessandro Di Federico via
@ 2021-02-25 21:34   ` Richard Henderson
  2021-03-01 16:26     ` Paolo Montesel via
  0 siblings, 1 reply; 30+ messages in thread
From: Richard Henderson @ 2021-02-25 21:34 UTC (permalink / raw)
  To: Alessandro Di Federico, qemu-devel
  Cc: Alessandro Di Federico, bcain, babush, tsimpson, nizzo, philmd

On 2/25/21 7:18 AM, Alessandro Di Federico wrote:
> 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>
> ---
>  target/hexagon/gen_idef_parser_funcs.py | 114 ++++++++++++++++
>  target/hexagon/idef-parser/macros.inc   | 166 ++++++++++++++++++++++++
>  target/hexagon/idef-parser/prepare      |  33 +++++
>  target/hexagon/meson.build              |  18 +++
>  4 files changed, 331 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..6fb3659201
> --- /dev/null
> +++ b/target/hexagon/gen_idef_parser_funcs.py
> @@ -0,0 +1,114 @@
> +#!/usr/bin/env python3
> +
> +##
> +##  Copyright(c) 2019-2020 rev.ng Srls. 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.read_overrides_file(sys.argv[3])
> +    hex_common.calculate_attribs()
> +    tagregs = hex_common.get_tagregs()
> +    tagimms = hex_common.get_tagimms()
> +
> +    with open(sys.argv[4], '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
> +            ## Skip other unsupported instructions
> +            if ( tag.startswith('S2_cabacdecbin') ) :
> +                continue
> +            if ( tag.startswith('Y') ) :
> +                continue
> +            if ( tag.startswith('V6_') ) :
> +                continue
> +            if ( tag.startswith('F') ) :
> +                continue
> +            if ( tag.endswith('_locked') ) :
> +                continue
> +
> +            regs = tagregs[tag]
> +            imms = tagimms[tag]
> +
> +            arguments = []
> +            if hex_common.need_ea(tag):
> +                arguments.append("EA")
> +
> +            for regtype,regid,toss,numregs in regs:
> +                prefix = "in " if hex_common.is_read(regid) else ""
> +
> +                is_pair = hex_common.is_pair(regid)
> +                is_single_old = (hex_common.is_single(regid)
> +                                 and hex_common.is_old_val(regtype, regid, tag))
> +                is_single_new = (hex_common.is_single(regid)
> +                                 and hex_common.is_new_val(regtype, regid, tag))
> +
> +                if is_pair or is_single_old:
> +                    arguments.append("%s%s%sV" % (prefix, regtype, regid))
> +                elif is_single_new:
> +                    arguments.append("%s%s%sN" % (prefix, regtype, regid))
> +                else:
> +                    print("Bad register parse: ",regtype,regid,toss,numregs)
> +
> +            for immlett,bits,immshift in imms:
> +                arguments.append(hex_common.imm_name(immlett))
> +
> +            f.write("%s(%s) {\n" % (tag, ", ".join(arguments)))
> +            f.write("    %s\n" % hex_common.semdict[tag])
> +            f.write("}\n\n")
> +
> +if __name__ == "__main__":
> +    main()
> diff --git a/target/hexagon/idef-parser/macros.inc b/target/hexagon/idef-parser/macros.inc
> new file mode 100644
> index 0000000000..719bebaee3
> --- /dev/null
> +++ b/target/hexagon/idef-parser/macros.inc
> @@ -0,0 +1,166 @@
> +/*
> + * Copyright(c) 2019-2020 rev.ng Srls. All Rights Reserved.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +/* 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 fCAST8S_16S(A) (fSXTN(64, 128, A))
> +#define fCAST16S_8S(A) (fSXTN(128, 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))))

I guess this is what's in the manual, but my reading of this expression is
"saturate", not "clip".  How does it differ from

  fSATN(U, SRC)

?

> +#define fCARRY_FROM_ADD(A, B, C)                                        \
> +    fGETUWORD(1,                                                        \
> +              fGETUWORD(1, A) +                                         \
> +              fGETUWORD(1, B) +                                         \
> +              fGETUWORD(1,                                              \
> +                        fGETUWORD(0, A) +                               \
> +                        fGETUWORD(0, B) + C))

Hmm.  FWIW, it's probably worth letting this pass through to bison so that you
can expand with tcg_gen_add2.

> +#define fADDSAT64(DST, A, B)                                            \
> +        __a = fCAST8u(A);                                               \
> +        __b = fCAST8u(B);                                               \
> +        __sum = __a + __b;                                              \
> +        __xor = __a ^ __b;                                              \
> +        __mask = 0x8000000000000000ULL;                                 \
> +        if (__xor & __mask) {                                           \
> +            DST = __sum;                                                \
> +        }                                                               \
> +        else if ((__a ^ __sum) & __mask) {                              \
> +            if (__sum & __mask) {                                       \
> +                DST = 0x7FFFFFFFFFFFFFFFLL;                             \
> +                fSET_OVERFLOW();                                        \
> +            } else {                                                    \
> +                DST = 0x8000000000000000ULL;                            \
> +                fSET_OVERFLOW();    

Why not squash some of the subexpressions?

  if ((__a ^ __b) | ~(__a ^ sum)) & __mask) {
    DST = __sum;
  } else {
    DST = ((__sum & __mask) >> 63) + __mask;
    fSET_OVERFLOW();
  }


> +/* Negation operator */
> +#define fLSBOLDNOT(VAL) (!fGETBIT(0, VAL))

  fGETBIT(0, ~VAL) ?

> +# 2. Transform
> +#
> +#        condition ? A = B : A = C
> +#
> +#    in
> +#
> +#        A = (condition ? B : C)
> +#
> +# 3. Remove comments (starting with "#")
> +cpp "$@" | sed 's/\(\s*[{;]\)\s*\([^;?]*\) ? (\([^;=]*\)=\([^;)]*\))\s*:\s*([^;=]*=\([^;)]*\));/\1 \3 = (\2) ? \4 : \5;/' | grep -v '^#'

Wow, that is a really ugly regexp.  It screams for handling this in the parser
instead.  Which honestly doesn't seem that hard.


r~


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

* Re: [PATCH v2 07/10] target/hexagon: import lexer for idef-parser
  2021-02-25 15:18 ` [PATCH v2 07/10] target/hexagon: import lexer for idef-parser Alessandro Di Federico via
@ 2021-02-25 22:24   ` Richard Henderson
  0 siblings, 0 replies; 30+ messages in thread
From: Richard Henderson @ 2021-02-25 22:24 UTC (permalink / raw)
  To: Alessandro Di Federico, qemu-devel
  Cc: Alessandro Di Federico, bcain, babush, tsimpson, nizzo, philmd

On 2/25/21 7:18 AM, Alessandro Di Federico wrote:
> From: Paolo Montesel <babush@rev.ng>
> 
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Paolo Montesel <babush@rev.ng>
> ---
>  target/hexagon/idef-parser/idef-parser.h      | 245 +++++++
>  target/hexagon/idef-parser/idef-parser.lex    | 647 ++++++++++++++++++
>  target/hexagon/meson.build                    |   4 +
>  tests/docker/dockerfiles/alpine.docker        |   1 +
>  tests/docker/dockerfiles/centos7.docker       |   1 +
>  tests/docker/dockerfiles/centos8.docker       |   1 +
>  tests/docker/dockerfiles/debian10.docker      |   1 +
>  .../dockerfiles/fedora-i386-cross.docker      |   1 +
>  .../dockerfiles/fedora-win32-cross.docker     |   1 +
>  .../dockerfiles/fedora-win64-cross.docker     |   1 +
>  tests/docker/dockerfiles/fedora.docker        |   1 +
>  tests/docker/dockerfiles/opensuse-leap.docker |   1 +
>  tests/docker/dockerfiles/ubuntu.docker        |   1 +
>  tests/docker/dockerfiles/ubuntu1804.docker    |   1 +
>  tests/docker/dockerfiles/ubuntu2004.docker    |   3 +-
>  15 files changed, 909 insertions(+), 1 deletion(-)
>  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..d08b9c80ea
> --- /dev/null
> +++ b/target/hexagon/idef-parser/idef-parser.h
> @@ -0,0 +1,245 @@
> +/*
> + * Copyright(c) 2019-2020 rev.ng Srls. All Rights Reserved.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef IDEF_PARSER_H
> +#define IDEF_PARSER_H
> +
> +#include <inttypes.h>
> +#include <stdio.h>
> +#include <stdbool.h>
> +
> +#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)

Uh, right.  Let's not be declaring statically sized 1MB buffers, thanks.

> +#define SIGNATURE_BUF_LEN (128 * 1024)
> +#define HEADER_BUF_LEN (128 * 1024)

Nor 128k buffers.

> +/* Variadic macros to wrap the buffer printing functions */
> +#define EMIT(c, ...)                                                 \
> +    do {                                                             \
> +        (c)->out_c += snprintf((c)->out_buffer + (c)->out_c,         \
> +                               OUT_BUF_LEN - (c)->out_c,             \
> +                               __VA_ARGS__);                         \

There's nothing here that can't be better done with glib GString, with no
pre-determined buffer sizes.

E.g.

  g_string_append_printf((c)->out_str, __VA_ARGS__)

which seems simple enough to drop the macros entirely.

> +/**
> + * Semantic record of the EXTRACT token, identifying the cast operator
> + */
> +typedef struct HexExtract {
> +    int bit_width;          /**< Bit width of the extract operator           */
> +    int storage_bit_width;  /**< Actual bit width of the extract operator    */
> +    bool is_unsigned;       /**< Unsigned flag for the extract operator      */
> +} HexExtract;

All extracts begin at the lsb?

> +/**
> + * Enum of the possible rvalue types, used in the HexValue.type field
> + */
> +enum RvalueUnionTag {REGISTER, TEMP, IMMEDIATE, PREDICATE, VARID};

Typedef this.

> +    enum RvalueUnionTag type; /**< Type of the rvalue                        */

so you can drop the enum here.

> +enum OpType {ADD_OP, SUB_OP, MUL_OP, DIV_OP, ASL_OP, ASR_OP, LSR_OP, ANDB_OP,
> +             ORB_OP, XORB_OP, ANDL_OP, MINI_OP, MAXI_OP, MOD_OP};

Likewise.

> +/**
> + * Data structure including instruction specific information, to be cleared
> + * out after the compilation of each instruction
> + */
> +typedef struct Inst {
> +    char *name;                   /**< Name of the compiled instruction      */
> +    char *code_begin;             /**< Beginning of instruction input code   */
> +    char *code_end;               /**< End of instruction input code         */
> +    int tmp_count;                /**< Index of the last declared TCGv temp  */
> +    int qemu_tmp_count;           /**< Index of the last declared int temp   */
> +    int if_count;                 /**< Index of the last declared if label   */
> +    int error_count;              /**< Number of generated errors            */
> +    Var allocated[ALLOC_LIST_LEN]; /**< Allocated VARID automatic vars       */
> +    int allocated_count;          /**< Elements contained in allocated[]     */
> +    HexValue init_list[INIT_LIST_LEN]; /**< List of initialized registers    */
> +    int init_count;               /**< Number of members of init_list        */
> +} 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      */
> +    char *out_buffer;             /**< Buffer containing the output code     */
> +    int out_c;                    /**< Characters emitted into out_buffer    */
> +    char *signature_buffer;       /**< Buffer containing the signatures code */
> +    int signature_c;              /**< Characters emitted into sig..._buffer */
> +    char *header_buffer;          /**< Buffer containing the output code     */
> +    int header_c;                 /**< Characters emitted into header buffer */
> +    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    */
> +    int total_insn;               /**< Number of instructions in input file  */
> +    int implemented_insn;         /**< Instruction compiled without errors   */
> +    Inst inst;                  /**< Parsing data of the current inst      */
> +} Context;

I have a notion that every "char *" should be "GString *".


> +"(unsigned int)"         { /* Skip c-style casts */ }

Why is this not treated like

> +"(size8"[us]"_t)"        { yylval->cast.bit_width = 8;
> +                           yylval->cast.is_unsigned = ((yytext[6]) == 'u');
> +                           return CAST; }
> +"(size16"[us]"_t)"       { yylval->cast.bit_width = 16;
> +                           yylval->cast.is_unsigned = ((yytext[7]) == 'u');
> +                           return CAST; }
> +"(int)"                  { yylval->cast.bit_width = 32;
> +                           yylval->cast.is_unsigned = false;
> +                           return CAST; }

these?  Certainly it should be placed nearby.

> +"CANCEL"                 { return CANC; }

Any reason not to spell out CANCEL?

> +"fREAD_LC"{ZERO_ONE}     { yylval->rvalue.type = REGISTER;
> +                           yylval->rvalue.reg.type = CONTROL;
> +                           yylval->rvalue.reg.id = LC0 + atoi(yytext + 8);

Why atoi and not yytext[8] - '0'?
While we're at it, {ZERO_ONE} seems unnecessary obfuscation over [01].

> +{DIGIT}+                 { yylval->rvalue.type = IMMEDIATE;
> +                           yylval->rvalue.bit_width = 64;
> +                           yylval->rvalue.is_unsigned = false;
> +                           yylval->rvalue.imm.type = VALUE;
> +                           yylval->rvalue.imm.value = atoi(yytext);
> +                           return IMM; }
> +{DIGIT}+"LL"             { yylval->rvalue.type = IMMEDIATE;
> +                           yylval->rvalue.bit_width = 64;
> +                           yylval->rvalue.is_unsigned = false;
> +                           yylval->rvalue.imm.type = VALUE;
> +                           yylval->rvalue.imm.value = atoi(yytext);

I assume "LL" means it's supposed to be producing a 64-bit result, which atoi
will not do.  You need to be using strtoll.

> +"0x"{HEX_DIGIT}+"ULL"    { yylval->rvalue.type = IMMEDIATE;
> +                           yylval->rvalue.bit_width = 64;
> +                           yylval->rvalue.is_unsigned = true;
> +                           yylval->rvalue.imm.type = VALUE;
> +                           yylval->rvalue.imm.value = strtoul(yytext, NULL, 16);

And of course here, strtoull.

> +{VAR_ID}                 { /* Variable name, we adopt the C names convention */
> +                           yylval->rvalue.type = VARID;
> +                           yylval->rvalue.var.name = strndup(yytext,
> +                                                             ALLOC_NAME_SIZE);
> +                           /* Default types are int */
> +                           yylval->rvalue.bit_width = 32;
> +                           if (yylval->rvalue.var.name == NULL) {

This is the sort of check you need not be doing, by using the correct
functions.  In this case, g_string_new(yytext).

Glib generally asserts on memory allocation failure -- you have to explicitly
use a "*_try_*" function if you want to manage failure yourself.  Which of
course we don't.


r~


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

* Re: [PATCH v2 08/10] target/hexagon: import parser for idef-parser
  2021-02-25 15:18 ` [PATCH v2 08/10] target/hexagon: import parser " Alessandro Di Federico via
@ 2021-02-26  3:30   ` Richard Henderson
  2021-03-01 14:50     ` Alessandro Di Federico via
  2021-03-23 16:52     ` Paolo Montesel via
  0 siblings, 2 replies; 30+ messages in thread
From: Richard Henderson @ 2021-02-26  3:30 UTC (permalink / raw)
  To: Alessandro Di Federico, qemu-devel
  Cc: Alessandro Di Federico, bcain, babush, tsimpson, nizzo, philmd

On 2/25/21 7:18 AM, Alessandro Di Federico wrote:
> +instructions : instruction instructions
> +| %empty
> +;

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

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

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

Surely this belongs in the error alternative.

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

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

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

These are identical.

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

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

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

> +arguments : LPAR RPAR

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

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

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

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

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

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

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

A loop, really?  Surely this is just

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

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

You can drop all the empty code blocks.

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

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

> +for_statement : FOR LPAR IMM ASSIGN IMM SEMI IMM LT IMM SEMI IMM PLUSPLUS RPAR
> +{
> +    @1.last_column = @13.last_column;
> +    OUT(c, &@1, "for (int ", &$3, " = ", &$5, "; ", &$7, " < ", &$9);
> +    OUT(c, &@1, "; ", &$11, "++) {\n");
> +}
> +code_block
> +{
> +    OUT(c, &@1, "}\n");
> +}
> +;
> +
> +for_statement : FOR LPAR IMM ASSIGN IMM SEMI IMM LT IMM SEMI IMM INC IMM RPAR

Why separate these productions, and not use |?

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

Do you actually use the label before...

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

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


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

Useless assignment.

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

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

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

Why no gen_unary_op()?

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

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

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

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

E.g. instead of

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

you'd be able to do

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

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

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

tcg_gen_abs, surely via gen_unary_op.

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

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

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

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

Merge to a single printf.

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

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

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

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

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

Drop all inline markup and let the compiler decide.

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

Drop useless braces like this.

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

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

Then you don't need any of the complication of

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

this, you'd only have

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

this.

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

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

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

here, and so forth.

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

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

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

Er... this is

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

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

What semantics are you actually after?

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

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

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

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

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

I strongly suggest TCG_COND_GEU.

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

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

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

cut-and-paste error

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

and again.

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

tcg_gen_smin
tcg_gen_umin

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

tcg_gen_smax
tcg_gen_umax

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

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

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

>From here is

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

tcg_gen_bswap32

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

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

this one.

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

tcg_gen_rotl

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

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

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

IMMEDIATEs are never equal?

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

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

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

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


r~


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

* Re: [PATCH v2 09/10] target/hexagon: call idef-parser functions
  2021-02-25 15:18 ` [PATCH v2 09/10] target/hexagon: call idef-parser functions Alessandro Di Federico via
@ 2021-02-26  3:47   ` Richard Henderson
  2021-03-01 14:49     ` Alessandro Di Federico via
  0 siblings, 1 reply; 30+ messages in thread
From: Richard Henderson @ 2021-02-26  3:47 UTC (permalink / raw)
  To: Alessandro Di Federico, qemu-devel
  Cc: Alessandro Di Federico, bcain, babush, tsimpson, nizzo, philmd

On 2/25/21 7:18 AM, Alessandro Di Federico wrote:
> +            elif hex_common.is_new_val(regtype, regid, tag):
> +                declared.append("%s%sN" % (regtype,regid))
> +            else:
> +                print("Bad register parse: ",regtype,regid,toss,numregs)

print, but nothing to force exit-with-failure, now or at a later date.  Just
raise a python exception?

Otherwise looks fine.


r~


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

* Re: [PATCH v2 10/10] target/hexagon: import additional tests
  2021-02-25 15:18 ` [PATCH v2 10/10] target/hexagon: import additional tests Alessandro Di Federico via
@ 2021-02-26  3:52   ` Richard Henderson
  0 siblings, 0 replies; 30+ messages in thread
From: Richard Henderson @ 2021-02-26  3:52 UTC (permalink / raw)
  To: Alessandro Di Federico, qemu-devel
  Cc: Alessandro Di Federico, bcain, babush, tsimpson, nizzo, philmd

On 2/25/21 7:18 AM, Alessandro Di Federico wrote:
> +++ b/tests/tcg/hexagon/first.S
> @@ -21,24 +21,24 @@
>  
>  #define FD_STDOUT                1
>  
> -	.type	str,@object
> -	.section	.rodata
> +    .type	str,@object
> +    .section	.rodata
>  str:
> -	.string	"Hello!\n"
> -	.size	str, 8
> +    .string	"Hello!\n"
> +    .size	str, 8
>  
>  .text
>  .global _start
>  _start:
> -	r6 = #SYS_write
> -	r0 = #FD_STDOUT
> -	r1 = ##str
> -	r2 = #7
> -	trap0(#1)
> +    r6 = #SYS_write
> +    r0 = #FD_STDOUT
> +    r1 = ##str
> +    r2 = #7
> +    trap0(#1)
>  

Don't re-indent stuff.  Otherwise, it all looks fairly straightforward.

r~


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

* Re: [PATCH v2 09/10] target/hexagon: call idef-parser functions
  2021-02-26  3:47   ` Richard Henderson
@ 2021-03-01 14:49     ` Alessandro Di Federico via
  0 siblings, 0 replies; 30+ messages in thread
From: Alessandro Di Federico via @ 2021-03-01 14:49 UTC (permalink / raw)
  To: Richard Henderson
  Cc: Alessandro Di Federico, qemu-devel, tsimpson, bcain, babush,
	nizzo, philmd

On Thu, 25 Feb 2021 19:47:04 -0800
Richard Henderson <richard.henderson@linaro.org> wrote:

> On 2/25/21 7:18 AM, Alessandro Di Federico wrote:
> > +            elif hex_common.is_new_val(regtype, regid, tag):
> > +                declared.append("%s%sN" % (regtype,regid))
> > +            else:
> > +                print("Bad register parse:",regtype,regid,toss,numregs)  
> 
> print, but nothing to force exit-with-failure, now or at a later
> date.  Just raise a python exception?

Yes, the whole error handling should be improved in the script.

Our goal was to get this patchset in and then do another pass to clean
up things later on. However, if you deem this is the proper time to
do it, we can go for it.

-- 
Alessandro Di Federico
rev.ng


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

* Re: [PATCH v2 02/10] target/hexagon: import README for idef-parser
  2021-02-25 20:20   ` Richard Henderson
@ 2021-03-01 14:50     ` Alessandro Di Federico via
  2021-03-10 15:48     ` Taylor Simpson
  1 sibling, 0 replies; 30+ messages in thread
From: Alessandro Di Federico via @ 2021-03-01 14:50 UTC (permalink / raw)
  To: Richard Henderson
  Cc: Alessandro Di Federico, qemu-devel, tsimpson, bcain, babush,
	nizzo, philmd

On Thu, 25 Feb 2021 12:20:53 -0800
Richard Henderson <richard.henderson@linaro.org> wrote:
> This is odd, as is the description of why.  Yes, if RdV is read
> without initialization, TCG middle-end will abort (at least with
> --enable-debug-tcg enabling the assertions).  But you've just said
> that "no reading" was found.

When we say that no reading was found, we mean that it was not
initialized by the caller. The term "reading" is a leftover from how
the parser input was organized in the first iterations of the base
patchset.

I'll rephrase that.

> So why did you perform this dummy initialization, which will be
> eliminated later?

The initialization is redundant in this specific example, but, in
general, non-initialized values are assumed to be zero-initialized.
For instance when you're writing a 64-bit integer piecewise, by OR-ing
two 32-bit integers, it matters.

In short: useless in this case (but DCE'd by the mid-end), important in
general.
 
> So, I take it from this that you're emitting tcg directly from within
> the parser, and not generating any kind of abstract syntax tree?

Yes. There a few spots where an AST would have been beneficial, but
overall we deem it would increase the complexity of the parser with
limited return.

-- 
Alessandro Di Federico
rev.ng


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

* Re: [PATCH v2 08/10] target/hexagon: import parser for idef-parser
  2021-02-26  3:30   ` Richard Henderson
@ 2021-03-01 14:50     ` Alessandro Di Federico via
  2021-03-23 16:52     ` Paolo Montesel via
  1 sibling, 0 replies; 30+ messages in thread
From: Alessandro Di Federico via @ 2021-03-01 14:50 UTC (permalink / raw)
  To: Richard Henderson
  Cc: Alessandro Di Federico, qemu-devel, tsimpson, bcain, babush,
	nizzo, philmd

On Thu, 25 Feb 2021 19:30:14 -0800
Richard Henderson <richard.henderson@linaro.org> wrote:

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

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

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

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

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

Yes, `sed` is a workaround I really don't like too. But preprocessing
with `cpp` saves us from having to handle a larger, redundant language.
After all, the input language is designed to be expanded through the
preprocessor, although with a different set of macros. I'd keep that
part.

-- 
Alessandro Di Federico
rev.ng


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

* Re: [PATCH v2 06/10] target/hexagon: prepare input for the idef-parser
  2021-02-25 21:34   ` Richard Henderson
@ 2021-03-01 16:26     ` Paolo Montesel via
  0 siblings, 0 replies; 30+ messages in thread
From: Paolo Montesel via @ 2021-03-01 16:26 UTC (permalink / raw)
  To: Richard Henderson
  Cc: Alessandro Di Federico, qemu-devel, Taylor Simpson, Brian Cain,
	nizzo, philmd, Alessandro Di Federico

> > +/* 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 fCAST8S_16S(A) (fSXTN(64, 128, A))
> > +#define fCAST16S_8S(A) (fSXTN(128, 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))))
>
> I guess this is what's in the manual, but my reading of this expression is
> "saturate", not "clip".  How does it differ from
>
>   fSATN(U, SRC)
>
> ?

Their semantics are different.
E.g.:
- fCLIP(dst, 0x80, 8) => dst = 0x80
- fSATN(8, 0x80) => 0x7F

Take a look at `target/hexagon/macros.h` to see their slow
(macro/helper-based) implementation, which is basically our reference.

As for the naming, it's not up to us.

Paolo


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

* RE: [PATCH v2 02/10] target/hexagon: import README for idef-parser
  2021-02-25 20:20   ` Richard Henderson
  2021-03-01 14:50     ` Alessandro Di Federico via
@ 2021-03-10 15:48     ` Taylor Simpson
  2021-03-18 17:26       ` Alessandro Di Federico via
  1 sibling, 1 reply; 30+ messages in thread
From: Taylor Simpson @ 2021-03-10 15:48 UTC (permalink / raw)
  To: Richard Henderson, Alessandro Di Federico, qemu-devel
  Cc: babush, Brian Cain, Alessandro Di Federico, nizzo, philmd



> -----Original Message-----
> From: Richard Henderson <richard.henderson@linaro.org>
> Sent: Thursday, February 25, 2021 2:21 PM
> To: Alessandro Di Federico <ale.qemu@rev.ng>; qemu-devel@nongnu.org
> Cc: Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; babush@rev.ng; nizzo@rev.ng; philmd@redhat.com;
> Alessandro Di Federico <ale@rev.ng>
> Subject: Re: [PATCH v2 02/10] target/hexagon: import README for idef-
> parser
>
> On 2/25/21 7:18 AM, Alessandro Di Federico wrote:
> > +Now let's have a quick look at the generated code, line by line.
> > +
> > +::
> > +
> > +   tcg_gen_movi_i32(RdV, 0);
> > +
> > +This code starts by initializing ``RdV``, since reading from that register
> > +without initialization will cause a segmentation fault by QEMU.  This is
> emitted
> > +because a declaration of the ``RdV`` register was parsed, but no reading of
> the
> > +``RdV`` register was found.
>
> This is odd, as is the description of why.  Yes, if RdV is read without
> initialization, TCG middle-end will abort (at least with --enable-debug-tcg
> enabling the assertions).  But you've just said that "no reading" was found.
> So why did you perform this dummy initialization, which will be eliminated
> later?

Which instructions require this?  There must be an attribute that we could check to see if it is needed before emitting the TCG.

Taylor


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

* Re: [PATCH v2 02/10] target/hexagon: import README for idef-parser
  2021-03-10 15:48     ` Taylor Simpson
@ 2021-03-18 17:26       ` Alessandro Di Federico via
  2021-04-05 21:26         ` Taylor Simpson
  0 siblings, 1 reply; 30+ messages in thread
From: Alessandro Di Federico via @ 2021-03-18 17:26 UTC (permalink / raw)
  To: Taylor Simpson
  Cc: Richard Henderson, qemu-devel, Brian Cain, babush, nizzo, philmd

On Wed, 10 Mar 2021 15:48:14 +0000
Taylor Simpson <tsimpson@quicinc.com> wrote:

> Which instructions require this?  There must be an attribute that we
> could check to see if it is needed before emitting the TCG.

The following should be an example of an instruction that requires
zero-initialization:

    /* S2_vsplatrh */
    void emit_S2_vsplatrh(DisasContext *ctx, Insn *insn, Packet *pkt,
                          TCGv_i64 RddV, TCGv_i32 RsV)
    /*  for (i=0;i<4;i++) { fSETHALF(i,RddV, fGETHALF(0,RsV)); } } */
    {
      tcg_gen_movi_i64(RddV, 0);
      for (int i = ((int64_t)0ULL); i < ((int64_t)4ULL); i++) {
        TCGv_i32 tmp_0 = tcg_temp_new_i32();
        tcg_gen_sextract_i32(tmp_0, RsV, ((int64_t)0ULL) * 16, 16);
        TCGv_i64 tmp_1 = tcg_temp_new_i64();
        tcg_gen_ext_i32_i64(tmp_1, tmp_0);
        tcg_temp_free_i32(tmp_0);
        tcg_gen_deposit_i64(RddV, RddV, tmp_1, i * 16, 16);
        tcg_temp_free_i64(tmp_1);
      }
    }

If we don't zero-initialize RddV, the deposit instruction will read
uninitialized data.

Note that, IIRC, `RddV` is not always a global variable, which could be
safely read, but it might be an uninitialized TCGv that will be
written to the CPU state in the commit phase.

-- 
Alessandro Di Federico
rev.ng


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

* Re: [PATCH v2 08/10] target/hexagon: import parser for idef-parser
  2021-02-26  3:30   ` Richard Henderson
  2021-03-01 14:50     ` Alessandro Di Federico via
@ 2021-03-23 16:52     ` Paolo Montesel via
  1 sibling, 0 replies; 30+ messages in thread
From: Paolo Montesel via @ 2021-03-23 16:52 UTC (permalink / raw)
  To: Richard Henderson
  Cc: Alessandro Di Federico, qemu-devel, Taylor Simpson, Brian Cain,
	nizzo, Philippe Mathieu-Daudé,
	Alessandro Di Federico

Thanks for the feedback, it helped us improve the implementation quite a bit.

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

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

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

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

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

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

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

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

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

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

~Paolo


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

* RE: [PATCH v2 02/10] target/hexagon: import README for idef-parser
  2021-03-18 17:26       ` Alessandro Di Federico via
@ 2021-04-05 21:26         ` Taylor Simpson
  0 siblings, 0 replies; 30+ messages in thread
From: Taylor Simpson @ 2021-04-05 21:26 UTC (permalink / raw)
  To: Alessandro Di Federico
  Cc: Brian Cain, Richard Henderson, qemu-devel, babush, nizzo, philmd



> -----Original Message-----
> From: Alessandro Di Federico <ale.qemu@rev.ng>
> Sent: Thursday, March 18, 2021 12:27 PM
> To: Taylor Simpson <tsimpson@quicinc.com>
> Cc: Richard Henderson <richard.henderson@linaro.org>; qemu-
> devel@nongnu.org; Brian Cain <bcain@quicinc.com>; babush@rev.ng;
> nizzo@rev.ng; philmd@redhat.com
> Subject: Re: [PATCH v2 02/10] target/hexagon: import README for idef-
> parser
>
> On Wed, 10 Mar 2021 15:48:14 +0000
> Taylor Simpson <tsimpson@quicinc.com> wrote:
>
> > Which instructions require this?  There must be an attribute that we
> > could check to see if it is needed before emitting the TCG.
>
> The following should be an example of an instruction that requires
> zero-initialization:
>
>     /* S2_vsplatrh */
>     void emit_S2_vsplatrh(DisasContext *ctx, Insn *insn, Packet *pkt,
>                           TCGv_i64 RddV, TCGv_i32 RsV)
>     /*  for (i=0;i<4;i++) { fSETHALF(i,RddV, fGETHALF(0,RsV)); } } */
>     {
>       tcg_gen_movi_i64(RddV, 0);
>       for (int i = ((int64_t)0ULL); i < ((int64_t)4ULL); i++) {
>         TCGv_i32 tmp_0 = tcg_temp_new_i32();
>         tcg_gen_sextract_i32(tmp_0, RsV, ((int64_t)0ULL) * 16, 16);
>         TCGv_i64 tmp_1 = tcg_temp_new_i64();
>         tcg_gen_ext_i32_i64(tmp_1, tmp_0);
>         tcg_temp_free_i32(tmp_0);
>         tcg_gen_deposit_i64(RddV, RddV, tmp_1, i * 16, 16);
>         tcg_temp_free_i64(tmp_1);
>       }
>     }
>
> If we don't zero-initialize RddV, the deposit instruction will read
> uninitialized data.
>
> Note that, IIRC, `RddV` is not always a global variable, which could be
> safely read, but it might be an uninitialized TCGv that will be
> written to the CPU state in the commit phase.

Correct, in fact you should assume it is *always* uninitialized.

For instructions like vsplatrh, the original C semantics are OK because all parts of the result are eventually written.  So, you could detect this in the parser or manually add an attribute.  If you want to add an attribute:
1) add a line to attribs_def.h.inc
2) Figure out which macros lead to a problem and add them to calculate_attribs in hex_common.py


Thanks,
Taylor



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

end of thread, other threads:[~2021-04-05 21:27 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-25 15:18 [PATCH v2 00/10] target/hexagon: introduce idef-parser Alessandro Di Federico via
2021-02-25 15:18 ` [PATCH v2 01/10] target/hexagon: update MAINTAINERS for idef-parser Alessandro Di Federico via
2021-02-25 20:46   ` Richard Henderson
2021-02-25 15:18 ` [PATCH v2 02/10] target/hexagon: import README " Alessandro Di Federico via
2021-02-25 20:20   ` Richard Henderson
2021-03-01 14:50     ` Alessandro Di Federico via
2021-03-10 15:48     ` Taylor Simpson
2021-03-18 17:26       ` Alessandro Di Federico via
2021-04-05 21:26         ` Taylor Simpson
2021-02-25 15:18 ` [PATCH v2 03/10] target/hexagon: make helper functions non-static Alessandro Di Federico via
2021-02-25 20:47   ` Richard Henderson
2021-02-25 15:18 ` [PATCH v2 04/10] target/hexagon: introduce new helper functions Alessandro Di Federico via
2021-02-25 20:45   ` Richard Henderson
2021-02-25 15:18 ` [PATCH v2 05/10] target/hexagon: expose next PC in DisasContext Alessandro Di Federico via
2021-02-25 20:48   ` Richard Henderson
2021-02-25 15:18 ` [PATCH v2 06/10] target/hexagon: prepare input for the idef-parser Alessandro Di Federico via
2021-02-25 21:34   ` Richard Henderson
2021-03-01 16:26     ` Paolo Montesel via
2021-02-25 15:18 ` [PATCH v2 07/10] target/hexagon: import lexer for idef-parser Alessandro Di Federico via
2021-02-25 22:24   ` Richard Henderson
2021-02-25 15:18 ` [PATCH v2 08/10] target/hexagon: import parser " Alessandro Di Federico via
2021-02-26  3:30   ` Richard Henderson
2021-03-01 14:50     ` Alessandro Di Federico via
2021-03-23 16:52     ` Paolo Montesel via
2021-02-25 15:18 ` [PATCH v2 09/10] target/hexagon: call idef-parser functions Alessandro Di Federico via
2021-02-26  3:47   ` Richard Henderson
2021-03-01 14:49     ` Alessandro Di Federico via
2021-02-25 15:18 ` [PATCH v2 10/10] target/hexagon: import additional tests Alessandro Di Federico via
2021-02-26  3:52   ` Richard Henderson
2021-02-25 16:03 ` [PATCH v2 00/10] target/hexagon: introduce idef-parser no-reply

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).