All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 00/14] target/hexagon: introduce idef-parser
@ 2021-06-19  9:36 Alessandro Di Federico via
  2021-06-19  9:37 ` [PATCH v5 01/14] tcg: expose TCGCond manipulation routines Alessandro Di Federico via
                   ` (13 more replies)
  0 siblings, 14 replies; 38+ messages in thread
From: Alessandro Di Federico via @ 2021-06-19  9:36 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 fifth iteration of the patchset and includes fixes suggested in
previous iterations.

This patchset also drops some macro overrides that are no longer
necessary, since the instructions they were handling are now implemented
in `idef-parser`.

`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.
* The build on the CI fails for the cross-i386-* jobs. This seems to be
  due to the fact that, despite we specified glib as a native
  dependency, meson still chooses the i386 bit version of the library,
  as opposed to the x86-64.
  Help on this matter is appreciated.
  We also introduced a commit to make sure containers produced by the
  developer Docker registry (as opposed to the official one) is
  used. Otherwise, the changes we made to the containers would not
  take effect.
  Building debian-hexagon-cross still fails since it's not built by
  the CI by default.

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

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

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

 .gitlab-ci.d/container-cross.yml              |    2 +-
 .gitlab-ci.d/container-template.yml           |    4 +-
 MAINTAINERS                                   |    8 +
 include/tcg/tcg-cond.h                        |  101 +
 include/tcg/tcg.h                             |   70 +-
 target/hexagon/README                         |    5 +
 target/hexagon/gen_helper_funcs.py            |    5 +-
 target/hexagon/gen_helper_protos.py           |    5 +-
 target/hexagon/gen_idef_parser_funcs.py       |  114 +
 target/hexagon/gen_tcg.h                      |  528 ----
 target/hexagon/gen_tcg_funcs.py               |   28 +-
 target/hexagon/genptr.c                       |  250 +-
 target/hexagon/genptr.h                       |   29 +
 target/hexagon/hex_common.py                  |   10 +
 target/hexagon/idef-parser/README.rst         |  447 +++
 target/hexagon/idef-parser/idef-parser.h      |  262 ++
 target/hexagon/idef-parser/idef-parser.lex    |  597 ++++
 target/hexagon/idef-parser/idef-parser.y      |  961 +++++++
 target/hexagon/idef-parser/macros.inc         |  153 ++
 target/hexagon/idef-parser/parser-helpers.c   | 2396 +++++++++++++++++
 target/hexagon/idef-parser/parser-helpers.h   |  347 +++
 target/hexagon/idef-parser/prepare            |   24 +
 target/hexagon/macros.h                       |  209 +-
 target/hexagon/meson.build                    |  113 +-
 target/hexagon/op_helper.c                    |  119 -
 target/hexagon/translate.c                    |    3 +-
 target/hexagon/translate.h                    |    1 +
 tests/docker/dockerfiles/alpine.docker        |    2 +
 tests/docker/dockerfiles/centos8.docker       |    2 +
 tests/docker/dockerfiles/debian-amd64.docker  |    2 +
 tests/docker/dockerfiles/debian10.docker      |    3 +
 .../dockerfiles/fedora-i386-cross.docker      |    3 +
 .../dockerfiles/fedora-win32-cross.docker     |    3 +
 .../dockerfiles/fedora-win64-cross.docker     |    3 +
 tests/docker/dockerfiles/fedora.docker        |    2 +
 tests/docker/dockerfiles/opensuse-leap.docker |    2 +
 tests/docker/dockerfiles/ubuntu.docker        |    3 +
 tests/docker/dockerfiles/ubuntu1804.docker    |    3 +
 tests/docker/dockerfiles/ubuntu2004.docker    |    5 +-
 tests/tcg/hexagon/Makefile.target             |   36 +-
 tests/tcg/hexagon/crt.S                       |   28 +
 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_overflow.S             |   63 +
 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 +
 74 files changed, 6875 insertions(+), 1053 deletions(-)
 create mode 100644 include/tcg/tcg-cond.h
 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_overflow.S
 create mode 100644 tests/tcg/hexagon/test_packet.S
 create mode 100644 tests/tcg/hexagon/test_reorder.S
 create mode 100644 tests/tcg/hexagon/test_round.S
 create mode 100644 tests/tcg/hexagon/test_vavgw.S
 create mode 100644 tests/tcg/hexagon/test_vcmpb.S
 create mode 100644 tests/tcg/hexagon/test_vcmpw.S
 create mode 100644 tests/tcg/hexagon/test_vcmpy.S
 create mode 100644 tests/tcg/hexagon/test_vlsrw.S
 create mode 100644 tests/tcg/hexagon/test_vmaxh.S
 create mode 100644 tests/tcg/hexagon/test_vminh.S
 create mode 100644 tests/tcg/hexagon/test_vpmpyh.S
 create mode 100644 tests/tcg/hexagon/test_vspliceb.S

-- 
2.31.1



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

* [PATCH v5 01/14] tcg: expose TCGCond manipulation routines
  2021-06-19  9:36 [PATCH v5 00/14] target/hexagon: introduce idef-parser Alessandro Di Federico via
@ 2021-06-19  9:37 ` Alessandro Di Federico via
  2021-06-19 13:51   ` Richard Henderson
  2021-06-19  9:37 ` [PATCH v5 02/14] target/hexagon: update MAINTAINERS for idef-parser Alessandro Di Federico via
                   ` (12 subsequent siblings)
  13 siblings, 1 reply; 38+ messages in thread
From: Alessandro Di Federico via @ 2021-06-19  9:37 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 commit moves into a separate file routines used to manipulate
TCGCond. These will be employed by the idef-parser.

Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Paolo Montesel <babush@rev.ng>
---
 include/tcg/tcg-cond.h | 101 +++++++++++++++++++++++++++++++++++++++++
 include/tcg/tcg.h      |  70 +---------------------------
 2 files changed, 102 insertions(+), 69 deletions(-)
 create mode 100644 include/tcg/tcg-cond.h

diff --git a/include/tcg/tcg-cond.h b/include/tcg/tcg-cond.h
new file mode 100644
index 0000000000..2a38a386d4
--- /dev/null
+++ b/include/tcg/tcg-cond.h
@@ -0,0 +1,101 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef TCG_COND_H
+#define TCG_COND_H
+
+/*
+ * Conditions.  Note that these are laid out for easy manipulation by
+ * the functions below:
+ *    bit 0 is used for inverting;
+ *    bit 1 is signed,
+ *    bit 2 is unsigned,
+ *    bit 3 is used with bit 0 for swapping signed/unsigned.
+ */
+typedef enum {
+    /* non-signed */
+    TCG_COND_NEVER  = 0 | 0 | 0 | 0,
+    TCG_COND_ALWAYS = 0 | 0 | 0 | 1,
+    TCG_COND_EQ     = 8 | 0 | 0 | 0,
+    TCG_COND_NE     = 8 | 0 | 0 | 1,
+    /* signed */
+    TCG_COND_LT     = 0 | 0 | 2 | 0,
+    TCG_COND_GE     = 0 | 0 | 2 | 1,
+    TCG_COND_LE     = 8 | 0 | 2 | 0,
+    TCG_COND_GT     = 8 | 0 | 2 | 1,
+    /* unsigned */
+    TCG_COND_LTU    = 0 | 4 | 0 | 0,
+    TCG_COND_GEU    = 0 | 4 | 0 | 1,
+    TCG_COND_LEU    = 8 | 4 | 0 | 0,
+    TCG_COND_GTU    = 8 | 4 | 0 | 1,
+} TCGCond;
+
+/* Invert the sense of the comparison.  */
+static inline TCGCond tcg_invert_cond(TCGCond c)
+{
+    return (TCGCond)(c ^ 1);
+}
+
+/* Swap the operands in a comparison.  */
+static inline TCGCond tcg_swap_cond(TCGCond c)
+{
+    return c & 6 ? (TCGCond)(c ^ 9) : c;
+}
+
+/* Create an "unsigned" version of a "signed" comparison.  */
+static inline TCGCond tcg_unsigned_cond(TCGCond c)
+{
+    return c & 2 ? (TCGCond)(c ^ 6) : c;
+}
+
+/* Create a "signed" version of an "unsigned" comparison.  */
+static inline TCGCond tcg_signed_cond(TCGCond c)
+{
+    return c & 4 ? (TCGCond)(c ^ 6) : c;
+}
+
+/* Must a comparison be considered unsigned?  */
+static inline bool is_unsigned_cond(TCGCond c)
+{
+    return (c & 4) != 0;
+}
+
+/*
+ * Create a "high" version of a double-word comparison.
+ * This removes equality from a LTE or GTE comparison.
+ */
+static inline TCGCond tcg_high_cond(TCGCond c)
+{
+    switch (c) {
+    case TCG_COND_GE:
+    case TCG_COND_LE:
+    case TCG_COND_GEU:
+    case TCG_COND_LEU:
+        return (TCGCond)(c ^ 8);
+    default:
+        return c;
+    }
+}
+
+#endif /* TCG_COND_H */
diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
index 064dab383b..23a49122da 100644
--- a/include/tcg/tcg.h
+++ b/include/tcg/tcg.h
@@ -33,6 +33,7 @@
 #include "tcg/tcg-mo.h"
 #include "tcg-target.h"
 #include "qemu/int128.h"
+#include "tcg/tcg-cond.h"
 
 /* XXX: make safe guess about sizes */
 #define MAX_OP_PER_INSTR 266
@@ -406,75 +407,6 @@ typedef TCGv_ptr TCGv_env;
 /* Used to align parameters.  See the comment before tcgv_i32_temp.  */
 #define TCG_CALL_DUMMY_ARG      ((TCGArg)0)
 
-/* Conditions.  Note that these are laid out for easy manipulation by
-   the functions below:
-     bit 0 is used for inverting;
-     bit 1 is signed,
-     bit 2 is unsigned,
-     bit 3 is used with bit 0 for swapping signed/unsigned.  */
-typedef enum {
-    /* non-signed */
-    TCG_COND_NEVER  = 0 | 0 | 0 | 0,
-    TCG_COND_ALWAYS = 0 | 0 | 0 | 1,
-    TCG_COND_EQ     = 8 | 0 | 0 | 0,
-    TCG_COND_NE     = 8 | 0 | 0 | 1,
-    /* signed */
-    TCG_COND_LT     = 0 | 0 | 2 | 0,
-    TCG_COND_GE     = 0 | 0 | 2 | 1,
-    TCG_COND_LE     = 8 | 0 | 2 | 0,
-    TCG_COND_GT     = 8 | 0 | 2 | 1,
-    /* unsigned */
-    TCG_COND_LTU    = 0 | 4 | 0 | 0,
-    TCG_COND_GEU    = 0 | 4 | 0 | 1,
-    TCG_COND_LEU    = 8 | 4 | 0 | 0,
-    TCG_COND_GTU    = 8 | 4 | 0 | 1,
-} TCGCond;
-
-/* Invert the sense of the comparison.  */
-static inline TCGCond tcg_invert_cond(TCGCond c)
-{
-    return (TCGCond)(c ^ 1);
-}
-
-/* Swap the operands in a comparison.  */
-static inline TCGCond tcg_swap_cond(TCGCond c)
-{
-    return c & 6 ? (TCGCond)(c ^ 9) : c;
-}
-
-/* Create an "unsigned" version of a "signed" comparison.  */
-static inline TCGCond tcg_unsigned_cond(TCGCond c)
-{
-    return c & 2 ? (TCGCond)(c ^ 6) : c;
-}
-
-/* Create a "signed" version of an "unsigned" comparison.  */
-static inline TCGCond tcg_signed_cond(TCGCond c)
-{
-    return c & 4 ? (TCGCond)(c ^ 6) : c;
-}
-
-/* Must a comparison be considered unsigned?  */
-static inline bool is_unsigned_cond(TCGCond c)
-{
-    return (c & 4) != 0;
-}
-
-/* Create a "high" version of a double-word comparison.
-   This removes equality from a LTE or GTE comparison.  */
-static inline TCGCond tcg_high_cond(TCGCond c)
-{
-    switch (c) {
-    case TCG_COND_GE:
-    case TCG_COND_LE:
-    case TCG_COND_GEU:
-    case TCG_COND_LEU:
-        return (TCGCond)(c ^ 8);
-    default:
-        return c;
-    }
-}
-
 typedef enum TCGTempVal {
     TEMP_VAL_DEAD,
     TEMP_VAL_REG,
-- 
2.31.1



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

* [PATCH v5 02/14] target/hexagon: update MAINTAINERS for idef-parser
  2021-06-19  9:36 [PATCH v5 00/14] target/hexagon: introduce idef-parser Alessandro Di Federico via
  2021-06-19  9:37 ` [PATCH v5 01/14] tcg: expose TCGCond manipulation routines Alessandro Di Federico via
@ 2021-06-19  9:37 ` Alessandro Di Federico via
  2021-06-19  9:37 ` [PATCH v5 03/14] target/hexagon: import README " Alessandro Di Federico via
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 38+ messages in thread
From: Alessandro Di Federico via @ 2021-06-19  9:37 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>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
 MAINTAINERS | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 7d9cd29042..7fd32062be 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -192,6 +192,8 @@ Hexagon TCG CPUs
 M: Taylor Simpson <tsimpson@quicinc.com>
 S: Supported
 F: target/hexagon/
+X: target/hexagon/idef-parser/
+X: target/hexagon/gen_idef_parser_funcs.py
 F: linux-user/hexagon/
 F: tests/tcg/hexagon/
 F: disas/hexagon.c
@@ -199,6 +201,12 @@ F: default-configs/targets/hexagon-linux-user.mak
 F: docker/dockerfiles/debian-hexagon-cross.docker
 F: docker/dockerfiles/debian-hexagon-cross.docker.d/build-toolchain.sh
 
+Hexagon idef-parser
+M: Alessandro Di Federico <ale@rev.ng>
+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.31.1



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

* [PATCH v5 03/14] target/hexagon: import README for idef-parser
  2021-06-19  9:36 [PATCH v5 00/14] target/hexagon: introduce idef-parser Alessandro Di Federico via
  2021-06-19  9:37 ` [PATCH v5 01/14] tcg: expose TCGCond manipulation routines Alessandro Di Federico via
  2021-06-19  9:37 ` [PATCH v5 02/14] target/hexagon: update MAINTAINERS for idef-parser Alessandro Di Federico via
@ 2021-06-19  9:37 ` Alessandro Di Federico via
  2021-06-23 15:46   ` Taylor Simpson
  2021-06-19  9:37 ` [PATCH v5 04/14] target/hexagon: make slot number an unsigned Alessandro Di Federico via
                   ` (10 subsequent siblings)
  13 siblings, 1 reply; 38+ messages in thread
From: Alessandro Di Federico via @ 2021-06-19  9:37 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..f4cb416e8b
--- /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 zero-initializing ``RdV``, since reading from that register
+without initialization will cause a segmentation fault by QEMU.  This is emitted
+since a declaration of the ``RdV`` register was parsed, but we got no indication
+that the variable has been initialized by the caller.
+
+::
+
+   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.31.1



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

* [PATCH v5 04/14] target/hexagon: make slot number an unsigned
  2021-06-19  9:36 [PATCH v5 00/14] target/hexagon: introduce idef-parser Alessandro Di Federico via
                   ` (2 preceding siblings ...)
  2021-06-19  9:37 ` [PATCH v5 03/14] target/hexagon: import README " Alessandro Di Federico via
@ 2021-06-19  9:37 ` Alessandro Di Federico via
  2021-06-23 15:58   ` Taylor Simpson
  2021-06-19  9:37 ` [PATCH v5 05/14] target/hexagon: make helper functions non-static Alessandro Di Federico via
                   ` (9 subsequent siblings)
  13 siblings, 1 reply; 38+ messages in thread
From: Alessandro Di Federico via @ 2021-06-19  9:37 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>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/hexagon/genptr.c | 6 ++++--
 target/hexagon/macros.h | 2 +-
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index 797a6c0cc9..3b8013d4e2 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -33,7 +33,8 @@ static inline 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 zero = tcg_const_tl(0);
     TCGv slot_mask = tcg_temp_new();
@@ -66,7 +67,8 @@ static inline void gen_log_reg_write(int rnum, TCGv val)
     }
 }
 
-static void gen_log_predicated_reg_write_pair(int rnum, TCGv_i64 val, int slot)
+static void gen_log_predicated_reg_write_pair(int rnum, TCGv_i64 val,
+                                              unsigned slot)
 {
     TCGv val32 = tcg_temp_new();
     TCGv zero = tcg_const_tl(0);
diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h
index b726c3b791..eadb7e5d05 100644
--- a/target/hexagon/macros.h
+++ b/target/hexagon/macros.h
@@ -186,7 +186,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, unsigned slot_num)
  {
     TCGv slot_mask = tcg_const_tl(1 << slot_num);
     TCGv tmp = tcg_temp_new();
-- 
2.31.1



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

* [PATCH v5 05/14] target/hexagon: make helper functions non-static
  2021-06-19  9:36 [PATCH v5 00/14] target/hexagon: introduce idef-parser Alessandro Di Federico via
                   ` (3 preceding siblings ...)
  2021-06-19  9:37 ` [PATCH v5 04/14] target/hexagon: make slot number an unsigned Alessandro Di Federico via
@ 2021-06-19  9:37 ` Alessandro Di Federico via
  2021-06-23 18:29   ` Taylor Simpson
  2021-06-19  9:37 ` [PATCH v5 06/14] target/hexagon: introduce new helper functions Alessandro Di Federico via
                   ` (8 subsequent siblings)
  13 siblings, 1 reply; 38+ messages in thread
From: Alessandro Di Federico via @ 2021-06-19  9:37 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>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/hexagon/genptr.c | 7 ++++---
 target/hexagon/genptr.h | 6 ++++++
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index 3b8013d4e2..6f2816f6e2 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -26,8 +26,9 @@
 #include "macros.h"
 #undef QEMU_GENERATE
 #include "gen_tcg.h"
+#include "genptr.h"
 
-static inline TCGv gen_read_preg(TCGv pred, uint8_t num)
+TCGv gen_read_preg(TCGv pred, uint8_t num)
 {
     tcg_gen_mov_tl(pred, hex_pred[num]);
     return pred;
@@ -58,7 +59,7 @@ static inline void gen_log_predicated_reg_write(int rnum, TCGv val,
     tcg_temp_free(slot_mask);
 }
 
-static inline void gen_log_reg_write(int rnum, TCGv val)
+void gen_log_reg_write(int rnum, TCGv val)
 {
     tcg_gen_mov_tl(hex_new_value[rnum], val);
     if (HEX_DEBUG) {
@@ -121,7 +122,7 @@ static void gen_log_reg_write_pair(int rnum, TCGv_i64 val)
     }
 }
 
-static inline void gen_log_pred_write(DisasContext *ctx, int pnum, TCGv val)
+void gen_log_pred_write(DisasContext *ctx, int pnum, TCGv val)
 {
     TCGv 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..709b8eb099 100644
--- a/target/hexagon/genptr.h
+++ b/target/hexagon/genptr.h
@@ -19,7 +19,13 @@
 #define HEXAGON_GENPTR_H
 
 #include "insn.h"
+#include "tcg/tcg.h"
+#include "translate.h"
 
 extern const SemanticInsn opcode_genptr[];
 
+TCGv gen_read_preg(TCGv pred, uint8_t num);
+void gen_log_reg_write(int rnum, TCGv val);
+void gen_log_pred_write(DisasContext *ctx, int pnum, TCGv val);
+
 #endif
-- 
2.31.1



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

* [PATCH v5 06/14] target/hexagon: introduce new helper functions
  2021-06-19  9:36 [PATCH v5 00/14] target/hexagon: introduce idef-parser Alessandro Di Federico via
                   ` (4 preceding siblings ...)
  2021-06-19  9:37 ` [PATCH v5 05/14] target/hexagon: make helper functions non-static Alessandro Di Federico via
@ 2021-06-19  9:37 ` Alessandro Di Federico via
  2021-06-23 12:05   ` Taylor Simpson
  2021-06-23 18:49   ` Taylor Simpson
  2021-06-19  9:37 ` [PATCH v5 07/14] target/hexagon: expose next PC in DisasContext Alessandro Di Federico via
                   ` (7 subsequent siblings)
  13 siblings, 2 replies; 38+ messages in thread
From: Alessandro Di Federico via @ 2021-06-19  9:37 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 | 163 ++++++++++++++++++++++++++++++++++++----
 target/hexagon/genptr.h |  23 ++++++
 target/hexagon/macros.h |   9 +++
 3 files changed, 180 insertions(+), 15 deletions(-)

diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index 6f2816f6e2..cf45c28f58 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -28,6 +28,12 @@
 #include "gen_tcg.h"
 #include "genptr.h"
 
+TCGv gen_read_reg(TCGv result, int num)
+{
+    tcg_gen_mov_tl(result, hex_gpr[num]);
+    return result;
+}
+
 TCGv gen_read_preg(TCGv pred, uint8_t num)
 {
     tcg_gen_mov_tl(pred, hex_pred[num]);
@@ -396,18 +402,19 @@ static inline void gen_store_conditional8(CPUHexagonState *env,
     tcg_gen_movi_tl(hex_llsc_addr, ~0);
 }
 
-static inline void gen_store32(TCGv vaddr, TCGv src, int width, int slot)
+void gen_store32(DisasContext *ctx, 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);
+    ctx->store_width[slot] = width;
 }
 
-static inline void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src,
-                              DisasContext *ctx, int slot)
+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;
+    gen_store32(ctx, vaddr, src, 1, slot);
 }
 
 static inline void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
@@ -418,11 +425,10 @@ static inline void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
     tcg_temp_free(tmp);
 }
 
-static inline void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src,
-                              DisasContext *ctx, int slot)
+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;
+    gen_store32(ctx, vaddr, src, 2, slot);
 }
 
 static inline void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
@@ -433,11 +439,10 @@ static inline void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
     tcg_temp_free(tmp);
 }
 
-static inline void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src,
-                              DisasContext *ctx, int slot)
+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;
+    gen_store32(ctx, vaddr, src, 4, slot);
 }
 
 static inline void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
@@ -448,8 +453,8 @@ static inline void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
     tcg_temp_free(tmp);
 }
 
-static inline void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src,
-                              DisasContext *ctx, int slot)
+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);
@@ -476,5 +481,133 @@ static TCGv gen_8bitsof(TCGv result, TCGv value)
     return result;
 }
 
+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)
+{
+    TCGv max_val = tcg_const_i32((1 << (width - 1)) - 1);
+    TCGv min_val = tcg_const_i32(-(1 << (width - 1)));
+    tcg_gen_smin_tl(dest, source, max_val);
+    tcg_gen_smax_tl(dest, dest, min_val);
+    tcg_temp_free_i32(max_val);
+    tcg_temp_free_i32(min_val);
+}
+
+void gen_sat_i32_ext(TCGv ovfl, TCGv dest, TCGv source, int width)
+{
+    gen_sat_i32(dest, source, width);
+    tcg_gen_setcond_i32(TCG_COND_NE, ovfl, source, dest);
+}
+
+void gen_satu_i32(TCGv dest, TCGv source, int width)
+{
+    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);
+    tcg_temp_free_i32(max_val);
+    tcg_temp_free_i32(zero);
+}
+
+void gen_satu_i32_ext(TCGv ovfl, TCGv dest, TCGv source, int width)
+{
+    gen_satu_i32(dest, source, width);
+    tcg_gen_setcond_i32(TCG_COND_NE, ovfl, source, dest);
+}
+
+void gen_sat_i64(TCGv_i64 dest, TCGv_i64 source, int width)
+{
+    TCGv_i64 max_val = tcg_const_i64((1 << (width - 1)) - 1);
+    TCGv_i64 min_val = tcg_const_i64(-(1 << (width - 1)));
+    tcg_gen_smin_i64(dest, source, max_val);
+    tcg_gen_smax_i64(dest, dest, min_val);
+    tcg_temp_free_i64(max_val);
+    tcg_temp_free_i64(min_val);
+}
+
+void gen_sat_i64_ext(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width)
+{
+    gen_sat_i64(dest, source, width);
+    TCGv_i64 ovfl_64 = tcg_temp_new_i64();
+    tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, dest, source);
+    tcg_gen_trunc_i64_tl(ovfl, ovfl_64);
+    tcg_temp_free_i64(ovfl_64);
+}
+
+void gen_satu_i64(TCGv_i64 dest, TCGv_i64 source, int width)
+{
+    TCGv_i64 max_val = tcg_const_i64((1 << width) - 1);
+    tcg_gen_movcond_i64(TCG_COND_GTU, dest, source, max_val, max_val, source);
+    TCGv_i64 zero = tcg_const_i64(0);
+    tcg_gen_movcond_i64(TCG_COND_LT, dest, source, zero, zero, dest);
+    tcg_temp_free_i64(max_val);
+    tcg_temp_free_i64(zero);
+}
+
+void gen_satu_i64_ext(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width)
+{
+    gen_sat_i64(dest, source, width);
+    TCGv_i64 ovfl_64 = tcg_temp_new_i64();
+    tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, dest, source);
+    tcg_gen_trunc_i64_tl(ovfl, ovfl_64);
+    tcg_temp_free_i64(ovfl_64);
+}
+
+void gen_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_deposit_tl(result, src, lo, 0, 16);
+    tcg_gen_or_tl(result, result, lo);
+
+    tcg_temp_free(lo);
+    tcg_temp_free(tmp1);
+    tcg_temp_free(tmp2);
+}
+
 #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 709b8eb099..48d1a32f49 100644
--- a/target/hexagon/genptr.h
+++ b/target/hexagon/genptr.h
@@ -24,8 +24,31 @@
 
 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(DisasContext *ctx, int pnum, TCGv val);
+void gen_store32(DisasContext *ctx, 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_write_new_pc(TCGv addr);
+void gen_set_usr_field(int field, TCGv val);
+void gen_set_usr_fieldi(int field, int x);
+void gen_sat_i32(TCGv dest, TCGv source, int width);
+void gen_sat_i32_ext(TCGv ovfl, TCGv dest, TCGv source, int width);
+void gen_satu_i32(TCGv dest, TCGv source, int width);
+void gen_satu_i32_ext(TCGv ovfl, TCGv dest, TCGv source, int width);
+void gen_sat_i64(TCGv_i64 dest, TCGv_i64 source, int width);
+void gen_sat_i64_ext(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width);
+void gen_satu_i64(TCGv_i64 dest, TCGv_i64 source, int width);
+void gen_satu_i64_ext(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width);
+void gen_fbrev(TCGv result, TCGv src);
 
 #endif
diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h
index eadb7e5d05..7d09501844 100644
--- a/target/hexagon/macros.h
+++ b/target/hexagon/macros.h
@@ -181,7 +181,16 @@
 #define MEM_STORE8(VA, DATA, SLOT) log_store64(env, VA, DATA, 8, SLOT)
 #endif
 
+#ifdef QEMU_GENERATE
+static inline void gen_cancel(unsigned slot)
+{
+    tcg_gen_ori_tl(hex_slot_cancelled, hex_slot_cancelled, 1 << slot);
+}
+
+#define CANCEL gen_cancel(slot);
+#else
 #define CANCEL cancel_slot(env, slot)
+#endif
 
 #define LOAD_CANCEL(EA) do { CANCEL; } while (0)
 
-- 
2.31.1



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

* [PATCH v5 07/14] target/hexagon: expose next PC in DisasContext
  2021-06-19  9:36 [PATCH v5 00/14] target/hexagon: introduce idef-parser Alessandro Di Federico via
                   ` (5 preceding siblings ...)
  2021-06-19  9:37 ` [PATCH v5 06/14] target/hexagon: introduce new helper functions Alessandro Di Federico via
@ 2021-06-19  9:37 ` Alessandro Di Federico via
  2021-06-23 18:54   ` Taylor Simpson
  2021-06-19  9:37 ` [PATCH v5 08/14] target/hexagon: prepare input for the idef-parser Alessandro Di Federico via
                   ` (6 subsequent siblings)
  13 siblings, 1 reply; 38+ messages in thread
From: Alessandro Di Federico via @ 2021-06-19  9:37 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>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/hexagon/translate.c | 3 ++-
 target/hexagon/translate.h | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index 9a37644182..34c3bc5222 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -516,11 +516,12 @@ static void decode_and_translate_packet(CPUHexagonState *env, DisasContext *ctx)
     if (decode_packet(nwords, words, &pkt, false) > 0) {
         HEX_DEBUG_PRINT_PKT(&pkt);
         gen_start_packet(ctx, &pkt);
+        ctx->npc = ctx->base.pc_next + pkt.encod_pkt_size_in_bytes;
         for (i = 0; i < pkt.num_insns; i++) {
             gen_insn(env, ctx, &pkt.insn[i], &pkt);
         }
         gen_commit_packet(ctx, &pkt);
-        ctx->base.pc_next += pkt.encod_pkt_size_in_bytes;
+        ctx->base.pc_next = ctx->npc;
     } else {
         gen_exception_end_tb(ctx, HEX_EXCP_INVALID_PACKET);
     }
diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h
index 703fd1345f..d5a7fece31 100644
--- a/target/hexagon/translate.h
+++ b/target/hexagon/translate.h
@@ -37,6 +37,7 @@ typedef struct DisasContext {
     DECLARE_BITMAP(pregs_written, NUM_PREGS);
     uint8_t store_width[STORES_MAX];
     bool s1_store_processed;
+    uint32_t npc;
 } DisasContext;
 
 static inline void ctx_log_reg_write(DisasContext *ctx, int rnum)
-- 
2.31.1



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

* [PATCH v5 08/14] target/hexagon: prepare input for the idef-parser
  2021-06-19  9:36 [PATCH v5 00/14] target/hexagon: introduce idef-parser Alessandro Di Federico via
                   ` (6 preceding siblings ...)
  2021-06-19  9:37 ` [PATCH v5 07/14] target/hexagon: expose next PC in DisasContext Alessandro Di Federico via
@ 2021-06-19  9:37 ` Alessandro Di Federico via
  2021-06-23 19:37   ` Taylor Simpson
  2021-06-19  9:37 ` [PATCH v5 09/14] target/hexagon: import lexer for idef-parser Alessandro Di Federico via
                   ` (5 subsequent siblings)
  13 siblings, 1 reply; 38+ messages in thread
From: Alessandro Di Federico via @ 2021-06-19  9:37 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   | 153 ++++++++++++++++++++++++
 target/hexagon/idef-parser/prepare      |  24 ++++
 target/hexagon/meson.build              |  17 +++
 4 files changed, 308 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..7b8e0f6981
--- /dev/null
+++ b/target/hexagon/gen_idef_parser_funcs.py
@@ -0,0 +1,114 @@
+#!/usr/bin/env python3
+
+##
+##  Copyright(c) 2019-2021 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..20535691e8
--- /dev/null
+++ b/target/hexagon/idef-parser/macros.inc
@@ -0,0 +1,153 @@
+/*
+ * Copyright(c) 2019-2021 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 fADDSAT64(DST, A, B)                                            \
+    __a = fCAST8u(A);                                                   \
+    __b = fCAST8u(B);                                                   \
+    __sum = __a + __b;                                                  \
+    __xor = __a ^ __b;                                                  \
+    __mask = fCAST8s(0x8000000000000000ULL);                            \
+    if (((__a ^ __b) | ~(__a ^ __sum)) & __mask) {                      \
+        DST = __sum;                                                    \
+    } else {                                                            \
+        DST = ((__sum & __mask) >> 63) + __mask;                        \
+        fSET_OVERFLOW();                                                \
+    }
+
+/* Least significant bit operations */
+#define fLSBNEW0 fLSBNEW(P0N)
+#define fLSBNEW1 fLSBNEW(P1N)
+#define fLSBOLDNOT(VAL) fGETBIT(0, ~VAL)
+#define fLSBNEWNOT(PRED) (fLSBNEW(~PRED))
+#define fLSBNEW0NOT fLSBNEW(~P0N)
+#define fLSBNEW1NOT fLSBNEW(~P1N)
+
+/* Assignments */
+#define fPCALIGN(IMM) (IMM = IMM & ~3)
+#define fWRITE_LR(A) (LR = A)
+#define fWRITE_FP(A) (FP = A)
+#define fWRITE_SP(A) (SP = A)
+#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..c9bff5fb80
--- /dev/null
+++ b/target/hexagon/idef-parser/prepare
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+#
+# Copyright(c) 2019-2021 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
+
+# Run the preprocessor and drop comments
+cpp "$@"
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index 6fd9360b74..bf4a0f76fa 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
@@ -175,4 +176,20 @@ hexagon_ss.add(files(
     'fma_emu.c',
 ))
 
+idef_parser_input_generated = custom_target(
+    'idef_parser_input.h.inc',
+    output: 'idef_parser_input.h.inc',
+    depend_files: [hex_common_py],
+    command: [python, files('gen_idef_parser_funcs.py'), 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.31.1



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

* [PATCH v5 09/14] target/hexagon: import lexer for idef-parser
  2021-06-19  9:36 [PATCH v5 00/14] target/hexagon: introduce idef-parser Alessandro Di Federico via
                   ` (7 preceding siblings ...)
  2021-06-19  9:37 ` [PATCH v5 08/14] target/hexagon: prepare input for the idef-parser Alessandro Di Federico via
@ 2021-06-19  9:37 ` Alessandro Di Federico via
  2021-06-23 20:05   ` Taylor Simpson
  2021-06-19  9:37 ` [PATCH v5 10/14] target/hexagon: import parser " Alessandro Di Federico via
                   ` (4 subsequent siblings)
  13 siblings, 1 reply; 38+ messages in thread
From: Alessandro Di Federico via @ 2021-06-19  9:37 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      | 262 ++++++++
 target/hexagon/idef-parser/idef-parser.lex    | 597 ++++++++++++++++++
 target/hexagon/meson.build                    |   4 +
 tests/docker/dockerfiles/alpine.docker        |   1 +
 tests/docker/dockerfiles/centos8.docker       |   1 +
 tests/docker/dockerfiles/debian-amd64.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, 876 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..d5feac8710
--- /dev/null
+++ b/target/hexagon/idef-parser/idef-parser.h
@@ -0,0 +1,262 @@
+/*
+ * Copyright(c) 2019-2021 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>
+#include <glib.h>
+
+#define TCGV_NAME_SIZE 7
+#define MAX_WRITTEN_REGS 32
+#define OFFSET_STR_LEN 32
+#define ALLOC_LIST_LEN 32
+#define ALLOC_NAME_SIZE 32
+#define INIT_LIST_LEN 32
+#define OUT_BUF_LEN (1024 * 1024)
+#define SIGNATURE_BUF_LEN (128 * 1024)
+#define HEADER_BUF_LEN (128 * 1024)
+
+/* Variadic macros to wrap the buffer printing functions */
+#define EMIT(c, ...)                                                 \
+    do {                                                             \
+        g_string_append_printf((c)->out_str, __VA_ARGS__);           \
+    } while (0)
+
+#define EMIT_SIG(c, ...)                                                       \
+    do {                                                                       \
+        g_string_append_printf((c)->signature_str, __VA_ARGS__);               \
+    } while (0)
+
+#define EMIT_HEAD(c, ...)                                                      \
+    do {                                                                       \
+        g_string_append_printf((c)->header_str, __VA_ARGS__);                  \
+    } while (0)
+
+/**
+ * Type of register, assigned to the HexReg.type field
+ */
+typedef enum {GENERAL_PURPOSE, CONTROL, MODIFIER, DOTNEW} 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_NPC,
+    IMM_CONSTEXT,
+};
+
+/**
+ * Semantic record of the IMM token, identifying an immediate constant
+ */
+typedef struct HexImm {
+    union {
+        char id;            /**< Identifier of the immediate                 */
+        uint64_t value;     /**< Immediate value (for VALUE type immediates) */
+        uint64_t index;     /**< Index of the immediate (for int temp vars)  */
+    };
+    enum ImmUnionTag type;  /**< Type of the immediate                      */
+} HexImm;
+
+/**
+ * Semantic record of the 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 {
+    GString *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 {
+    GString *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
+ */
+typedef enum RvalueUnionTag {
+    REGISTER, TEMP, IMMEDIATE, PREDICATE, VARID
+} RvalueUnionTag;
+
+/**
+ * Semantic record of the rvalue token, identifying any numeric value,
+ * immediate or register based. The rvalue tokens are combined together
+ * through the use of several operators, to encode expressions
+ */
+typedef struct HexValue {
+    union {
+        HexReg reg;      /**< rvalue of register type                     */
+        HexTmp tmp;      /**< rvalue of temporary type                    */
+        HexImm imm;      /**< rvalue of immediate type                    */
+        HexPre pre;      /**< rvalue of predicate type                    */
+        HexVar var;      /**< rvalue of automatic variable type           */
+    };
+    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;
+
+/**
+ * State of ternary operator
+ */
+typedef enum TernaryState { IN_LEFT, IN_RIGHT } TernaryState;
+
+/**
+ * Data structure used to handle side effects inside ternary operators
+ */
+typedef struct Ternary {
+    TernaryState state;
+    HexValue cond;
+} Ternary;
+
+/**
+ * Operator type, used for referencing the correct operator when calling the
+ * gen_bin_op() function, which in turn will generate the correct code to
+ * execute the operation between the two rvalues
+ */
+typedef enum OpType {
+    ADD_OP, SUB_OP, MUL_OP, ASL_OP, ASR_OP, LSR_OP, ANDB_OP, ORB_OP,
+    XORB_OP, ANDL_OP, MINI_OP, MAXI_OP, MOD_OP
+} OpType;
+
+/**
+ * Data structure including instruction specific information, to be cleared
+ * out after the compilation of each instruction
+ */
+typedef struct Inst {
+    GString *name;                /**< Name of the compiled instruction      */
+    char *code_begin;             /**< Beginning of instruction input code   */
+    char *code_end;               /**< End of instruction input code         */
+    int tmp_count;                /**< Index of the last declared TCGv temp  */
+    int qemu_tmp_count;           /**< Index of the last declared int temp   */
+    int if_count;                 /**< Index of the last declared if label   */
+    int error_count;              /**< Number of generated errors            */
+    GArray *allocated;            /**< Allocated VARID automatic vars        */
+    GArray *init_list;            /**< List of initialized registers         */
+    GArray *strings;              /**< Strings allocated by the instruction  */
+} Inst;
+
+/**
+ * Data structure representing the whole translation context, which in a
+ * reentrant flex/bison parser just like ours is passed between the scanner
+ * and the parser, holding all the necessary information to perform the
+ * parsing, this data structure survives between the compilation of different
+ * instructions
+ *
+ */
+typedef struct Context {
+    void *scanner;                /**< Reentrant parser state pointer        */
+    char *input_buffer;           /**< Buffer containing the input code      */
+    GString *out_str;             /**< String containing the output code     */
+    GString *signature_str;       /**< String containing the signatures code */
+    GString *header_str;          /**< String containing the output code     */
+    FILE *defines_file;           /**< FILE * of the generated header        */
+    FILE *output_file;            /**< FILE * of the C output file           */
+    FILE *enabled_file;           /**< FILE * of the list of enabled inst    */
+    GArray *ternary;              /**< Array to track nesting of ternary ops */
+    int total_insn;               /**< Number of instructions in input file  */
+    int implemented_insn;         /**< Instruction compiled without errors   */
+    Inst inst;                  /**< Parsing data of the current inst      */
+} Context;
+
+#endif /* IDEF_PARSER_H */
diff --git a/target/hexagon/idef-parser/idef-parser.lex b/target/hexagon/idef-parser/idef-parser.lex
new file mode 100644
index 0000000000..888b667163
--- /dev/null
+++ b/target/hexagon/idef-parser/idef-parser.lex
@@ -0,0 +1,597 @@
+%option noyywrap noinput nounput
+%option 8bit reentrant bison-bridge
+%option warn nodefault
+%option bison-locations
+
+%{
+/*
+ * Copyright(c) 2019-2021 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
+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. */ }
+^#.*$                     { /* Ignore linemarkers. */ }
+
+{INST_NAME}               { yylval->string = g_string_new(yytext);
+                            return INAME; }
+"fFLOAT"                 |
+"fUNFLOAT"               |
+"fDOUBLE"                |
+"fUNDOUBLE"              |
+"0.0"                    |
+"0x1.0p52"               |
+"0x1.0p-52"              { return FAIL; }
+"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.bit_width = 32;
+                           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; }
+"IV1DEAD()"              |
+"fPAUSE(uiV);"           { return ';'; }
+"**"                     { return POW; }
+"+="                     { return INC; }
+"-="                     { return DEC; }
+"++"                     { return PLUSPLUS; }
+"&="                     { return ANDA; }
+"|="                     { return ORA; }
+"^="                     { return XORA; }
+"<<"                     { return ASL; }
+">>"                     { return ASR; }
+">>>"                    { return LSR; }
+"=="                     { return EQ; }
+"!="                     { return NEQ; }
+"<="                     { return LTE; }
+">="                     { return GTE; }
+"&&"                     { return ANDL; }
+"||"                     { return ORL; }
+"else"                   { return ELSE; }
+"for"                    { return FOR; }
+"fREAD_IREG"             { return ICIRC; }
+"fPART1"                 { return PART1; }
+"if"                     { return IF; }
+"fFRAME_SCRAMBLE"        { return FSCR; }
+"fFRAME_UNSCRAMBLE"      { return FSCR; }
+"fFRAMECHECK"            { return FCHK; }
+"Constant_extended"      { return CONSTEXT; }
+"fCL1_"{DIGIT}           { return LOCNT; }
+"fBREV_8"                { return BREV_8; }
+"fBREV_4"                { return BREV_4; }
+"fbrev"                  { return BREV; }
+"fSXTN"                  { return SXT; }
+"fZXTN"                  { return ZXT; }
+"fDF_MAX"                |
+"fSF_MAX"                |
+"fMAX"                   { return MAX; }
+"fDF_MIN"                |
+"fSF_MIN"                |
+"fMIN"                   { return MIN; }
+"fABS"                   { return ABS; }
+"fRNDN"                  { return ROUND; }
+"fCRND"                  { return CROUND; }
+"fCRNDN"                 { return CROUND; }
+"fPM_CIRI"               { return CIRCADD; }
+"fPM_CIRR"               { return CIRCADD; }
+"fCOUNTONES_"{DIGIT}     { return COUNTONES; }
+"fSATN"                  { yylval->sat.set_overflow = true;
+                           yylval->sat.is_unsigned = false;
+                           return SAT; }
+"fVSATN"                 { yylval->sat.set_overflow = false;
+                           yylval->sat.is_unsigned = false;
+                           return SAT; }
+"fSATUN"                 { yylval->sat.set_overflow = false;
+                           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 = 64;
+                           yylval->cast.is_unsigned = ((yytext[6]) == 'u');
+                           return CAST; }
+"(int)"                  { yylval->cast.bit_width = 32;
+                           yylval->cast.is_unsigned = false;
+                           return CAST; }
+"(unsigned int)"         { yylval->cast.bit_width = 32;
+                           yylval->cast.is_unsigned = true;
+                           return CAST; }
+"fREAD_PC()"             |
+"PC"                     { return PC; }
+"fREAD_NPC()"            |
+"NPC"                    { return NPC; }
+"fGET_LPCFG"             |
+"USR.LPCFG"              { return LPCFG; }
+"LOAD_CANCEL(EA)"        |
+"STORE_CANCEL(EA)"       |
+"CANCEL"                 { return CANCEL; }
+"N"{LOWER_ID}            { yylval->rvalue.type = REGISTER;
+                           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"[01]           { yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = CONTROL;
+                           yylval->rvalue.reg.id = LC0 + (yytext[8] - '0');
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           return REG; }
+"LC"[01]                 { yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = CONTROL;
+                           yylval->rvalue.reg.id = LC0 + (yytext[2] - '0');
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           return REG; }
+"fREAD_SA"[01]           { yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = CONTROL;
+                           yylval->rvalue.reg.id = SA0 + (yytext[8] - '0');
+                           yylval->rvalue.reg.bit_width = 32;
+                           yylval->rvalue.bit_width = 32;
+                           return REG; }
+"SA"[01]                 { yylval->rvalue.type = REGISTER;
+                           yylval->rvalue.reg.type = CONTROL;
+                           yylval->rvalue.reg.id = SA0 + (yytext[2] - '0');
+                           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;
+                           yylval->rvalue.is_dotnew = false;
+                           return PRE; }
+[pP]{DIGIT}[nN]          { yylval->rvalue.type = PREDICATE;
+                           yylval->rvalue.pre.id = yytext[1];
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.is_dotnew = true;
+                           return PRE; }
+"fLSBNEW"                { return LSBNEW; }
+"N"                      { yylval->rvalue.type = IMMEDIATE;
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.imm.type = VARIABLE;
+                           yylval->rvalue.imm.id = 'N';
+                           return IMM; }
+"i"                      { yylval->rvalue.type = IMMEDIATE;
+                           yylval->rvalue.bit_width = 32;
+                           yylval->rvalue.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 = strtoll(yytext, NULL, 10);
+                           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 = strtoul(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 = strtoll(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 = strtoull(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; }
+"fCARRY_FROM_ADD"        { return CARRY_FROM_ADD; }
+{VAR_ID}                 { /* Variable name, we adopt the C names convention */
+                           yylval->rvalue.type = VARID;
+                           yylval->rvalue.var.name = g_string_new(yytext);
+                           /* Default types are int */
+                           yylval->rvalue.bit_width = 32;
+                           return VAR; }
+"fHINTJR(RsV)"           { /* Emit no token */ }
+.                        { return yytext[0]; }
+
+%%
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index bf4a0f76fa..329219463f 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -192,4 +192,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 7eeecacc46..84294aef4c 100644
--- a/tests/docker/dockerfiles/alpine.docker
+++ b/tests/docker/dockerfiles/alpine.docker
@@ -12,6 +12,7 @@ ENV PACKAGES \
 	ccache \
 	coreutils \
 	curl-dev \
+	flex \
 	g++ \
 	gcc \
 	git \
diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker
index efc1349cc8..9a4f5880ba 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/debian-amd64.docker b/tests/docker/dockerfiles/debian-amd64.docker
index ed546edcd6..cd4d8ebe9c 100644
--- a/tests/docker/dockerfiles/debian-amd64.docker
+++ b/tests/docker/dockerfiles/debian-amd64.docker
@@ -17,6 +17,7 @@ RUN apt update && \
         cscope \
         genisoimage \
         exuberant-ctags \
+        flex \
         global \
         libbz2-dev \
         liblzo2-dev \
diff --git a/tests/docker/dockerfiles/debian10.docker b/tests/docker/dockerfiles/debian10.docker
index 63cf835ec5..0061c31854 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 66cdb06c19..de34f0f940 100644
--- a/tests/docker/dockerfiles/fedora-i386-cross.docker
+++ b/tests/docker/dockerfiles/fedora-i386-cross.docker
@@ -4,6 +4,7 @@ ENV PACKAGES \
     ccache \
     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 3733df63e9..c1726ed78d 100644
--- a/tests/docker/dockerfiles/fedora-win32-cross.docker
+++ b/tests/docker/dockerfiles/fedora-win32-cross.docker
@@ -7,6 +7,7 @@ ENV PACKAGES \
     ccache \
     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 2564ce4979..5f82a7c1a5 100644
--- a/tests/docker/dockerfiles/fedora-win64-cross.docker
+++ b/tests/docker/dockerfiles/fedora-win64-cross.docker
@@ -7,6 +7,7 @@ ENV PACKAGES \
     ccache \
     diffutils \
     findutils \
+    flex \
     gcc \
     gettext \
     git \
diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker
index 0979c0e1f4..3eeed98164 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 f7e1cbfbe6..73b84ba72c 100644
--- a/tests/docker/dockerfiles/opensuse-leap.docker
+++ b/tests/docker/dockerfiles/opensuse-leap.docker
@@ -7,6 +7,7 @@ ENV PACKAGES \
     bzip2 \
     ccache \
     cyrus-sasl-devel \
+    flex \
     gcc \
     gcc-c++ \
     mkisofs \
diff --git a/tests/docker/dockerfiles/ubuntu.docker b/tests/docker/dockerfiles/ubuntu.docker
index 98a527361c..60f0c68426 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 c0d3642507..1dcd83ac92 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 f1e0ebad49..9ca753a6d9 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.31.1



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

* [PATCH v5 10/14] target/hexagon: import parser for idef-parser
  2021-06-19  9:36 [PATCH v5 00/14] target/hexagon: introduce idef-parser Alessandro Di Federico via
                   ` (8 preceding siblings ...)
  2021-06-19  9:37 ` [PATCH v5 09/14] target/hexagon: import lexer for idef-parser Alessandro Di Federico via
@ 2021-06-19  9:37 ` Alessandro Di Federico via
  2021-06-22 22:35   ` Taylor Simpson
  2021-06-24  3:55   ` Taylor Simpson
  2021-06-19  9:37 ` [PATCH v5 11/14] target/hexagon: call idef-parser functions Alessandro Di Federico via
                   ` (3 subsequent siblings)
  13 siblings, 2 replies; 38+ messages in thread
From: Alessandro Di Federico via @ 2021-06-19  9:37 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      |  961 +++++++
 target/hexagon/idef-parser/parser-helpers.c   | 2396 +++++++++++++++++
 target/hexagon/idef-parser/parser-helpers.h   |  347 +++
 target/hexagon/meson.build                    |   26 +-
 tests/docker/dockerfiles/alpine.docker        |    1 +
 tests/docker/dockerfiles/centos8.docker       |    1 +
 tests/docker/dockerfiles/debian-amd64.docker  |    1 +
 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        |    1 +
 tests/docker/dockerfiles/opensuse-leap.docker |    1 +
 tests/docker/dockerfiles/ubuntu.docker        |    2 +
 tests/docker/dockerfiles/ubuntu1804.docker    |    2 +
 tests/docker/dockerfiles/ubuntu2004.docker    |    4 +-
 16 files changed, 3749 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..5e4fbb6e75
--- /dev/null
+++ b/target/hexagon/idef-parser/idef-parser.y
@@ -0,0 +1,961 @@
+%{
+/*
+ * Copyright(c) 2019-2021 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}
+
+%define parse.error verbose
+%define parse.lac full
+%define api.pure full
+
+%locations
+
+%union {
+    GString *string;
+    HexValue rvalue;
+    HexSat sat;
+    HexCast cast;
+    HexExtract extract;
+    HexMpy mpy;
+    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 VAR
+%token POW ABS CROUND ROUND CIRCADD COUNTONES INC DEC ANDA ORA XORA PLUSPLUS ASL
+%token ASR LSR EQ NEQ LTE GTE MIN MAX ANDL ORL FOR ICIRC IF MUN FSCR FCHK SXT
+%token ZXT CONSTEXT LOCNT BREV SIGN LOAD STORE CONSTLL CONSTULL PC NPC LPCFG
+%token CANCEL IDENTITY PART1 BREV_4 BREV_8 ROTL INSBITS SETBITS EXTBITS EXTRANGE
+%token CAST4_8U SETOVF FAIL DEINTERLEAVE INTERLEAVE CARRY_FROM_ADD LSBNEW
+
+%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 var
+%type <rvalue> DREG DIMM DPRE RREG RPRE FAIL
+%type <index> if_stmt IF
+%type <is_unsigned> SIGN
+
+/* Operator Precedences */
+%left MIN MAX
+%left '('
+%left ','
+%left '='
+%right CIRCADD
+%right INC DEC ANDA ORA XORA
+%left '?' ':'
+%left ORL
+%left ANDL
+%left '|'
+%left '^' ANDOR
+%left '&'
+%left EQ NEQ
+%left '<' '>' LTE GTE
+%left ASL ASR LSR
+%right ABS
+%left '-' '+'
+%left POW
+%left '*' '/' '%' MPY
+%right '~' '!'
+%left '['
+%right CAST
+%right LOCNT BREV
+
+/* Bison Grammar */
+%%
+
+/* Input file containing the description of each hexagon instruction */
+input : instructions
+      {
+          YYACCEPT;
+      }
+      ;
+
+instructions : instruction instructions
+             | %empty
+             ;
+
+instruction : INAME
+              {
+                  gen_inst(c, $1);
+              }
+              arguments
+              {
+                  gen_inst_args(c, &@1);
+              }
+              code
+              {
+                  gen_inst_code(c, &@1);
+              }
+            | error /* Recover gracefully after instruction compilation error */
+              {
+                  free_instruction(c);
+              }
+            ;
+
+arguments : '(' ')'
+          | '(' argument_list ')';
+
+argument_list : decl ',' argument_list
+              | decl
+              ;
+
+var : VAR
+      {
+          track_string(c, $1.var.name);
+          $$ = $1;
+      }
+    ;
+
+/* Return the modified registers list */
+code : '{' statements '}'
+       {
+           c->inst.code_begin = c->input_buffer + @2.first_column;
+           c->inst.code_end = c->input_buffer + @2.last_column - 1;
+       }
+     | '{'
+       {
+           /* Nop */
+       }
+       '}'
+     ;
+
+decl : REG
+       {
+           emit_arg(c, &@1, &$1);
+           /* Enqueue register into initialization list */
+           g_array_append_val(c->inst.init_list, $1);
+       }
+     | IMM
+       {
+           EMIT_SIG(c, ", int %ciV", $1.imm.id);
+       }
+     | PRE
+       {
+           emit_arg(c, &@1, &$1);
+           /* Enqueue predicate into initialization list */
+           g_array_append_val(c->inst.init_list, $1);
+       }
+     | var
+       {
+           yyassert(c, &@1, !strcmp($1.var.name->str, "EA"),
+                    "Unknown argument variable!");
+       }
+     | RREG
+       {
+           emit_arg(c, &@1, &$1);
+       }
+     | WREG
+     | FREG
+     | FIMM
+     | RPRE
+       {
+           emit_arg(c, &@1, &$1);
+       }
+     | WPRE
+     | FPRE
+     | FEA
+     ;
+
+code_block : '{' statements '}'
+           | '{' '}'
+           ;
+
+/* A list of one or more statements */
+statements : statements statement
+           | statement
+           ;
+
+/* Statements can be assignment (rvalue ';'), control or memory statements */
+statement : control_statement
+          | rvalue ';'
+            {
+                rvalue_free(c, &@1, &$1);
+            }
+          | code_block
+          | ';'
+          ;
+
+assign_statement : lvalue '=' 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 '=' rvalue
+                   {
+                       @1.last_column = @3.last_column;
+                       gen_pre_assign(c, &@1, &$1, &$3);
+                   }
+                 | IMM '=' rvalue
+                   {
+                       @1.last_column = @3.last_column;
+                       yyassert(c, &@1, $3.type == IMMEDIATE,
+                                "Cannot assign non-immediate to immediate!");
+                       yyassert(c, &@1, $1.imm.type == VARIABLE,
+                                "Cannot assign to non-variable!");
+                       /* Assign to the function argument */
+                       OUT(c, &@1, &$1, " = ", &$3, ";\n");
+                       $$ = $1;
+                   }
+                 | PC '=' rvalue
+                   {
+                       @1.last_column = @3.last_column;
+                       yyassert(c, &@1, c->ternary->len == 0,
+                                "Assignment side-effect not modeled!");
+                       $3 = 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 '(' IMM ',' IMM ',' SIGN ',' var ',' lvalue ')'
+                   {
+                       @1.last_column = @12.last_column;
+                       yyassert(c, &@1, c->ternary->len == 0,
+                                "Assignment side-effect not modeled!");
+                       gen_load(c, &@1, &$3, &$5, $7, &$9, &$11);
+                   }
+                 | STORE '(' IMM ',' IMM ',' var ',' rvalue ')'
+                   /* Store primitive */
+                   {
+                       @1.last_column = @10.last_column;
+                       yyassert(c, &@1, c->ternary->len == 0,
+                                "Assignment side-effect not modeled!");
+                       gen_store(c, &@1, &$3, &$5, &$7, &$9);
+                   }
+                 | LPCFG '=' rvalue
+                   {
+                       @1.last_column = @3.last_column;
+                       yyassert(c, &@1, c->ternary->len == 0,
+                                "Assignment side-effect not modeled!");
+                       $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 '(' rvalue ',' rvalue ',' rvalue ')'
+                   {
+                       @1.last_column = @8.last_column;
+                       yyassert(c, &@1, c->ternary->len == 0,
+                                "Assignment side-effect not modeled!");
+                       gen_deposit_op(c, &@1, &$5, &$7, &$3, &$1);
+                   }
+                 | SETHALF '(' rvalue ',' lvalue ',' rvalue ')'
+                   {
+                       @1.last_column = @8.last_column;
+                       yyassert(c, &@1, c->ternary->len == 0,
+                                "Assignment side-effect not modeled!");
+                       gen_sethalf(c, &@1, &$1, &$3, &$5, &$7);
+                   }
+                 | SETBITS '(' rvalue ',' rvalue ',' rvalue ',' rvalue ')'
+                   {
+                       @1.last_column = @10.last_column;
+                       yyassert(c, &@1, c->ternary->len == 0,
+                                "Assignment side-effect not modeled!");
+                       gen_setbits(c, &@1, &$3, &$5, &$7, &$9);
+                   }
+                 | INSBITS '(' lvalue ',' rvalue ',' rvalue ',' rvalue ')'
+                   {
+                       @1.last_column = @10.last_column;
+                       yyassert(c, &@1, c->ternary->len == 0,
+                                "Assignment side-effect not modeled!");
+                       gen_rdeposit_op(c, &@1, &$3, &$9, &$7, &$5);
+                   }
+                 | IDENTITY '(' rvalue ')'
+                   {
+                       @1.last_column = @4.last_column;
+                       $$ = $3;
+                   }
+                 ;
+
+control_statement : frame_check
+                  | cancel_statement
+                  | if_statement
+                  | for_statement
+                  | fpart1_statement
+                  ;
+
+frame_check : FCHK '(' rvalue ',' rvalue ')' ';'
+              {
+                  rvalue_free(c, &@1, &$3);
+                  rvalue_free(c, &@1, &$5);
+              }
+            ;
+
+cancel_statement : CANCEL
+                   {
+                       OUT(c, &@1, "gen_cancel(insn->slot);\n");
+                   }
+                 ;
+
+if_statement : if_stmt
+               {
+                   /* Fix else label */
+                   OUT(c, &@1, "gen_set_label(if_label_", &$1, ");\n");
+               }
+             | if_stmt ELSE
+               {
+                   @1.last_column = @2.last_column;
+                   $2 = gen_if_else(c, &@1, $1);
+               }
+               statement
+               {
+                   OUT(c, &@1, "gen_set_label(if_label_", &$2, ");\n");
+               }
+             ;
+
+for_statement : FOR '(' IMM '=' IMM ';' IMM '<' IMM ';' IMM PLUSPLUS ')'
+                {
+                    @1.last_column = @13.last_column;
+                    OUT(c, &@1, "for (int ", &$3, " = ", &$5, "; ",
+                        &$7, " < ", &$9);
+                    OUT(c, &@1, "; ", &$11, "++) {\n");
+                }
+                code_block
+                {
+                    OUT(c, &@1, "}\n");
+                }
+              | FOR '(' IMM '=' IMM ';' IMM '<' IMM ';' IMM INC IMM ')'
+                {
+                    @1.last_column = @14.last_column;
+                    OUT(c, &@1, "for (int ", &$3, " = ", &$5, "; ",
+                        &$7, " < ", &$9);
+                    OUT(c, &@1, "; ", &$11, " += ", &$13, ") {\n");
+                }
+                code_block
+                {
+                    OUT(c, &@1, "}\n");
+                }
+              ;
+
+fpart1_statement : PART1
+                   {
+                       OUT(c, &@1, "if (insn->part1) {\n");
+                   }
+                   '(' statements ')'
+                   {
+                       @1.last_column = @3.last_column;
+                       OUT(c, &@1, "return; }\n");
+                   }
+                 ;
+
+if_stmt : IF '(' rvalue ')'
+          {
+              @1.last_column = @3.last_column;
+              $1 = gen_if_cond(c, &@1, &$3);
+          }
+          statement
+          {
+              $$ = $1;
+          }
+        ;
+
+rvalue : FAIL
+         {
+             yyassert(c, &@1, false, "Encountered a FAIL token as rvalue.\n");
+         }
+       | assign_statement
+       | REG
+         {
+             if ($1.reg.type == CONTROL) {
+                 $$ = gen_read_creg(c, &@1, &$1);
+             } else {
+                 $$ = $1;
+             }
+         }
+       | IMM
+         {
+             $$ = $1;
+         }
+       | CONSTLL '(' IMM ')'
+         {
+             $3.is_unsigned = false;
+             $3.bit_width = 64;
+             $$ = $3;
+         }
+       | CONSTULL '(' IMM ')'
+         {
+             $3.is_unsigned = true;
+             $3.bit_width = 64;
+             $$ = $3;
+         }
+       | PRE
+         {
+             $$ = gen_rvalue_pre(c, &@1, &$1);
+         }
+       | PC
+         {
+             /* Read PC from the CR */
+             HexValue rvalue;
+             rvalue.type = IMMEDIATE;
+             rvalue.imm.type = IMM_PC;
+             rvalue.bit_width = 32;
+             rvalue.is_unsigned = true;
+             $$ = rvalue;
+         }
+       | NPC
+         {
+             /* NPC is only read from CALLs, so we can hardcode it
+                at translation time */
+             HexValue rvalue;
+             rvalue.type = IMMEDIATE;
+             rvalue.imm.type = IMM_NPC;
+             rvalue.bit_width = 32;
+             rvalue.is_unsigned = true;
+             $$ = rvalue;
+         }
+       | 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
+         {
+             $$ = gen_rvalue_var(c, &@1, &$1);
+         }
+       | MPY '(' rvalue ',' rvalue ')'
+         {
+             @1.last_column = @6.last_column;
+             $$ = gen_rvalue_mpy(c, &@1, &$1, &$3, &$5);
+         }
+       | rvalue '+' rvalue
+         {
+             @1.last_column = @3.last_column;
+             $$ = gen_bin_op(c, &@1, ADD_OP, &$1, &$3);
+         }
+       | rvalue '-' rvalue
+         {
+             @1.last_column = @3.last_column;
+             $$ = gen_bin_op(c, &@1, SUB_OP, &$1, &$3);
+         }
+       | rvalue '*' rvalue
+         {
+             @1.last_column = @3.last_column;
+             $$ = gen_bin_op(c, &@1, MUL_OP, &$1, &$3);
+         }
+       | rvalue POW rvalue
+         {
+             @1.last_column = @3.last_column;
+             $$ = gen_rvalue_pow(c, &@1, &$1, &$3);
+         }
+       | rvalue '%' rvalue
+         {
+             @1.last_column = @3.last_column;
+             $$ = gen_bin_op(c, &@1, MOD_OP, &$1, &$3);
+         }
+       | rvalue ASL rvalue
+         {
+             @1.last_column = @3.last_column;
+             $$ = gen_bin_op(c, &@1, ASL_OP, &$1, &$3);
+         }
+       | rvalue ASR rvalue
+         {
+             @1.last_column = @3.last_column;
+             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 '&' rvalue
+         {
+             @1.last_column = @3.last_column;
+             $$ = gen_bin_op(c, &@1, ANDB_OP, &$1, &$3);
+         }
+       | rvalue '|' rvalue
+         {
+             @1.last_column = @3.last_column;
+             $$ = gen_bin_op(c, &@1, ORB_OP, &$1, &$3);
+         }
+       | rvalue '^' rvalue
+         {
+             @1.last_column = @3.last_column;
+             $$ = gen_bin_op(c, &@1, XORB_OP, &$1, &$3);
+         }
+       | rvalue ANDL rvalue
+         {
+             @1.last_column = @3.last_column;
+             $$ = gen_bin_op(c, &@1, ANDL_OP, &$1, &$3);
+         }
+       | MIN '(' rvalue ',' rvalue ')'
+         {
+             @1.last_column = @3.last_column;
+             $$ = gen_bin_op(c, &@1, MINI_OP, &$3, &$5);
+         }
+       | MAX '(' rvalue ',' rvalue ')'
+         {
+             @1.last_column = @3.last_column;
+             $$ = gen_bin_op(c, &@1, MAXI_OP, &$3, &$5);
+         }
+       | '~' rvalue
+         {
+             @1.last_column = @2.last_column;
+             $$ = gen_rvalue_not(c, &@1, &$2);
+         }
+       | '!' rvalue
+         {
+             @1.last_column = @2.last_column;
+             $$ = gen_rvalue_notl(c, &@1, &$2);
+         }
+       | SAT '(' IMM ',' rvalue ')'
+         {
+             @1.last_column = @6.last_column;
+             $$ = gen_rvalue_sat(c, &@1, &$1, &$3, &$5);
+         }
+       | CAST rvalue
+         {
+             @1.last_column = @2.last_column;
+             /* Assign target signedness */
+             $2.is_unsigned = $1.is_unsigned;
+             $$ = gen_cast_op(c, &@1, &$2, $1.bit_width);
+             $$.is_unsigned = $1.is_unsigned;
+         }
+       | rvalue '[' rvalue ']'
+         {
+             @1.last_column = @4.last_column;
+             if ($3.type == IMMEDIATE) {
+                 $$ = gen_tmp(c, &@1, $1.bit_width);
+                 OUT(c, &@1, "tcg_gen_extract_i", &$$.bit_width, "(");
+                 OUT(c, &@1, &$$, ", ", &$1, ", ", &$3, ", 1);\n");
+             } else {
+                 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 '<' 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 '>' 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 '?'
+         {
+             $1.is_manual = true;
+             Ternary t = {0};
+             t.state = IN_LEFT;
+             t.cond = $1;
+             g_array_append_val(c->ternary, t);
+         }
+         rvalue ':'
+         {
+             Ternary *t = &g_array_index(c->ternary, Ternary,
+                                         c->ternary->len - 1);
+             t->state = IN_RIGHT;
+         }
+         rvalue
+         {
+             @1.last_column = @5.last_column;
+             $$ = gen_rvalue_ternary(c, &@1, &$1, &$4, &$7);
+         }
+       | FSCR '(' rvalue ')'
+         {
+             @1.last_column = @4.last_column;
+             $$ = gen_rvalue_fscr(c, &@1, &$3);
+         }
+       | SXT '(' rvalue ',' IMM ',' rvalue ')'
+         {
+             @1.last_column = @8.last_column;
+             yyassert(c, &@1, $5.type == IMMEDIATE &&
+                      $5.imm.type == VALUE,
+                      "SXT expects immediate values\n");
+             $5.imm.value = 64;
+             $$ = gen_extend_op(c, &@1, &$3, &$5, &$7, false);
+         }
+       | ZXT '(' rvalue ',' IMM ',' rvalue ')'
+         {
+             @1.last_column = @8.last_column;
+             yyassert(c, &@1, $5.type == IMMEDIATE &&
+                      $5.imm.type == VALUE,
+                      "ZXT expects immediate values\n");
+             $$ = gen_extend_op(c, &@1, &$3, &$5, &$7, true);
+         }
+       | '(' rvalue ')'
+         {
+             $$ = $2;
+         }
+       | ABS rvalue
+         {
+             @1.last_column = @2.last_column;
+             $$ = gen_rvalue_abs(c, &@1, &$2);
+         }
+       | CROUND '(' rvalue ',' rvalue ')'
+         {
+             @1.last_column = @6.last_column;
+             $$ = gen_convround_n(c, &@1, &$3, &$5);
+         }
+       | CROUND '(' rvalue ')'
+         {
+             @1.last_column = @4.last_column;
+             $$ = gen_convround(c, &@1, &$3);
+         }
+       | ROUND '(' rvalue ',' rvalue ')'
+         {
+             @1.last_column = @6.last_column;
+             $$ = gen_round(c, &@1, &$3, &$5);
+         }
+       | '-' rvalue
+         {
+             @1.last_column = @2.last_column;
+             $$ = gen_rvalue_neg(c, &@1, &$2);
+         }
+       | ICIRC '(' rvalue ')' ASL IMM
+         {
+             @1.last_column = @6.last_column;
+             $$ = gen_tmp(c, &@1, 32);
+             OUT(c, &@1, "gen_read_ireg(", &$$, ", ", &$3, ", ", &$6, ");\n");
+             rvalue_free(c, &@1, &$3);
+         }
+       | CIRCADD '(' rvalue ',' rvalue ',' rvalue ')'
+         {
+             @1.last_column = @8.last_column;
+             gen_circ_op(c, &@1, &$3, &$5, &$7);
+         }
+       | LOCNT '(' rvalue ')'
+         {
+             @1.last_column = @4.last_column;
+             /* Leading ones count */
+             $$ = gen_locnt_op(c, &@1, &$3);
+         }
+       | COUNTONES '(' rvalue ')'
+         {
+             @1.last_column = @4.last_column;
+             /* Ones count */
+             $$ = gen_ctpop_op(c, &@1, &$3);
+         }
+       | LPCFG
+         {
+             $$ = gen_tmp_value(c, &@1, "0", 32);
+             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 '(' rvalue ',' rvalue ')'
+         {
+             @1.last_column = @6.last_column;
+             $$ = gen_extract_op(c, &@1, &$5, &$3, &$1);
+         }
+       | EXTBITS '(' rvalue ',' rvalue ',' rvalue ')'
+         {
+             @1.last_column = @8.last_column;
+             yyassert(c, &@1, $5.type == IMMEDIATE &&
+                      $5.imm.type == VALUE &&
+                      $7.type == IMMEDIATE &&
+                      $7.imm.type == VALUE,
+                      "Range extract needs immediate values!\n");
+             $$ = gen_rextract_op(c, &@1, &$3, $7.imm.value, $5.imm.value);
+         }
+       | EXTRANGE '(' rvalue ',' rvalue ',' rvalue ')'
+         {
+             @1.last_column = @8.last_column;
+             yyassert(c, &@1, $5.type == IMMEDIATE &&
+                      $5.imm.type == VALUE &&
+                      $7.type == IMMEDIATE &&
+                      $7.imm.type == VALUE,
+                      "Range extract needs immediate values!\n");
+             $$ = gen_rextract_op(c,
+                                  &@1,
+                                  &$3,
+                                  $7.imm.value,
+                                  $5.imm.value - $7.imm.value + 1);
+         }
+       | CAST4_8U '(' rvalue ')'
+         {
+             @1.last_column = @4.last_column;
+             $$ = rvalue_truncate(c, &@1, &$3);
+             $$.is_unsigned = true;
+             $$ = rvalue_materialize(c, &@1, &$$);
+             $$ = rvalue_extend(c, &@1, &$$);
+         }
+       | BREV '(' rvalue ')'
+         {
+             @1.last_column = @4.last_column;
+             $$ = gen_rvalue_brev(c, &@1, &$3);
+         }
+       | BREV_4 '(' rvalue ')'
+         {
+             @1.last_column = @4.last_column;
+             $$ = gen_fbrev_4(c, &@1, &$3);
+         }
+       | BREV_8 '(' rvalue ')'
+         {
+             @1.last_column = @4.last_column;
+             $$ = gen_fbrev_8(c, &@1, &$3);
+         }
+       | ROTL '(' rvalue ',' rvalue ')'
+         {
+             @1.last_column = @6.last_column;
+             $$ = gen_rotl(c, &@1, &$3, &$5);
+         }
+       | SETOVF '(' ')'
+         {
+             @1.last_column = @3.last_column;
+             HexValue ovfl = gen_imm_value(c, &@1, 1, 32);
+             gen_set_overflow(c, &@1, &ovfl);
+         }
+       | SETOVF '(' rvalue ')'
+         {
+             /* Convenience fSET_OVERFLOW with pass-through */
+             @1.last_column = @3.last_column;
+             HexValue ovfl = gen_imm_value(c, &@1, 1, 32);
+             gen_set_overflow(c, &@1, &ovfl);
+             $$ = $3;
+         }
+       | DEINTERLEAVE '(' rvalue ')'
+         {
+             @1.last_column = @4.last_column;
+             $$ = gen_deinterleave(c, &@1, &$3);
+         }
+       | INTERLEAVE '(' rvalue ',' rvalue ')'
+         {
+             @1.last_column = @6.last_column;
+             $$ = gen_interleave(c, &@1, &$3, &$5);
+         }
+       | CARRY_FROM_ADD '(' rvalue ',' rvalue ',' rvalue ')'
+         {
+             @1.last_column = @8.last_column;
+             $$ = gen_carry_from_add(c, &@1, &$3, &$5, &$7);
+         }
+       | LSBNEW '(' rvalue ')'
+         {
+             @1.last_column = @4.last_column;
+             HexValue one = gen_imm_value(c, &@1, 1, 32);
+             $$ = gen_bin_op(c, &@1, ANDB_OP, &$3, &one);
+         }
+       ;
+
+lvalue : FAIL
+         {
+             @1.last_column = @1.last_column;
+             yyassert(c, &@1, false, "Encountered a FAIL token as lvalue.\n");
+         }
+       | REG
+         {
+             $$ = $1;
+         }
+       | var
+         {
+             $$ = $1;
+         }
+       ;
+
+%%
+
+int main(int argc, char **argv)
+{
+    if (argc != 5) {
+        fprintf(stderr,
+                "Semantics: Hexagon ISA to tinycode generator compiler\n\n");
+        fprintf(stderr,
+                "Usage: ./semantics IDEFS EMITTER_C EMITTER_H "
+                "ENABLED_INSTRUCTIONS_LIST\n");
+        return 1;
+    }
+
+    enum {
+        ARG_INDEX_ARGV0 = 0,
+        ARG_INDEX_IDEFS,
+        ARG_INDEX_EMITTER_C,
+        ARG_INDEX_EMITTER_H,
+        ARG_INDEX_ENABLED_INSTRUCTIONS_LIST
+    };
+
+    FILE *enabled_file = fopen(argv[ARG_INDEX_ENABLED_INSTRUCTIONS_LIST], "w");
+
+    FILE *output_file = fopen(argv[ARG_INDEX_EMITTER_C], "w");
+    fputs("#include \"qemu/osdep.h\"\n", output_file);
+    fputs("#include \"qemu/log.h\"\n", output_file);
+    fputs("#include \"cpu.h\"\n", output_file);
+    fputs("#include \"internal.h\"\n", output_file);
+    fputs("#include \"tcg/tcg-op.h\"\n", output_file);
+    fputs("#include \"insn.h\"\n", output_file);
+    fputs("#include \"opcodes.h\"\n", output_file);
+    fputs("#include \"translate.h\"\n", output_file);
+    fputs("#define QEMU_GENERATE\n", output_file);
+    fputs("#include \"genptr.h\"\n", output_file);
+    fputs("#include \"tcg/tcg.h\"\n", output_file);
+    fputs("#include \"macros.h\"\n", output_file);
+    fprintf(output_file, "#include \"%s\"\n", argv[ARG_INDEX_EMITTER_H]);
+
+    FILE *defines_file = fopen(argv[ARG_INDEX_EMITTER_H], "w");
+    assert(defines_file != NULL);
+    fputs("#ifndef HEX_EMITTER_H\n", defines_file);
+    fputs("#define HEX_EMITTER_H\n", defines_file);
+    fputs("\n", defines_file);
+    fputs("#include \"insn.h\"\n\n", defines_file);
+
+    /* Parser input file */
+    Context context = { 0 };
+    context.defines_file = defines_file;
+    context.output_file = output_file;
+    context.enabled_file = enabled_file;
+    /* Initialize buffers */
+    context.out_str = g_string_new(NULL);
+    context.signature_str = g_string_new(NULL);
+    context.header_str = g_string_new(NULL);
+    context.ternary = g_array_new(FALSE, TRUE, sizeof(Ternary));
+    /* Read input file */
+    FILE *input_file = fopen(argv[ARG_INDEX_IDEFS], "r");
+    fseek(input_file, 0L, SEEK_END);
+    long input_size = ftell(input_file);
+    context.input_buffer = (char *) calloc(input_size + 1, sizeof(char));
+    fseek(input_file, 0L, SEEK_SET);
+    size_t read_chars = fread(context.input_buffer,
+                              sizeof(char),
+                              input_size,
+                              input_file);
+    if (read_chars != input_size) {
+        fprintf(stderr, "Error: an error occurred while reading input file!\n");
+        return -1;
+    }
+    yylex_init(&context.scanner);
+    YY_BUFFER_STATE buffer;
+    buffer = yy_scan_string(context.input_buffer, context.scanner);
+    /* Start the parsing procedure */
+    yyparse(context.scanner, &context);
+    if (context.implemented_insn != context.total_insn) {
+        fprintf(stderr,
+                "Warning: %d/%d meta instructions have been implemented!\n",
+                context.implemented_insn,
+                context.total_insn);
+    }
+    fputs("#endif " START_COMMENT " HEX_EMITTER_h " END_COMMENT "\n",
+          defines_file);
+    /* Cleanup */
+    yy_delete_buffer(buffer, context.scanner);
+    yylex_destroy(context.scanner);
+    free(context.input_buffer);
+    g_string_free(context.out_str, TRUE);
+    g_string_free(context.signature_str, TRUE);
+    g_string_free(context.header_str, TRUE);
+    g_array_free(context.ternary, TRUE);
+    fclose(output_file);
+    fclose(input_file);
+    fclose(defines_file);
+    fclose(enabled_file);
+
+    return 0;
+}
diff --git a/target/hexagon/idef-parser/parser-helpers.c b/target/hexagon/idef-parser/parser-helpers.c
new file mode 100644
index 0000000000..622f447c85
--- /dev/null
+++ b/target/hexagon/idef-parser/parser-helpers.c
@@ -0,0 +1,2396 @@
+/*
+ * Copyright(c) 2019-2021 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 *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->str, s);
+
+    fprintf(stderr, "Problematic range: ");
+    for (int i = locp->first_column; i < locp->last_column; i++) {
+        if (code_ptr[i] != '\n') {
+            fprintf(stderr, "%c", code_ptr[i]);
+        }
+    }
+    fprintf(stderr, "\n");
+
+    for (int i = 0;
+         i < 80 &&
+         code_ptr[locp->first_column - 10 + i] != '\0' &&
+         code_ptr[locp->first_column - 10 + i] != '\n';
+         i++) {
+        fprintf(stderr, "%c", code_ptr[locp->first_column - 10 + i]);
+    }
+    fprintf(stderr, "\n");
+    for (int i = 0; i < 9; i++) {
+        fprintf(stderr, " ");
+    }
+    fprintf(stderr, "^");
+    for (int i = 0; i < (locp->last_column - locp->first_column) - 1; i++) {
+        fprintf(stderr, "~");
+    }
+    fprintf(stderr, "\n");
+    c->inst.error_count++;
+}
+
+bool is_direct_predicate(HexValue *value)
+{
+    return value->pre.id >= '0' && value->pre.id <= '3';
+
+}
+
+bool is_inside_ternary(Context *c)
+{
+    return c->ternary->len > 0;
+}
+
+/* Print functions */
+void str_print(Context *c, YYLTYPE *locp, const char *string)
+{
+    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_%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, "ctx->base.pc_next");
+        break;
+    case IMM_NPC:
+        EMIT(c, "ctx->npc");
+        break;
+    case IMM_CONSTEXT:
+        EMIT(c, "insn->extension_valid");
+        break;
+    default:
+        yyassert(c, locp, false, "Cannot print this expression!");
+    }
+}
+
+void var_print(Context *c, YYLTYPE *locp, HexVar *var)
+{
+    EMIT(c, "%s", var->name->str);
+}
+
+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!");
+  }
+}
+
+void out_assert(Context *c, YYLTYPE *locp,
+                void *dummy __attribute__((unused))) {
+    abort();
+    yyassert(c, locp, false, "Unhandled print type!");
+}
+
+/* Copy output code buffer */
+void commit(Context *c)
+{
+    /* Emit instruction pseudocode */
+    EMIT_SIG(c, "\n" START_COMMENT " ");
+    for (char *x = c->inst.code_begin; x < c->inst.code_end; x++) {
+        EMIT_SIG(c, "%c", *x);
+    }
+    EMIT_SIG(c, " " END_COMMENT "\n");
+
+    /* Commit instruction code to output file */
+    fwrite(c->signature_str->str, sizeof(char), c->signature_str->len,
+           c->output_file);
+    fwrite(c->header_str->str, sizeof(char), c->header_str->len,
+           c->output_file);
+    fwrite(c->out_str->str, sizeof(char), c->out_str->len,
+           c->output_file);
+
+    fwrite(c->signature_str->str, sizeof(char), c->signature_str->len,
+           c->defines_file);
+    fprintf(c->defines_file, ";\n");
+}
+
+static HexValue get_ternary_cond(Context *c, YYLTYPE *locp)
+{
+    yyassert(c, locp, is_inside_ternary(c), "unexisting condition");
+    Ternary *t = &g_array_index(c->ternary, Ternary, 0);
+    HexValue cond = t->cond;
+    if (t->state == IN_RIGHT) {
+        cond = gen_rvalue_notl(c, locp, &cond);
+    }
+    for (unsigned i = 1; i < c->ternary->len; ++i) {
+        Ternary *right = &g_array_index(c->ternary, Ternary, i);
+        HexValue other = right->cond;
+        /* Invert condition if we are on the right side */
+        if (right->state == IN_RIGHT) {
+            other = gen_rvalue_notl(c, locp, &other);
+        }
+        cond = gen_bin_op(c, locp, ANDL_OP, &cond, &other);
+    }
+    return cond;
+}
+
+/* Temporary values creation */
+HexValue gen_tmp(Context *c, YYLTYPE *locp, int bit_width)
+{
+    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;
+    OUT(c, locp, "TCGv_i", &bit_width, " tmp_", &c->inst.tmp_count,
+        " = tcg_temp_new_i", &bit_width, "();\n");
+    c->inst.tmp_count++;
+    return rvalue;
+}
+
+HexValue gen_tmp_value(Context *c,
+                       YYLTYPE *locp,
+                       const char *value,
+                       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;
+}
+
+static HexValue gen_tmp_value_from_imm(Context *c,
+                                       YYLTYPE *locp,
+                                       HexValue *value)
+{
+    assert(value->type == IMMEDIATE);
+    HexValue rvalue;
+    rvalue.type = TEMP;
+    rvalue.bit_width = value->bit_width;
+    rvalue.is_unsigned = value->is_unsigned;
+    rvalue.is_dotnew = false;
+    rvalue.is_manual = false;
+    rvalue.tmp.index = c->inst.tmp_count;
+    OUT(c, locp, "TCGv_i", &rvalue.bit_width, " tmp_", &c->inst.tmp_count);
+    OUT(c, locp, " = tcg_const_i", &rvalue.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);
+}
+
+HexValue rvalue_materialize(Context *c, YYLTYPE *locp, HexValue *rvalue)
+{
+    if (rvalue->type == IMMEDIATE) {
+        HexValue res = gen_tmp_value_from_imm(c, locp, rvalue);
+        rvalue_free(c, locp, rvalue);
+        return res;
+    }
+    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->len; i++) {
+        Var *curr = &g_array_index(c->inst.allocated, Var, i);
+        if (g_string_equal(varid->var.name, curr->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";
+    int index = find_variable(c, locp, varid);
+    bool found = index != -1;
+    if (found) {
+        Var *other = &g_array_index(c->inst.allocated, Var, index);
+        varid->var.name = other->name;
+        varid->bit_width = other->bit_width;
+        varid->is_unsigned = other->is_unsigned;
+    } else {
+        EMIT_HEAD(c, "TCGv_i%s %s", bit_suffix, varid->var.name->str);
+        EMIT_HEAD(c, " = tcg_temp_local_new_i%s();\n", bit_suffix);
+        Var new_var = {
+            .name = varid->var.name,
+            .bit_width = width,
+            .is_unsigned = is_unsigned,
+        };
+        g_array_append_val(c->inst.allocated, new_var);
+    }
+}
+
+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,
+                     TCGCond 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 = tcg_swap_cond(type);
+    }
+    /* fallthrough */
+    case REG_IMM:
+        OUT(c, locp, "tcg_gen_setcondi_", bit_suffix, "(");
+        OUT(c, locp, cond_to_str(type), ", ", &res, ", ", &op1, ", ", &op2,
+            ");\n");
+        break;
+    case REG_REG:
+        OUT(c, locp, "tcg_gen_setcond_", bit_suffix, "(");
+        OUT(c, locp, cond_to_str(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_simple_op(Context *c, YYLTYPE *locp, unsigned bit_width,
+                          const char *bit_suffix, HexValue *res,
+                          enum OpTypes op_types, HexValue *op1,
+                          HexValue *op2,
+                          const char *imm_imm,
+                          const char *imm_reg,
+                          const char *reg_imm,
+                          const char *reg_reg
+                          ) {
+    switch (op_types) {
+    case IMM_IMM:
+        OUT(c, locp, "int", &bit_width, "_t ", res,
+            " = ", op1, imm_imm, op2, ";\n");
+        break;
+    case IMM_REG:
+        OUT(c, locp, imm_reg, bit_suffix,
+            "(", res, ", ", op2, ", ", op1, ");\n");
+        break;
+    case REG_IMM:
+        OUT(c, locp, reg_imm, bit_suffix,
+            "(", res, ", ", op1, ", ", op2, ");\n");
+        break;
+    case REG_REG:
+        OUT(c, locp, reg_reg, bit_suffix,
+            "(", res, ", ", op1, ", ", op2, ");\n");
+        break;
+    }
+    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_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:
+        {
+            OUT(c, locp, "if (", &op2, " >= ", &bit_width, ") {\n");
+            OUT(c, locp, "tcg_gen_movi_", bit_suffix, "(", res, ", 0);\n");
+            OUT(c, locp, "} else {\n");
+            OUT(c, locp, "tcg_gen_shli_", bit_suffix,
+                "(", res, ", ", &op1, ", ", &op2, ");\n");
+            OUT(c, locp, "}\n");
+        }
+        break;
+    case IMM_REG:
+        op1.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_REG || op_types == REG_REG) {
+        /* Handle left shift by 64/32 which hexagon-sim expects to clear out */
+        /* register */
+        HexValue edge = gen_imm_value(c, locp, bit_width, bit_width);
+        edge = rvalue_materialize(c, locp, &edge);
+        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);
+        OUT(c, locp, "(TCG_COND_GEU, ", 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,
+                       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:
+        OUT(c, locp, "{\nint", &bit_width, "_t shift = ", &op2, ";\n");
+        OUT(c, locp, "if (", &op2, " >= ", &bit_width, ") {\n");
+        OUT(c, locp, "    shift = ", &bit_width, " - 1;\n");
+        OUT(c, locp, "}\n");
+        OUT(c, locp, "tcg_gen_sari_", bit_suffix,
+            "(", res, ", ", &op1, ", shift);\n}\n");
+        break;
+    case IMM_REG:
+        op1 = rvalue_materialize(c, locp, &op1);
+        /* Fallthrough */
+    case REG_REG:
+        OUT(c, locp, "tcg_gen_sar_", bit_suffix,
+            "(", res, ", ", &op1, ", ", &op2, ");\n");
+        break;
+    }
+    if (op_types == IMM_REG ||  op_types == REG_REG) {
+        /* Handle right shift by values >= bit_width */
+        HexValue edge = gen_imm_value(c, locp, bit_width, bit_width);
+        edge = rvalue_materialize(c, locp, &edge);
+        HexValue tmp = gen_tmp(c, locp, 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);
+
+        const char *offset = op_is64bit ? "63" : "31";
+        OUT(c, locp, "tcg_gen_extract_", bit_suffix, "(",
+            &tmp, ", ", &op1, ", ", offset, ", 1);\n");
+        OUT(c, locp, "tcg_gen_sub_", bit_suffix, "(",
+            &tmp, ", ", &zero, ", ", &tmp, ");\n");
+        OUT(c, locp, "tcg_gen_movcond_i", &bit_width);
+        OUT(c, locp, "(TCG_COND_GEU, ", res, ", ", &op2, ", ", &edge);
+        OUT(c, locp, ", ", &tmp, ", ", res, ");\n");
+        rvalue_free(c, locp, &edge);
+        rvalue_free(c, locp, &tmp);
+        rvalue_free(c, locp, &zero);
+    }
+    rvalue_free(c, locp, &op1);
+    rvalue_free(c, locp, &op2);
+}
+
+static void gen_lsr_op(Context *c, YYLTYPE *locp, unsigned bit_width,
+                       bool op_is64bit, const char *bit_suffix, HexValue *res,
+                       enum OpTypes op_types, HexValue *op1_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:
+        OUT(c, locp, "if (", &op2, " >= ", &bit_width, ") {\n");
+        OUT(c, locp, "tcg_gen_movi_", bit_suffix, "(", res, ", 0);\n");
+        OUT(c, locp, "} else {\n");
+        OUT(c, locp, "tcg_gen_shri_", bit_suffix,
+            "(", res, ", ", &op1, ", ", &op2, ");\n");
+        OUT(c, locp, "}\n");
+        break;
+    case IMM_REG:
+        op1 = rvalue_materialize(c, locp, &op1);
+        /* Fallthrough */
+    case REG_REG:
+        OUT(c, locp, "tcg_gen_shr_", bit_suffix,
+            "(", res, ", ", &op1, ", ", &op2, ");\n");
+        break;
+    }
+    if (op_types == IMM_REG ||  op_types == REG_REG) {
+        /* Handle right shift by values >= bit_width */
+        HexValue edge = gen_imm_value(c, locp, bit_width, bit_width);
+        edge = rvalue_materialize(c, locp, &edge);
+        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);
+        OUT(c, locp, "(TCG_COND_GEU, ", 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_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 *min = res->is_unsigned ? "tcg_gen_umin" : "tcg_gen_smin";
+    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, min, "_i", &bit_width, "(");
+        OUT(c, locp, res, ", ", &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, min, "_i", &bit_width, "(");
+        OUT(c, locp, res, ", ", &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 *min = res->is_unsigned ? "tcg_gen_umax" : "tcg_gen_smax";
+    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, min, "_i", &bit_width, "(");
+        OUT(c, locp, res, ", ", &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, min, "_i", &bit_width, "(");
+        OUT(c, locp, res, ", ", &op1, ", ", &op2, ");\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,
+                    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, c->inst.allocated->len > 0,
+                 "Variable in bin_op must exist!\n");
+        op1.bit_width = g_array_index(c->inst.allocated, Var, index).bit_width;
+    }
+    if (op2.type == VARID) {
+        int index = find_variable(c, locp, &op2);
+        yyassert(c, locp, c->inst.allocated->len > 0,
+                 "Variable in bin_op must exist!\n");
+        op2.bit_width = g_array_index(c->inst.allocated, Var, 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_simple_op(c, locp, bit_width, bit_suffix, &res,
+                      op_types, &op1, &op2,
+                      " + ",
+                      "tcg_gen_addi_",
+                      "tcg_gen_addi_",
+                      "tcg_gen_add_");
+        break;
+    case SUB_OP:
+        gen_sub_op(c, locp, bit_width, bit_suffix, &res, op_types, &op1, &op2);
+        break;
+    case MUL_OP:
+        gen_simple_op(c, locp, bit_width, bit_suffix, &res,
+                      op_types, &op1, &op2,
+                      " * ",
+                      "tcg_gen_muli_",
+                      "tcg_gen_muli_",
+                      "tcg_gen_mul_");
+        break;
+    case ASL_OP:
+        gen_asl_op(c, locp, bit_width, op_is64bit, bit_suffix, &res, op_types,
+                   &op1, &op2);
+        break;
+    case ASR_OP:
+        gen_asr_op(c, locp, bit_width, op_is64bit, bit_suffix, &res, op_types,
+                   &op1, &op2);
+        break;
+    case LSR_OP:
+        gen_lsr_op(c, locp, bit_width, op_is64bit, bit_suffix, &res, op_types,
+                   &op1, &op2);
+        break;
+    case ANDB_OP:
+        gen_simple_op(c, locp, bit_width, bit_suffix, &res,
+                      op_types, &op1, &op2,
+                      " & ",
+                      "tcg_gen_andi_",
+                      "tcg_gen_andi_",
+                      "tcg_gen_and_");
+        break;
+    case ORB_OP:
+        gen_simple_op(c, locp, bit_width, bit_suffix, &res,
+                      op_types, &op1, &op2,
+                      " | ",
+                      "tcg_gen_ori_",
+                      "tcg_gen_ori_",
+                      "tcg_gen_or_");
+        break;
+    case XORB_OP:
+        gen_simple_op(c, locp, bit_width, bit_suffix, &res,
+                      op_types, &op1, &op2,
+                      " ^ ",
+                      "tcg_gen_xori_",
+                      "tcg_gen_xori_",
+                      "tcg_gen_xor_");
+        break;
+    case ANDL_OP:
+        gen_andl_op(c, locp, bit_width, bit_suffix, &res, op_types, &op1, &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(TCG_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)
+{
+    yyassert(c,
+             locp,
+             !is_inside_ternary(c)
+             || !(dest->type == REGISTER && dest->reg.type == CONTROL),
+             "control assign in ternary");
+
+    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);
+        }
+    }
+    if (is_inside_ternary(c)) {
+        value_m = rvalue_materialize(c, locp, &value_m);
+        HexValue cond = get_ternary_cond(c, locp);
+        if (cond.bit_width != bit_width) {
+            if (cond.bit_width == 64) {
+                cond = rvalue_truncate(c, locp, &cond);
+            } else {
+                cond = rvalue_extend(c, locp, &cond);
+            }
+        }
+        HexValue zero = gen_tmp_value(c, locp, "0", bit_width);
+        OUT(c, locp, "tcg_gen_movcond_i", &bit_width, "(TCG_COND_NE, ", dest);
+        OUT(c, locp, ", ", &cond, ", ", &zero, ", ");
+        OUT(c, locp, &value_m, ", ", dest, ");\n");
+        rvalue_free(c, locp, &cond);
+        rvalue_free(c, locp, &zero);
+    } else {
+        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");
+    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, &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, &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);
+
+    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(c, locp, &source);
+    rvalue_free(c, locp, &bit_pos);
+
+    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 */
+void gen_circ_op(Context *c,
+                 YYLTYPE *locp,
+                 HexValue *addr,
+                 HexValue *increment,
+                 HexValue *modifier) {
+    HexValue increment_m = *increment;
+    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(",
+        addr,
+        ", ",
+        addr,
+        ", ",
+        &increment_m,
+        ", ",
+        modifier);
+    OUT(c, locp, ", ", &cs, ");\n");
+    rvalue_free(c, locp, &increment_m);
+    rvalue_free(c, locp, modifier);
+    rvalue_free(c, locp, &cs);
+}
+
+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_bswap32_tl(", &res, ", ", &res, ");\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)
+{
+    HexValue amount = *n;
+    if (amount.bit_width < source->bit_width) {
+        amount = rvalue_extend(c, locp, &amount);
+    } else {
+        amount = rvalue_truncate(c, locp, &amount);
+    }
+    amount = rvalue_materialize(c, locp, &amount);
+    const char *suffix = source->bit_width == 64 ? "i64" : "i32";
+
+    HexValue res = gen_tmp(c, locp, source->bit_width);
+    res.is_unsigned = source->is_unsigned;
+    OUT(c, locp, "tcg_gen_rotl_", suffix, "(",
+        &res, ", ", source, ", ", &amount, ");\n");
+    rvalue_free(c, locp, source);
+    rvalue_free(c, locp, &amount);
+
+    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;
+}
+
+HexValue gen_carry_from_add(Context *c,
+                            YYLTYPE *locp,
+                            HexValue *op1,
+                            HexValue *op2,
+                            HexValue *op3)
+{
+    HexValue opa = rvalue_materialize(c, locp, op1);
+    HexValue opb = rvalue_materialize(c, locp, op2);
+    HexValue opc = rvalue_materialize(c, locp, op3);
+    opc = rvalue_extend(c, locp, &opc);
+
+    HexValue zero = gen_tmp_value(c, locp, "0", 64);
+    HexValue res = gen_tmp(c, locp, 64);
+    HexValue cf = gen_tmp(c, locp, 64);
+    OUT(c, locp, "tcg_gen_add2_i64(", &res, ", ", &cf, ", ", &opa, ", ", &zero);
+    OUT(c, locp, ", ", &opc, ", ", &zero, ");\n");
+    OUT(c, locp, "tcg_gen_add2_i64(", &res, ", ", &cf, ", ", &res, ", ", &cf);
+    OUT(c, locp, ", ", &opb, ", ", &zero, ");\n");
+
+    rvalue_free(c, locp, &opa);
+    rvalue_free(c, locp, &opb);
+    rvalue_free(c, locp, &opc);
+    rvalue_free(c, locp, &zero);
+    rvalue_free(c, locp, &res);
+    return cf;
+}
+
+void gen_inst(Context *c, GString *iname)
+{
+    c->total_insn++;
+    c->inst.name = iname;
+    c->inst.allocated = g_array_new(FALSE, FALSE, sizeof(Var));
+    c->inst.init_list = g_array_new(FALSE, FALSE, sizeof(HexValue));
+    c->inst.strings = g_array_new(FALSE, FALSE, sizeof(GString *));
+    EMIT_SIG(c, "void emit_%s(DisasContext *ctx, Insn *insn, Packet *pkt",
+             c->inst.name->str);
+}
+
+void gen_inst_args(Context *c, YYLTYPE *locp)
+{
+    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_list->len; i++) {
+        HexValue *reg = &g_array_index(c->inst.init_list, HexValue, i);
+        if (reg->type == REGISTER || reg->type == PREDICATE) {
+            OUT(c, locp, "tcg_gen_movi_i", &reg->bit_width, "(",
+                reg, ", 0);\n");
+        }
+    }
+}
+
+void gen_inst_code(Context *c, YYLTYPE *locp)
+{
+    if (c->inst.error_count != 0) {
+        fprintf(stderr,
+                "Parsing of instruction %s generated %d errors!\n",
+                c->inst.name->str,
+                c->inst.error_count);
+    } else {
+        free_variables(c, locp);
+        c->implemented_insn++;
+        fprintf(c->enabled_file, "%s\n", c->inst.name->str);
+        emit_footer(c);
+        commit(c);
+    }
+    free_instruction(c);
+}
+
+void gen_pre_assign(Context *c, YYLTYPE *locp, HexValue *lp, HexValue *rp)
+{
+    bool is_direct = is_direct_predicate(lp);
+    char pre_id[2] = " ";
+    pre_id[0] = lp->pre.id;
+    /* Extract predicate TCGv */
+    if (is_direct) {
+        *lp = gen_tmp_value(c, locp, "0", 32);
+    }
+    HexValue r = rvalue_materialize(c, locp, rp);
+    r = rvalue_truncate(c, locp, &r);
+    /* Extract first 8 bits, and store new predicate value */
+    if (is_inside_ternary(c)) {
+        yyassert(c, locp, !is_direct, "direct pre assign inside ternary op");
+        HexValue tmp = gen_tmp(c, locp, r.bit_width);
+        HexValue cond = get_ternary_cond(c, locp);
+        HexValue zero = gen_tmp_value(c, locp, "0", r.bit_width);
+        OUT(c, locp, "tcg_gen_mov_i32(", &tmp, ", ", &r, ");\n");
+        OUT(c, locp, "tcg_gen_andi_i32(", &tmp, ", ", &tmp, ", 0xff);\n");
+        OUT(c, locp, "tcg_gen_movcond_i", &r.bit_width);
+        OUT(c, locp, "(TCG_COND_NE, ", lp, ", ", &cond, ", ", &zero);
+        OUT(c, locp, ", ", &tmp, ", ", lp, ");\n");
+        rvalue_free(c, locp, &tmp);
+        rvalue_free(c, locp, &cond);
+        rvalue_free(c, locp, &zero);
+    } else {
+        OUT(c, locp, "tcg_gen_mov_i32(", lp, ", ", &r, ");\n");
+        OUT(c, locp, "tcg_gen_andi_i32(", lp, ", ", lp, ", 0xff);\n");
+    }
+    if (is_direct) {
+        OUT(c, locp, "gen_log_pred_write(ctx, ", pre_id, ", ", lp, ");\n");
+        OUT(c, locp, "ctx_log_pred_write(ctx, ", pre_id, ");\n");
+        rvalue_free(c, locp, lp);
+    }
+    rvalue_free(c, locp, &r);  /* Free temporary value */
+}
+
+void gen_load(Context *c, YYLTYPE *locp, HexValue *num, HexValue *size,
+              bool is_unsigned, HexValue *ea, HexValue *dst)
+{
+    /* Memop width is specified in the load macro */
+    int bit_width = (size->imm.value > 4) ? 64 : 32;
+    const char *sign_suffix = (size->imm.value > 4)
+                              ? ""
+                              : ((is_unsigned) ? "u" : "s");
+    char size_suffix[4] = { 0 };
+    /* Create temporary variable (if not present) */
+    if (dst->type == VARID) {
+        /* TODO: this is a common pattern, the parser should be varid-aware. */
+        varid_allocate(c, locp, dst, bit_width, is_unsigned);
+    }
+    snprintf(size_suffix, 4, "%" PRIu64, size->imm.value * 8);
+    if (bit_width == 32) {
+        *dst = rvalue_truncate(c, locp, dst);
+    } else {
+        *dst = rvalue_extend(c, locp, dst);
+    }
+    int var_id = find_variable(c, locp, ea);
+    yyassert(c, locp, var_id != -1, "Load variable must exist!\n");
+    /* We need to enforce the variable size */
+    ea->bit_width = g_array_index(c->inst.allocated, Var, var_id).bit_width;
+    if (ea->bit_width != 32) {
+        *ea = rvalue_truncate(c, locp, ea);
+    }
+    OUT(c, locp, "if (insn->slot == 0 && pkt->pkt_has_store_s1) {\n");
+    OUT(c, locp, "process_store(ctx, pkt, 1);\n");
+    OUT(c, locp, "}\n");
+    OUT(c, locp, "tcg_gen_qemu_ld", size_suffix, sign_suffix);
+    OUT(c, locp, "(", dst, ", ", ea, ", 0);\n");
+    /* If the var in EA was truncated it is now a tmp HexValue, so free it. */
+    rvalue_free(c, locp, ea);
+}
+
+void gen_store(Context *c, YYLTYPE *locp, HexValue *num, HexValue *size,
+               HexValue *ea, HexValue *src)
+{
+    /* Memop width is specified in the store macro */
+    int mem_width = size->imm.value;
+    /* Adjust operand bit width to memop bit width */
+    if (mem_width < 8) {
+        *src = rvalue_truncate(c, locp, src);
+    } else {
+        *src = rvalue_extend(c, locp, src);
+    }
+    assert(ea->type == VARID);
+    int var_id = find_variable(c, locp, ea);
+    yyassert(c, locp, var_id != -1, "Load variable must exist!\n");
+    /* We need to enforce the variable size */
+    ea->bit_width = g_array_index(c->inst.allocated, Var, var_id).bit_width;
+    if (ea->bit_width != 32) {
+        *ea = rvalue_truncate(c, locp, ea);
+    }
+    *src = rvalue_materialize(c, locp, src);
+    OUT(c, locp, "gen_store", &mem_width, "(cpu_env, ", ea, ", ", src);
+    OUT(c, locp, ", ctx, insn->slot);\n");
+    rvalue_free(c, locp, src);
+    /* If the var in ea was truncated it is now a tmp HexValue, so free it. */
+    rvalue_free(c, locp, ea);
+}
+
+void gen_sethalf(Context *c, YYLTYPE *locp, HexCast *sh, HexValue *n,
+                 HexValue *dst, HexValue *val)
+{
+    yyassert(c, locp, n->type == IMMEDIATE,
+             "Deposit index must be immediate!\n");
+    if (dst->type == VARID) {
+        int var_id = find_variable(c, locp, dst);
+        if (var_id == -1) {
+            HexValue zero = gen_imm_value(c, locp, 0, 64);
+            zero.is_unsigned = true;
+            dst->bit_width = 64;
+            gen_assign(c, locp, dst, &zero);
+        } else {
+            /* We need to enforce the variable size (default is 32) */
+            dst->bit_width = g_array_index(c->inst.allocated,
+                                           Var,
+                                           var_id).bit_width;
+        }
+    }
+    gen_deposit_op(c, locp, dst, val, n, sh);
+}
+
+void gen_setbits(Context *c, YYLTYPE *locp, HexValue *hi, HexValue *lo,
+                 HexValue *dst, HexValue *val)
+{
+    yyassert(c, locp, hi->type == IMMEDIATE &&
+             hi->imm.type == VALUE &&
+             lo->type == IMMEDIATE &&
+             lo->imm.type == VALUE,
+             "Range deposit needs immediate values!\n");
+
+    *val = rvalue_truncate(c, locp, val);
+    unsigned len = hi->imm.value + 1 - lo->imm.value;
+    HexValue tmp = gen_tmp(c, locp, 32);
+    OUT(c, locp, "tcg_gen_neg_i32(", &tmp, ", ", val, ");\n");
+    OUT(c, locp, "tcg_gen_deposit_i32(", dst, ", ", dst, ", ", &tmp, ", ");
+    OUT(c, locp, lo, ", ", &len, ");\n");
+
+    rvalue_free(c, locp, &tmp);
+    rvalue_free(c, locp, hi);
+    rvalue_free(c, locp, lo);
+    rvalue_free(c, locp, val);
+}
+
+int gen_if_cond(Context *c, YYLTYPE *locp, HexValue *cond)
+{
+    /* Generate an end label, if false branch to that label */
+    OUT(c, locp, "TCGLabel *if_label_", &c->inst.if_count,
+        " = gen_new_label();\n");
+    *cond = rvalue_materialize(c, locp, cond);
+    const char *bit_suffix = (cond->bit_width == 64) ? "i64" : "i32";
+    OUT(c, locp, "tcg_gen_brcondi_", bit_suffix, "(TCG_COND_EQ, ", cond,
+        ", 0, if_label_", &c->inst.if_count, ");\n");
+    rvalue_free(c, locp, cond);
+    return c->inst.if_count++;
+}
+
+int gen_if_else(Context *c, YYLTYPE *locp, int index)
+{
+    /* Generate label to jump if else is not verified */
+    OUT(c, locp, "TCGLabel *if_label_", &c->inst.if_count,
+        " = gen_new_label();\n");
+    int if_index = c->inst.if_count;
+    c->inst.if_count++;
+    /* Jump out of the else statement */
+    OUT(c, locp, "tcg_gen_br(if_label_", &if_index, ");\n");
+    /* Fix the else label */
+    OUT(c, locp, "gen_set_label(if_label_", &index, ");\n");
+    return if_index;
+}
+
+HexValue gen_rvalue_pre(Context *c, YYLTYPE *locp, HexValue *pre)
+{
+    if (is_direct_predicate(pre)) {
+        bool is_dotnew = pre->is_dotnew;
+        char predicate_id[2] = { pre->pre.id, '\0' };
+        char *pre_str = (char *) &predicate_id;
+        *pre = gen_tmp_value(c, locp, "0", 32);
+        if (is_dotnew) {
+            OUT(c, locp, "tcg_gen_mov_i32(", pre, ", hex_new_pred_value[");
+            OUT(c, locp, pre_str, "]);\n");
+        } else {
+            OUT(c, locp, "gen_read_preg(", pre, ", ", pre_str, ");\n");
+        }
+    }
+    return *pre;
+}
+
+HexValue gen_rvalue_var(Context *c, YYLTYPE *locp, HexValue *var)
+{
+    /* Assign correct bit width and signedness */
+    bool found = false;
+    for (int i = 0; i < c->inst.allocated->len; i++) {
+        Var *other = &g_array_index(c->inst.allocated, Var, i);
+        if (g_string_equal(var->var.name, other->name)) {
+            found = true;
+            other->name = var->var.name;
+            var->bit_width = other->bit_width;
+            var->is_unsigned = other->is_unsigned;
+            break;
+        }
+    }
+    yyassert(c, locp, found, "Undefined symbol!\n");
+    return *var;
+}
+
+HexValue gen_rvalue_mpy(Context *c, YYLTYPE *locp, HexMpy *mpy, HexValue *a,
+                        HexValue *b)
+{
+    a->is_unsigned = mpy->first_unsigned;
+    b->is_unsigned = mpy->second_unsigned;
+    *a = gen_cast_op(c, locp, a, mpy->first_bit_width * 2);
+    /* Handle fMPTY3216.. */
+    if (mpy->first_bit_width == 32) {
+        *b = gen_cast_op(c, locp, b, 64);
+    } else {
+        *b = gen_cast_op(c, locp, b, mpy->second_bit_width * 2);
+    }
+    HexValue ret = gen_bin_op(c, locp, MUL_OP, a, b);
+    /* Handle special cases required by the language */
+    if (mpy->first_bit_width == 16 && mpy->second_bit_width == 16) {
+        HexValue src_width = gen_imm_value(c, locp, 32, 32);
+        HexValue dst_width = gen_imm_value(c, locp, 64, 32);
+        ret = gen_extend_op(c, locp, &src_width, &dst_width, &ret,
+                            mpy->first_unsigned && mpy->second_unsigned);
+    }
+    return ret;
+}
+
+HexValue gen_rvalue_pow(Context *c, YYLTYPE *locp, HexValue *l, HexValue *r)
+{
+    /* We assume that this is a shorthand for a shift */
+    yyassert(c, locp, l->type == IMMEDIATE && r->imm.value == 2,
+             "Exponentiation is not a left shift!\n");
+    HexValue one = gen_imm_value(c, locp, 1, 32);
+    HexValue shift = gen_bin_op(c, locp, SUB_OP, r, &one);
+    HexValue res = gen_bin_op(c, locp, ASL_OP, l, &shift);
+    rvalue_free(c, locp, &one);
+    rvalue_free(c, locp, &shift);
+    return res;
+}
+
+HexValue gen_rvalue_not(Context *c, YYLTYPE *locp, HexValue *v)
+{
+    const char *bit_suffix = (v->bit_width == 64) ? "i64" : "i32";
+    int bit_width = (v->bit_width == 64) ? 64 : 32;
+    HexValue res;
+    res.is_unsigned = v->is_unsigned;
+    res.is_dotnew = false;
+    res.is_manual = false;
+    if (v->type == IMMEDIATE) {
+        res.type = IMMEDIATE;
+        res.imm.type = QEMU_TMP;
+        res.imm.index = c->inst.qemu_tmp_count;
+        OUT(c, locp, "int", &bit_width, "_t ", &res, " = ~", v, ";\n");
+        c->inst.qemu_tmp_count++;
+    } else {
+        res = gen_tmp(c, locp, bit_width);
+        OUT(c, locp, "tcg_gen_not_", bit_suffix, "(", &res,
+            ", ", v, ");\n");
+        rvalue_free(c, locp, v);
+    }
+    return res;
+}
+
+HexValue gen_rvalue_notl(Context *c, YYLTYPE *locp, HexValue *v)
+{
+    const char *bit_suffix = (v->bit_width == 64) ? "i64" : "i32";
+    int bit_width = (v->bit_width == 64) ? 64 : 32;
+    HexValue res;
+    res.is_unsigned = v->is_unsigned;
+    res.is_dotnew = false;
+    res.is_manual = false;
+    if (v->type == IMMEDIATE) {
+        res.type = IMMEDIATE;
+        res.imm.type = QEMU_TMP;
+        res.imm.index = c->inst.qemu_tmp_count;
+        OUT(c, locp, "int", &bit_width, "_t ", &res, " = !", v, ";\n");
+        c->inst.qemu_tmp_count++;
+    } else {
+        res = gen_tmp(c, locp, bit_width);
+        HexValue zero = gen_tmp_value(c, locp, "0", bit_width);
+        HexValue one = gen_tmp_value(c, locp, "0xff", bit_width);
+        OUT(c, locp, "tcg_gen_movcond_", bit_suffix);
+        OUT(c, locp, "(TCG_COND_EQ, ", &res, ", ", v, ", ", &zero);
+        OUT(c, locp, ", ", &one, ", ", &zero, ");\n");
+        rvalue_free(c, locp, v);
+        rvalue_free(c, locp, &zero);
+        rvalue_free(c, locp, &one);
+    }
+    return res;
+}
+
+void gen_set_overflow(Context *c, YYLTYPE *locp, HexValue *vp)
+{
+    HexValue v = *vp;
+
+    HexValue ovfl = gen_tmp(c, locp, 32);
+    ovfl.is_unsigned = true;
+    OUT(c, locp, "GET_USR_FIELD(USR_OVF, ", &ovfl, ");\n");
+
+    if (is_inside_ternary(c)) {
+        /* Inside ternary operator, need to take care of the side-effect */
+        HexValue cond = get_ternary_cond(c, locp);
+        v = rvalue_materialize(c, locp, &v);
+        bool is_64bit = cond.bit_width == 64;
+        unsigned bit_width = cond.bit_width;
+        if (is_64bit) {
+            ovfl = rvalue_extend(c, locp, &ovfl);
+            v = rvalue_extend(c, locp, &v);
+        }
+        HexValue tmp = gen_tmp_value(c, locp, "0", cond.bit_width);
+        OUT(c, locp, "tcg_gen_movcond_i", &bit_width,
+                     "(TCG_COND_NE, ", &tmp, ", ", &cond);
+        OUT(c, locp, ", ", &tmp, ", ", &v, ", ", &tmp, ");\n");
+        OUT(c, locp, "tcg_gen_or_i", &bit_width, "(",
+            &ovfl, ", ", &ovfl, ", ", &tmp, ");\n");
+        if (is_64bit) {
+            ovfl = rvalue_truncate(c, locp, &ovfl);
+        }
+        rvalue_free(c, locp, &tmp);
+        rvalue_free(c, locp, &cond);
+    } else {
+        if (v.type == IMMEDIATE) {
+            OUT(c, locp, "tcg_gen_ori_i32(",
+                &ovfl, ", ", &ovfl, ", ", &v, ");\n");
+        } else {
+            OUT(c, locp, "tcg_gen_or_i32(",
+                &ovfl, ", ", &ovfl, ", ", &v, ");\n");
+        }
+    }
+
+    OUT(c, locp, "SET_USR_FIELD(USR_OVF, ", &ovfl, ");\n");
+
+    rvalue_free(c, locp, &ovfl);
+    rvalue_free(c, locp, &v);
+}
+
+HexValue gen_rvalue_sat(Context *c, YYLTYPE *locp, HexSat *sat, HexValue *n,
+                        HexValue *v)
+{
+    if (sat->set_overflow) {
+        yyassert(c, locp, n->imm.value < v->bit_width, "To compute overflow, "
+                 "source width must be greater than saturation width!");
+    }
+    HexValue res = gen_tmp(c, locp, v->bit_width);
+    const char *bit_suffix = (v->bit_width == 64) ? "i64" : "i32";
+    const char *unsigned_str = (sat->is_unsigned) ? "u" : "";
+    if (sat->set_overflow) {
+        HexValue ovfl = gen_tmp(c, locp, 32);
+        OUT(c, locp, "gen_sat", unsigned_str, "_", bit_suffix, "_ext(");
+        OUT(c, locp, &ovfl, ", ", &res, ", ", v, ", ", &n->imm.value, ");\n");
+        gen_set_overflow(c, locp, &ovfl);
+    } else {
+        OUT(c, locp, "gen_sat", unsigned_str, "_", bit_suffix, "(", &res, ", ");
+        OUT(c, locp, v, ", ", &n->imm.value, ");\n");
+    }
+    res.is_unsigned = sat->is_unsigned;
+    rvalue_free(c, locp, v);
+    return res;
+}
+
+HexValue gen_rvalue_fscr(Context *c, YYLTYPE *locp, HexValue *v)
+{
+    HexValue key = gen_tmp(c, locp, 64);
+    HexValue res = gen_tmp(c, locp, 64);
+    *v = rvalue_extend(c, locp, v);
+    HexValue frame_key = gen_tmp(c, locp, 32);
+    OUT(c, locp, "READ_REG(", &frame_key, ", HEX_REG_FRAMEKEY);\n");
+    OUT(c, locp, "tcg_gen_concat_i32_i64(",
+        &key, ", ", &frame_key, ", ", &frame_key, ");\n");
+    OUT(c, locp, "tcg_gen_xor_i64(", &res, ", ", v, ", ", &key, ");\n");
+    rvalue_free(c, locp, &key);
+    rvalue_free(c, locp, &frame_key);
+    rvalue_free(c, locp, v);
+    return res;
+}
+
+HexValue gen_rvalue_abs(Context *c, YYLTYPE *locp, HexValue *v)
+{
+    const char *bit_suffix = (v->bit_width == 64) ? "i64" : "i32";
+    int bit_width = (v->bit_width == 64) ? 64 : 32;
+    HexValue res;
+    res.is_unsigned = v->is_unsigned;
+    res.is_dotnew = false;
+    res.is_manual = false;
+    if (v->type == IMMEDIATE) {
+        res.type = IMMEDIATE;
+        res.imm.type = QEMU_TMP;
+        res.imm.index = c->inst.qemu_tmp_count;
+        OUT(c, locp, "int", &bit_width, "_t ", &res, " = abs(", v, ");\n");
+        c->inst.qemu_tmp_count++;
+    } else {
+        res = gen_tmp(c, locp, bit_width);
+        HexValue zero = gen_tmp_value(c, locp, "0", bit_width);
+        OUT(c, locp, "tcg_gen_neg_", bit_suffix, "(", &res, ", ", v, ");\n");
+        OUT(c, locp, "tcg_gen_movcond_i", &bit_width);
+        OUT(c, locp, "(TCG_COND_GT, ", &res, ", ", v, ", ", &zero);
+        OUT(c, locp, ", ", v, ", ", &res, ");\n");
+        rvalue_free(c, locp, &zero);
+        rvalue_free(c, locp, v);
+    }
+    return res;
+}
+
+HexValue gen_rvalue_neg(Context *c, YYLTYPE *locp, HexValue *v)
+{
+    const char *bit_suffix = (v->bit_width == 64) ? "i64" : "i32";
+    int bit_width = (v->bit_width == 64) ? 64 : 32;
+    HexValue res;
+    res.is_unsigned = v->is_unsigned;
+    res.is_dotnew = false;
+    res.is_manual = false;
+    if (v->type == IMMEDIATE) {
+        res.type = IMMEDIATE;
+        res.imm.type = QEMU_TMP;
+        res.imm.index = c->inst.qemu_tmp_count;
+        OUT(c, locp, "int", &bit_width, "_t ", &res, " = -", v, ";\n");
+        c->inst.qemu_tmp_count++;
+    } else {
+        res = gen_tmp(c, locp, bit_width);
+        OUT(c, locp, "tcg_gen_neg_", bit_suffix, "(", &res, ", ", v, ");\n");
+        rvalue_free(c, locp, v);
+    }
+    return res;
+}
+
+HexValue gen_rvalue_brev(Context *c, YYLTYPE *locp, HexValue *v)
+{
+    yyassert(c, locp, v->bit_width <= 32,
+             "fbrev not implemented for 64-bit integers!");
+    HexValue res = gen_tmp(c, locp, v->bit_width);
+    *v = rvalue_materialize(c, locp, v);
+    OUT(c, locp, "gen_fbrev(", &res, ", ", v, ");\n");
+    rvalue_free(c, locp, v);
+    return res;
+}
+
+HexValue gen_rvalue_ternary(Context *c, YYLTYPE *locp, HexValue *cond,
+                            HexValue *t, HexValue *e) {
+    bool is_64bit = (t->bit_width == 64) || (e->bit_width == 64);
+    int bit_width = (is_64bit) ? 64 : 32;
+    if (is_64bit) {
+        *cond = rvalue_extend(c, locp, cond);
+        *t = rvalue_extend(c, locp, t);
+        *e = rvalue_extend(c, locp, e);
+    } else {
+        *cond = rvalue_truncate(c, locp, cond);
+    }
+    *cond = rvalue_materialize(c, locp, cond);
+    *t = rvalue_materialize(c, locp, t);
+    *e = rvalue_materialize(c, locp, e);
+    HexValue res = gen_tmp(c, locp, bit_width);
+    HexValue zero = gen_tmp_value(c, locp, "0", bit_width);
+
+    OUT(c, locp, "tcg_gen_movcond_i", &bit_width);
+    OUT(c, locp, "(TCG_COND_NE, ", &res, ", ", cond, ", ", &zero);
+    OUT(c, locp, ", ", t, ", ", e, ");\n");
+
+    assert(c->ternary->len > 0);
+    Ternary *ternary = &g_array_index(c->ternary, Ternary, c->ternary->len - 1);
+    rvalue_free_manual(c, locp, &ternary->cond);
+    g_array_remove_index(c->ternary, c->ternary->len - 1);
+
+    rvalue_free(c, locp, &zero);
+    rvalue_free(c, locp, cond);
+    rvalue_free(c, locp, t);
+    rvalue_free(c, locp, e);
+    return res;
+}
+
+const char *cond_to_str(TCGCond cond)
+{
+    switch (cond) {
+    case TCG_COND_NEVER:
+        return "TCG_COND_NEVER";
+    case TCG_COND_ALWAYS:
+        return "TCG_COND_ALWAYS";
+    case TCG_COND_EQ:
+        return "TCG_COND_EQ";
+    case TCG_COND_NE:
+        return "TCG_COND_NE";
+    case TCG_COND_LT:
+        return "TCG_COND_LT";
+    case TCG_COND_GE:
+        return "TCG_COND_GE";
+    case TCG_COND_LE:
+        return "TCG_COND_LE";
+    case TCG_COND_GT:
+        return "TCG_COND_GT";
+    case TCG_COND_LTU:
+        return "TCG_COND_LTU";
+    case TCG_COND_GEU:
+        return "TCG_COND_GEU";
+    case TCG_COND_LEU:
+        return "TCG_COND_LEU";
+    case TCG_COND_GTU:
+        return "TCG_COND_GTU";
+    default:
+        abort();
+    }
+}
+
+void emit_arg(Context *c, YYLTYPE *locp, HexValue *arg)
+{
+    switch (arg->type) {
+    case REGISTER:
+        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 track_string(Context *c, GString *s)
+{
+    g_array_append_val(c->inst.strings, s);
+}
+
+void free_variables(Context *c, YYLTYPE *locp)
+{
+    for (unsigned i = 0; i < c->inst.allocated->len; ++i) {
+        Var *var = &g_array_index(c->inst.allocated, Var, i);
+        const char *suffix = var->bit_width == 64 ? "i64" : "i32";
+        OUT(c, locp, "tcg_temp_free_", suffix, "(", var->name->str, ");\n");
+    }
+}
+
+void free_instruction(Context *c)
+{
+    assert(c->ternary->len == 0);
+    /* Free the strings */
+    g_string_truncate(c->signature_str, 0);
+    g_string_truncate(c->out_str, 0);
+    g_string_truncate(c->header_str, 0);
+    /* Free strings allocated by the instruction */
+    for (int i = 0; i < c->inst.strings->len; i++) {
+        g_string_free(g_array_index(c->inst.strings, GString*, i), TRUE);
+    }
+    g_array_free(c->inst.strings, TRUE);
+    /* Free INAME token value */
+    g_string_free(c->inst.name, TRUE);
+    /* Free variables and registers */
+    g_array_free(c->inst.allocated, TRUE);
+    g_array_free(c->inst.init_list, TRUE);
+    /* 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..fec3ad7819
--- /dev/null
+++ b/target/hexagon/idef-parser/parser-helpers.h
@@ -0,0 +1,347 @@
+/*
+ * Copyright(c) 2019-2021 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 "qemu/compiler.h"
+#include "tcg/tcg-cond.h"
+
+#include "idef-parser.tab.h"
+#include "idef-parser.yy.h"
+#include "idef-parser.h"
+
+/* Decomment this to disable yyasserts */
+/* #define NDEBUG */
+
+#define ERR_LINE_CONTEXT 40
+
+#define START_COMMENT "/" "*"
+#define END_COMMENT "*" "/"
+
+void yyerror(YYLTYPE *locp,
+             yyscan_t scanner __attribute__((unused)),
+             Context *c,
+             const char *s);
+
+#ifndef NDEBUG
+#define yyassert(context, locp, condition, msg) \
+    if (!(condition)) { \
+        yyerror(locp, (context)->scanner, (context), (msg)); \
+    }
+#endif
+
+bool is_direct_predicate(HexValue *value);
+
+/* Print functions */
+void str_print(Context *c, YYLTYPE *locp, const char *string);
+
+void 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);
+
+void out_assert(Context *c, YYLTYPE *locp, void *dummy);
+
+/* Copy output code buffer into stdout */
+void commit(Context *c);
+
+#define OUT_IMPL(c, locp, x)                    \
+    QEMU_GENERIC(typeof(*x),                \
+        (char,      str_print),             \
+        (uint64_t,  uint64_print),          \
+        (int,       int_print),             \
+        (unsigned,  uint_print),            \
+        (HexValue,  rvalue_out),            \
+        out_assert                          \
+    )(c, locp, x);                          \
+
+/* 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_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,
+                     TCGCond type,
+                     HexValue *op1_ptr,
+                     HexValue *op2_ptr);
+
+/* Code generation functions */
+HexValue gen_bin_op(Context *c,
+                       YYLTYPE *locp,
+                       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 */
+void 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);
+
+HexValue gen_carry_from_add(Context *c,
+                            YYLTYPE *locp,
+                            HexValue *op1,
+                            HexValue *op2,
+                            HexValue *op3);
+
+void gen_inst(Context *c, GString *iname);
+
+void gen_inst_args(Context *c, YYLTYPE *locp);
+
+void gen_inst_code(Context *c, YYLTYPE *locp);
+
+void gen_pre_assign(Context *c, YYLTYPE *locp, HexValue *lp, HexValue *rp);
+
+void gen_load(Context *c, YYLTYPE *locp, HexValue *num, HexValue *size,
+              bool is_unsigned, HexValue *ea, HexValue *dst);
+
+void gen_store(Context *c, YYLTYPE *locp, HexValue *num, HexValue *size,
+               HexValue *ea, HexValue *src);
+
+void gen_sethalf(Context *c, YYLTYPE *locp, HexCast *sh, HexValue *n,
+                 HexValue *dst, HexValue *val);
+
+void gen_setbits(Context *c, YYLTYPE *locp, HexValue *hi, HexValue *lo,
+                 HexValue *dst, HexValue *val);
+
+int gen_if_cond(Context *c, YYLTYPE *locp, HexValue *cond);
+
+int gen_if_else(Context *c, YYLTYPE *locp, int index);
+
+HexValue gen_rvalue_pre(Context *c, YYLTYPE *locp, HexValue *pre);
+
+HexValue gen_rvalue_var(Context *c, YYLTYPE *locp, HexValue *var);
+
+HexValue gen_rvalue_mpy(Context *c, YYLTYPE *locp, HexMpy *mpy, HexValue *a,
+                        HexValue *b);
+
+HexValue gen_rvalue_pow(Context *c, YYLTYPE *locp, HexValue *l, HexValue *r);
+
+HexValue gen_rvalue_not(Context *c, YYLTYPE *locp, HexValue *v);
+
+HexValue gen_rvalue_notl(Context *c, YYLTYPE *locp, HexValue *v);
+
+HexValue gen_rvalue_sat(Context *c, YYLTYPE *locp, HexSat *sat, HexValue *n,
+                        HexValue *v);
+
+HexValue gen_rvalue_ternary(Context *c, YYLTYPE *locp, HexValue *cond,
+                            HexValue *t, HexValue *e);
+
+HexValue gen_rvalue_fscr(Context *c, YYLTYPE *locp, HexValue *v);
+
+HexValue gen_rvalue_abs(Context *c, YYLTYPE *locp, HexValue *v);
+
+HexValue gen_rvalue_neg(Context *c, YYLTYPE *locp, HexValue *v);
+
+HexValue gen_rvalue_brev(Context *c, YYLTYPE *locp, HexValue *v);
+
+void gen_set_overflow(Context *c, YYLTYPE *locp, HexValue *vp);
+
+HexValue gen_rvalue_ternary(Context *c, YYLTYPE *locp, HexValue *cond,
+                            HexValue *t, HexValue *e);
+
+const char *cond_to_str(TCGCond cond);
+
+void emit_header(Context *c);
+
+void emit_arg(Context *c, YYLTYPE *locp, HexValue *arg);
+
+void emit_footer(Context *c);
+
+void track_string(Context *c, GString *s);
+
+void free_variables(Context *c, YYLTYPE *locp);
+
+void free_instruction(Context *c);
+
+#endif /* PARSER_HELPERS_h */
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index 329219463f..a2257d41a5 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -183,7 +183,7 @@ idef_parser_input_generated = custom_target(
     command: [python, files('gen_idef_parser_funcs.py'), 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,
@@ -196,4 +196,28 @@ flex = generator(find_program('flex'),
                  output: ['@BASENAME@.yy.c', '@BASENAME@.yy.h'],
                  arguments: ['-o', '@OUTPUT0@', '--header-file=@OUTPUT1@', '@INPUT@'])
 
+bison = generator(find_program('bison'),
+                  output: ['@BASENAME@.tab.c', '@BASENAME@.tab.h'],
+                  arguments: ['@INPUT@', '--defines=@OUTPUT1@', '--output=@OUTPUT0@'])
+
+glib_dep = dependency('glib-2.0', native: true)
+
+idef_parser = executable('idef-parser',
+                         [flex.process(idef_parser_dir / 'idef-parser.lex'),
+                          bison.process(idef_parser_dir / 'idef-parser.y'),
+                          idef_parser_dir / 'parser-helpers.c'],
+                         include_directories: ['idef-parser', '../../include/'],
+                         dependencies: [glib_dep],
+                         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 84294aef4c..e87622305e 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 \
 	ccache \
 	coreutils \
 	curl-dev \
diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker
index 9a4f5880ba..a87f1551d5 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/debian-amd64.docker b/tests/docker/dockerfiles/debian-amd64.docker
index cd4d8ebe9c..805fd6f981 100644
--- a/tests/docker/dockerfiles/debian-amd64.docker
+++ b/tests/docker/dockerfiles/debian-amd64.docker
@@ -14,6 +14,7 @@ RUN apt update && \
 RUN apt update && \
     DEBIAN_FRONTEND=noninteractive eatmydata \
     apt install -y --no-install-recommends \
+        bison \
         cscope \
         genisoimage \
         exuberant-ctags \
diff --git a/tests/docker/dockerfiles/debian10.docker b/tests/docker/dockerfiles/debian10.docker
index 0061c31854..7ae8b2f96b 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 \
@@ -27,6 +28,7 @@ RUN apt update && \
         gdb-multiarch \
         gettext \
         git \
+        libglib2.0-dev \
         libncurses5-dev \
         ninja-build \
         pkg-config \
diff --git a/tests/docker/dockerfiles/fedora-i386-cross.docker b/tests/docker/dockerfiles/fedora-i386-cross.docker
index de34f0f940..01471305ca 100644
--- a/tests/docker/dockerfiles/fedora-i386-cross.docker
+++ b/tests/docker/dockerfiles/fedora-i386-cross.docker
@@ -1,5 +1,6 @@
 FROM fedora:33
 ENV PACKAGES \
+    bison \
     bzip2 \
     ccache \
     diffutils \
@@ -7,6 +8,7 @@ ENV PACKAGES \
     flex \
     gcc \
     git \
+    glib2-devel \
     libtasn1-devel.i686 \
     libzstd-devel.i686 \
     make \
diff --git a/tests/docker/dockerfiles/fedora-win32-cross.docker b/tests/docker/dockerfiles/fedora-win32-cross.docker
index c1726ed78d..d65dde063b 100644
--- a/tests/docker/dockerfiles/fedora-win32-cross.docker
+++ b/tests/docker/dockerfiles/fedora-win32-cross.docker
@@ -2,6 +2,7 @@ FROM fedora:33
 
 # Please keep this list sorted alphabetically
 ENV PACKAGES \
+    bison \
     bc \
     bzip2 \
     ccache \
@@ -11,6 +12,7 @@ ENV PACKAGES \
     gcc \
     gettext \
     git \
+    glib2-devel \
     hostname \
     make \
     meson \
diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker
index 5f82a7c1a5..15cd48a5da 100644
--- a/tests/docker/dockerfiles/fedora-win64-cross.docker
+++ b/tests/docker/dockerfiles/fedora-win64-cross.docker
@@ -2,6 +2,7 @@ FROM fedora:33
 
 # Please keep this list sorted alphabetically
 ENV PACKAGES \
+    bison \
     bc \
     bzip2 \
     ccache \
@@ -10,6 +11,7 @@ ENV PACKAGES \
     flex \
     gcc \
     gettext \
+    glib2-devel \
     git \
     hostname \
     make \
diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker
index 3eeed98164..4308ae7f93 100644
--- a/tests/docker/dockerfiles/fedora.docker
+++ b/tests/docker/dockerfiles/fedora.docker
@@ -2,6 +2,7 @@ FROM fedora:33
 
 # 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 73b84ba72c..5ba970b127 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 \
     ccache \
diff --git a/tests/docker/dockerfiles/ubuntu.docker b/tests/docker/dockerfiles/ubuntu.docker
index 60f0c68426..cbe26b727a 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 \
@@ -30,6 +31,7 @@ ENV PACKAGES \
     libepoxy-dev \
     libfdt-dev \
     libgbm-dev \
+    libglib2.0-dev \
     libgnutls28-dev \
     libgtk-3-dev \
     libibverbs-dev \
diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker
index 1dcd83ac92..8d5a157a7d 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 \
@@ -18,6 +19,7 @@ ENV PACKAGES \
     libepoxy-dev \
     libfdt-dev \
     libgbm-dev \
+    libglib2.0-dev \
     libgtk-3-dev \
     libibverbs-dev \
     libiscsi-dev \
diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker
index 9ca753a6d9..29d9e07bb7 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\
@@ -21,6 +22,7 @@ ENV PACKAGES bison \
     libepoxy-dev \
     libfdt-dev \
     libgbm-dev \
+    libglib2.0-dev \
     libgtk-3-dev \
     libibverbs-dev \
     libiscsi-dev \
-- 
2.31.1



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

* [PATCH v5 11/14] target/hexagon: call idef-parser functions
  2021-06-19  9:36 [PATCH v5 00/14] target/hexagon: introduce idef-parser Alessandro Di Federico via
                   ` (9 preceding siblings ...)
  2021-06-19  9:37 ` [PATCH v5 10/14] target/hexagon: import parser " Alessandro Di Federico via
@ 2021-06-19  9:37 ` Alessandro Di Federico via
  2021-06-25 22:00   ` Taylor Simpson
  2021-06-19  9:37 ` [PATCH v5 12/14] target/hexagon: remove unused macros and functions Alessandro Di Federico via
                   ` (2 subsequent siblings)
  13 siblings, 1 reply; 38+ messages in thread
From: Alessandro Di Federico via @ 2021-06-19  9:37 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_helper_funcs.py  |  5 ++-
 target/hexagon/gen_helper_protos.py |  5 ++-
 target/hexagon/gen_tcg_funcs.py     | 28 +++++++++++-
 target/hexagon/hex_common.py        | 10 +++++
 target/hexagon/meson.build          | 68 ++++++++++++++++-------------
 5 files changed, 82 insertions(+), 34 deletions(-)

diff --git a/target/hexagon/gen_helper_funcs.py b/target/hexagon/gen_helper_funcs.py
index 2b1c5d8e3e..40fcc0269a 100755
--- a/target/hexagon/gen_helper_funcs.py
+++ b/target/hexagon/gen_helper_funcs.py
@@ -192,11 +192,12 @@ 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.read_idef_parser_enabled_file(sys.argv[4])
     hex_common.calculate_attribs()
     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:
         for tag in hex_common.tags:
             ## Skip the priv instructions
             if ( "A_PRIV" in hex_common.attribdict[tag] ) :
@@ -213,6 +214,8 @@ def main():
                 continue
             if ( hex_common.skip_qemu_helper(tag) ):
                 continue
+            if ( hex_common.is_idef_parser_enabled(tag) ):
+                continue
 
             gen_helper_function(f, tag, tagregs, tagimms)
 
diff --git a/target/hexagon/gen_helper_protos.py b/target/hexagon/gen_helper_protos.py
index ea41007ec9..6aee7229cb 100755
--- a/target/hexagon/gen_helper_protos.py
+++ b/target/hexagon/gen_helper_protos.py
@@ -121,11 +121,12 @@ 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.read_idef_parser_enabled_file(sys.argv[4])
     hex_common.calculate_attribs()
     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:
         for tag in hex_common.tags:
             ## Skip the priv instructions
             if ( "A_PRIV" in hex_common.attribdict[tag] ) :
@@ -143,6 +144,8 @@ def main():
 
             if ( hex_common.skip_qemu_helper(tag) ):
                 continue
+            if ( hex_common.is_idef_parser_enabled(tag) ):
+                continue
 
             gen_helper_prototype(f, tag, tagregs, tagimms)
 
diff --git a/target/hexagon/gen_tcg_funcs.py b/target/hexagon/gen_tcg_funcs.py
index 7ceb25b5f6..e12f6b7cfc 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 a2257d41a5..cb6eb77c24 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -42,10 +42,7 @@ hexagon_ss.add(semantics_generated)
 # Step 2
 # We use Python scripts to generate the following files
 #     shortcode_generated.h.inc
-#     helper_protos_generated.h.inc
-#     tcg_funcs_generated.c.inc
 #     tcg_func_table_generated.c.inc
-#     helper_funcs_generated.c.inc
 #     printinsn_generated.h.inc
 #     op_regs_generated.h.inc
 #     op_attribs_generated.h.inc
@@ -60,24 +57,6 @@ shortcode_generated = custom_target(
 )
 hexagon_ss.add(shortcode_generated)
 
-helper_protos_generated = custom_target(
-    'helper_protos_generated.h.inc',
-    output: 'helper_protos_generated.h.inc',
-    depends: [semantics_generated],
-    depend_files: [hex_common_py, attribs_def, gen_tcg_h],
-    command: [python, files('gen_helper_protos.py'), semantics_generated, attribs_def, gen_tcg_h, '@OUTPUT@'],
-)
-hexagon_ss.add(helper_protos_generated)
-
-tcg_funcs_generated = custom_target(
-    'tcg_funcs_generated.c.inc',
-    output: 'tcg_funcs_generated.c.inc',
-    depends: [semantics_generated],
-    depend_files: [hex_common_py, attribs_def, gen_tcg_h],
-    command: [python, files('gen_tcg_funcs.py'), 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',
@@ -87,15 +66,6 @@ tcg_func_table_generated = custom_target(
 )
 hexagon_ss.add(tcg_func_table_generated)
 
-helper_funcs_generated = custom_target(
-    'helper_funcs_generated.c.inc',
-    output: 'helper_funcs_generated.c.inc',
-    depends: [semantics_generated],
-    depend_files: [hex_common_py, attribs_def, gen_tcg_h],
-    command: [python, files('gen_helper_funcs.py'), semantics_generated, attribs_def, gen_tcg_h, '@OUTPUT@'],
-)
-hexagon_ss.add(helper_funcs_generated)
-
 printinsn_generated = custom_target(
     'printinsn_generated.h.inc',
     output: 'printinsn_generated.h.inc',
@@ -220,4 +190,42 @@ 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)
+
+#
+# Step 5
+# We use Python scripts to generate the following files
+#     helper_protos_generated.h.inc
+#     helper_funcs_generated.c.inc
+#     tcg_funcs_generated.c.inc
+#
+helper_protos_generated = custom_target(
+    'helper_protos_generated.h.inc',
+    output: 'helper_protos_generated.h.inc',
+    depends: [semantics_generated, idef_generated_tcg],
+    depend_files: [hex_common_py, attribs_def, gen_tcg_h],
+    command: [python, files('gen_helper_protos.py'), semantics_generated, attribs_def, gen_tcg_h, idef_generated_list, '@OUTPUT@'],
+)
+hexagon_ss.add(helper_protos_generated)
+
+helper_funcs_generated = custom_target(
+    'helper_funcs_generated.c.inc',
+    output: 'helper_funcs_generated.c.inc',
+    depends: [semantics_generated, idef_generated_tcg],
+    depend_files: [hex_common_py, attribs_def, gen_tcg_h],
+    command: [python, files('gen_helper_funcs.py'), semantics_generated, attribs_def, gen_tcg_h, idef_generated_list, '@OUTPUT@'],
+)
+hexagon_ss.add(helper_funcs_generated)
+
+tcg_funcs_generated = custom_target(
+    'tcg_funcs_generated.c.inc',
+    output: 'tcg_funcs_generated.c.inc',
+    depends: [semantics_generated, idef_generated_tcg],
+    depend_files: [hex_common_py, attribs_def, gen_tcg_h],
+    command: [python, files('gen_tcg_funcs.py'), semantics_generated, attribs_def, gen_tcg_h, idef_generated_list, '@OUTPUT@'],
+)
+hexagon_ss.add(tcg_funcs_generated)
+
 target_arch += {'hexagon': hexagon_ss}
-- 
2.31.1



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

* [PATCH v5 12/14] target/hexagon: remove unused macros and functions
  2021-06-19  9:36 [PATCH v5 00/14] target/hexagon: introduce idef-parser Alessandro Di Federico via
                   ` (10 preceding siblings ...)
  2021-06-19  9:37 ` [PATCH v5 11/14] target/hexagon: call idef-parser functions Alessandro Di Federico via
@ 2021-06-19  9:37 ` Alessandro Di Federico via
  2021-06-25 22:02   ` Taylor Simpson
  2021-06-19  9:37 ` [PATCH v5 13/14] target/hexagon: import additional tests Alessandro Di Federico via
  2021-06-19  9:37 ` [PATCH v5 14/14] gitlab-ci: do not use qemu-project Docker registry Alessandro Di Federico via
  13 siblings, 1 reply; 38+ messages in thread
From: Alessandro Di Federico via @ 2021-06-19  9:37 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/gen_tcg.h   | 528 -------------------------------------
 target/hexagon/genptr.c    |  98 -------
 target/hexagon/macros.h    | 200 +-------------
 target/hexagon/op_helper.c | 119 ---------
 4 files changed, 9 insertions(+), 936 deletions(-)

diff --git a/target/hexagon/gen_tcg.h b/target/hexagon/gen_tcg.h
index 18fcdbc7e4..f1dd1b64c1 100644
--- a/target/hexagon/gen_tcg.h
+++ b/target/hexagon/gen_tcg.h
@@ -43,381 +43,6 @@
  *     _pcr      post increment circular register  r0 = memw(r1++I:circ(m0))
  */
 
-/* Macros for complex addressing modes */
-#define GET_EA_ap \
-    do { \
-        fEA_IMM(UiV); \
-        tcg_gen_movi_tl(ReV, UiV); \
-    } while (0)
-#define GET_EA_pr \
-    do { \
-        fEA_REG(RxV); \
-        fPM_M(RxV, MuV); \
-    } while (0)
-#define GET_EA_pbr \
-    do { \
-        gen_helper_fbrev(EA, RxV); \
-        tcg_gen_add_tl(RxV, RxV, MuV); \
-    } while (0)
-#define GET_EA_pi \
-    do { \
-        fEA_REG(RxV); \
-        fPM_I(RxV, siV); \
-    } while (0)
-#define GET_EA_pci \
-    do { \
-        TCGv tcgv_siV = tcg_const_tl(siV); \
-        tcg_gen_mov_tl(EA, RxV); \
-        gen_helper_fcircadd(RxV, RxV, tcgv_siV, MuV, \
-                            hex_gpr[HEX_REG_CS0 + MuN]); \
-        tcg_temp_free(tcgv_siV); \
-    } while (0)
-#define GET_EA_pcr(SHIFT) \
-    do { \
-        TCGv ireg = tcg_temp_new(); \
-        tcg_gen_mov_tl(EA, RxV); \
-        gen_read_ireg(ireg, MuV, (SHIFT)); \
-        gen_helper_fcircadd(RxV, RxV, ireg, MuV, hex_gpr[HEX_REG_CS0 + MuN]); \
-        tcg_temp_free(ireg); \
-    } while (0)
-
-/* Instructions with multiple definitions */
-#define fGEN_TCG_LOAD_AP(RES, SIZE, SIGN) \
-    do { \
-        fMUST_IMMEXT(UiV); \
-        fEA_IMM(UiV); \
-        fLOAD(1, SIZE, SIGN, EA, RES); \
-        tcg_gen_movi_tl(ReV, UiV); \
-    } while (0)
-
-#define fGEN_TCG_L4_loadrub_ap(SHORTCODE) \
-    fGEN_TCG_LOAD_AP(RdV, 1, u)
-#define fGEN_TCG_L4_loadrb_ap(SHORTCODE) \
-    fGEN_TCG_LOAD_AP(RdV, 1, s)
-#define fGEN_TCG_L4_loadruh_ap(SHORTCODE) \
-    fGEN_TCG_LOAD_AP(RdV, 2, u)
-#define fGEN_TCG_L4_loadrh_ap(SHORTCODE) \
-    fGEN_TCG_LOAD_AP(RdV, 2, s)
-#define fGEN_TCG_L4_loadri_ap(SHORTCODE) \
-    fGEN_TCG_LOAD_AP(RdV, 4, u)
-#define fGEN_TCG_L4_loadrd_ap(SHORTCODE) \
-    fGEN_TCG_LOAD_AP(RddV, 8, u)
-
-#define fGEN_TCG_L2_loadrub_pci(SHORTCODE)    SHORTCODE
-#define fGEN_TCG_L2_loadrb_pci(SHORTCODE)     SHORTCODE
-#define fGEN_TCG_L2_loadruh_pci(SHORTCODE)    SHORTCODE
-#define fGEN_TCG_L2_loadrh_pci(SHORTCODE)     SHORTCODE
-#define fGEN_TCG_L2_loadri_pci(SHORTCODE)     SHORTCODE
-#define fGEN_TCG_L2_loadrd_pci(SHORTCODE)     SHORTCODE
-
-#define fGEN_TCG_LOAD_pcr(SHIFT, LOAD) \
-    do { \
-        TCGv ireg = tcg_temp_new(); \
-        tcg_gen_mov_tl(EA, RxV); \
-        gen_read_ireg(ireg, MuV, SHIFT); \
-        gen_helper_fcircadd(RxV, RxV, ireg, MuV, hex_gpr[HEX_REG_CS0 + MuN]); \
-        LOAD; \
-        tcg_temp_free(ireg); \
-    } while (0)
-
-#define fGEN_TCG_L2_loadrub_pcr(SHORTCODE) \
-      fGEN_TCG_LOAD_pcr(0, fLOAD(1, 1, u, EA, RdV))
-#define fGEN_TCG_L2_loadrb_pcr(SHORTCODE) \
-      fGEN_TCG_LOAD_pcr(0, fLOAD(1, 1, s, EA, RdV))
-#define fGEN_TCG_L2_loadruh_pcr(SHORTCODE) \
-      fGEN_TCG_LOAD_pcr(1, fLOAD(1, 2, u, EA, RdV))
-#define fGEN_TCG_L2_loadrh_pcr(SHORTCODE) \
-      fGEN_TCG_LOAD_pcr(1, fLOAD(1, 2, s, EA, RdV))
-#define fGEN_TCG_L2_loadri_pcr(SHORTCODE) \
-      fGEN_TCG_LOAD_pcr(2, fLOAD(1, 4, u, EA, RdV))
-#define fGEN_TCG_L2_loadrd_pcr(SHORTCODE) \
-      fGEN_TCG_LOAD_pcr(3, fLOAD(1, 8, u, EA, RddV))
-
-#define fGEN_TCG_L2_loadrub_pr(SHORTCODE)      SHORTCODE
-#define fGEN_TCG_L2_loadrub_pbr(SHORTCODE)     SHORTCODE
-#define fGEN_TCG_L2_loadrub_pi(SHORTCODE)      SHORTCODE
-#define fGEN_TCG_L2_loadrb_pr(SHORTCODE)       SHORTCODE
-#define fGEN_TCG_L2_loadrb_pbr(SHORTCODE)      SHORTCODE
-#define fGEN_TCG_L2_loadrb_pi(SHORTCODE)       SHORTCODE
-#define fGEN_TCG_L2_loadruh_pr(SHORTCODE)      SHORTCODE
-#define fGEN_TCG_L2_loadruh_pbr(SHORTCODE)     SHORTCODE
-#define fGEN_TCG_L2_loadruh_pi(SHORTCODE)      SHORTCODE
-#define fGEN_TCG_L2_loadrh_pr(SHORTCODE)       SHORTCODE
-#define fGEN_TCG_L2_loadrh_pbr(SHORTCODE)      SHORTCODE
-#define fGEN_TCG_L2_loadrh_pi(SHORTCODE)       SHORTCODE
-#define fGEN_TCG_L2_loadri_pr(SHORTCODE)       SHORTCODE
-#define fGEN_TCG_L2_loadri_pbr(SHORTCODE)      SHORTCODE
-#define fGEN_TCG_L2_loadri_pi(SHORTCODE)       SHORTCODE
-#define fGEN_TCG_L2_loadrd_pr(SHORTCODE)       SHORTCODE
-#define fGEN_TCG_L2_loadrd_pbr(SHORTCODE)      SHORTCODE
-#define fGEN_TCG_L2_loadrd_pi(SHORTCODE)       SHORTCODE
-
-/*
- * These instructions load 2 bytes and places them in
- * two halves of the destination register.
- * The GET_EA macro determines the addressing mode.
- * The SIGN argument determines whether to zero-extend or
- * sign-extend.
- */
-#define fGEN_TCG_loadbXw2(GET_EA, SIGN) \
-    do { \
-        TCGv tmp = tcg_temp_new(); \
-        TCGv byte = tcg_temp_new(); \
-        GET_EA; \
-        fLOAD(1, 2, u, EA, tmp); \
-        tcg_gen_movi_tl(RdV, 0); \
-        for (int i = 0; i < 2; i++) { \
-            gen_set_half(i, RdV, gen_get_byte(byte, i, tmp, (SIGN))); \
-        } \
-        tcg_temp_free(tmp); \
-        tcg_temp_free(byte); \
-    } while (0)
-
-#define fGEN_TCG_L2_loadbzw2_io(SHORTCODE) \
-    fGEN_TCG_loadbXw2(fEA_RI(RsV, siV), false)
-#define fGEN_TCG_L4_loadbzw2_ur(SHORTCODE) \
-    fGEN_TCG_loadbXw2(fEA_IRs(UiV, RtV, uiV), false)
-#define fGEN_TCG_L2_loadbsw2_io(SHORTCODE) \
-    fGEN_TCG_loadbXw2(fEA_RI(RsV, siV), true)
-#define fGEN_TCG_L4_loadbsw2_ur(SHORTCODE) \
-    fGEN_TCG_loadbXw2(fEA_IRs(UiV, RtV, uiV), true)
-#define fGEN_TCG_L4_loadbzw2_ap(SHORTCODE) \
-    fGEN_TCG_loadbXw2(GET_EA_ap, false)
-#define fGEN_TCG_L2_loadbzw2_pr(SHORTCODE) \
-    fGEN_TCG_loadbXw2(GET_EA_pr, false)
-#define fGEN_TCG_L2_loadbzw2_pbr(SHORTCODE) \
-    fGEN_TCG_loadbXw2(GET_EA_pbr, false)
-#define fGEN_TCG_L2_loadbzw2_pi(SHORTCODE) \
-    fGEN_TCG_loadbXw2(GET_EA_pi, false)
-#define fGEN_TCG_L4_loadbsw2_ap(SHORTCODE) \
-    fGEN_TCG_loadbXw2(GET_EA_ap, true)
-#define fGEN_TCG_L2_loadbsw2_pr(SHORTCODE) \
-    fGEN_TCG_loadbXw2(GET_EA_pr, true)
-#define fGEN_TCG_L2_loadbsw2_pbr(SHORTCODE) \
-    fGEN_TCG_loadbXw2(GET_EA_pbr, true)
-#define fGEN_TCG_L2_loadbsw2_pi(SHORTCODE) \
-    fGEN_TCG_loadbXw2(GET_EA_pi, true)
-#define fGEN_TCG_L2_loadbzw2_pci(SHORTCODE) \
-    fGEN_TCG_loadbXw2(GET_EA_pci, false)
-#define fGEN_TCG_L2_loadbsw2_pci(SHORTCODE) \
-    fGEN_TCG_loadbXw2(GET_EA_pci, true)
-#define fGEN_TCG_L2_loadbzw2_pcr(SHORTCODE) \
-    fGEN_TCG_loadbXw2(GET_EA_pcr(1), false)
-#define fGEN_TCG_L2_loadbsw2_pcr(SHORTCODE) \
-    fGEN_TCG_loadbXw2(GET_EA_pcr(1), true)
-
-/*
- * These instructions load 4 bytes and places them in
- * four halves of the destination register pair.
- * The GET_EA macro determines the addressing mode.
- * The SIGN argument determines whether to zero-extend or
- * sign-extend.
- */
-#define fGEN_TCG_loadbXw4(GET_EA, SIGN) \
-    do { \
-        TCGv tmp = tcg_temp_new(); \
-        TCGv byte = tcg_temp_new(); \
-        GET_EA; \
-        fLOAD(1, 4, u, EA, tmp);  \
-        tcg_gen_movi_i64(RddV, 0); \
-        for (int i = 0; i < 4; i++) { \
-            gen_set_half_i64(i, RddV, gen_get_byte(byte, i, tmp, (SIGN)));  \
-        }  \
-        tcg_temp_free(tmp); \
-        tcg_temp_free(byte); \
-    } while (0)
-
-#define fGEN_TCG_L2_loadbzw4_io(SHORTCODE) \
-    fGEN_TCG_loadbXw4(fEA_RI(RsV, siV), false)
-#define fGEN_TCG_L4_loadbzw4_ur(SHORTCODE) \
-    fGEN_TCG_loadbXw4(fEA_IRs(UiV, RtV, uiV), false)
-#define fGEN_TCG_L2_loadbsw4_io(SHORTCODE) \
-    fGEN_TCG_loadbXw4(fEA_RI(RsV, siV), true)
-#define fGEN_TCG_L4_loadbsw4_ur(SHORTCODE) \
-    fGEN_TCG_loadbXw4(fEA_IRs(UiV, RtV, uiV), true)
-#define fGEN_TCG_L2_loadbzw4_pci(SHORTCODE) \
-    fGEN_TCG_loadbXw4(GET_EA_pci, false)
-#define fGEN_TCG_L2_loadbsw4_pci(SHORTCODE) \
-    fGEN_TCG_loadbXw4(GET_EA_pci, true)
-#define fGEN_TCG_L2_loadbzw4_pcr(SHORTCODE) \
-    fGEN_TCG_loadbXw4(GET_EA_pcr(2), false)
-#define fGEN_TCG_L2_loadbsw4_pcr(SHORTCODE) \
-    fGEN_TCG_loadbXw4(GET_EA_pcr(2), true)
-#define fGEN_TCG_L4_loadbzw4_ap(SHORTCODE) \
-    fGEN_TCG_loadbXw4(GET_EA_ap, false)
-#define fGEN_TCG_L2_loadbzw4_pr(SHORTCODE) \
-    fGEN_TCG_loadbXw4(GET_EA_pr, false)
-#define fGEN_TCG_L2_loadbzw4_pbr(SHORTCODE) \
-    fGEN_TCG_loadbXw4(GET_EA_pbr, false)
-#define fGEN_TCG_L2_loadbzw4_pi(SHORTCODE) \
-    fGEN_TCG_loadbXw4(GET_EA_pi, false)
-#define fGEN_TCG_L4_loadbsw4_ap(SHORTCODE) \
-    fGEN_TCG_loadbXw4(GET_EA_ap, true)
-#define fGEN_TCG_L2_loadbsw4_pr(SHORTCODE) \
-    fGEN_TCG_loadbXw4(GET_EA_pr, true)
-#define fGEN_TCG_L2_loadbsw4_pbr(SHORTCODE) \
-    fGEN_TCG_loadbXw4(GET_EA_pbr, true)
-#define fGEN_TCG_L2_loadbsw4_pi(SHORTCODE) \
-    fGEN_TCG_loadbXw4(GET_EA_pi, true)
-
-/*
- * These instructions load a half word, shift the destination right by 16 bits
- * and place the loaded value in the high half word of the destination pair.
- * The GET_EA macro determines the addressing mode.
- */
-#define fGEN_TCG_loadalignh(GET_EA) \
-    do { \
-        TCGv tmp = tcg_temp_new(); \
-        TCGv_i64 tmp_i64 = tcg_temp_new_i64(); \
-        GET_EA;  \
-        fLOAD(1, 2, u, EA, tmp);  \
-        tcg_gen_extu_i32_i64(tmp_i64, tmp); \
-        tcg_gen_shri_i64(RyyV, RyyV, 16); \
-        tcg_gen_deposit_i64(RyyV, RyyV, tmp_i64, 48, 16); \
-        tcg_temp_free(tmp); \
-        tcg_temp_free_i64(tmp_i64); \
-    } while (0)
-
-#define fGEN_TCG_L4_loadalignh_ur(SHORTCODE) \
-    fGEN_TCG_loadalignh(fEA_IRs(UiV, RtV, uiV))
-#define fGEN_TCG_L2_loadalignh_io(SHORTCODE) \
-    fGEN_TCG_loadalignh(fEA_RI(RsV, siV))
-#define fGEN_TCG_L2_loadalignh_pci(SHORTCODE) \
-    fGEN_TCG_loadalignh(GET_EA_pci)
-#define fGEN_TCG_L2_loadalignh_pcr(SHORTCODE) \
-    fGEN_TCG_loadalignh(GET_EA_pcr(1))
-#define fGEN_TCG_L4_loadalignh_ap(SHORTCODE) \
-    fGEN_TCG_loadalignh(GET_EA_ap)
-#define fGEN_TCG_L2_loadalignh_pr(SHORTCODE) \
-    fGEN_TCG_loadalignh(GET_EA_pr)
-#define fGEN_TCG_L2_loadalignh_pbr(SHORTCODE) \
-    fGEN_TCG_loadalignh(GET_EA_pbr)
-#define fGEN_TCG_L2_loadalignh_pi(SHORTCODE) \
-    fGEN_TCG_loadalignh(GET_EA_pi)
-
-/* Same as above, but loads a byte instead of half word */
-#define fGEN_TCG_loadalignb(GET_EA) \
-    do { \
-        TCGv tmp = tcg_temp_new(); \
-        TCGv_i64 tmp_i64 = tcg_temp_new_i64(); \
-        GET_EA;  \
-        fLOAD(1, 1, u, EA, tmp);  \
-        tcg_gen_extu_i32_i64(tmp_i64, tmp); \
-        tcg_gen_shri_i64(RyyV, RyyV, 8); \
-        tcg_gen_deposit_i64(RyyV, RyyV, tmp_i64, 56, 8); \
-        tcg_temp_free(tmp); \
-        tcg_temp_free_i64(tmp_i64); \
-    } while (0)
-
-#define fGEN_TCG_L2_loadalignb_io(SHORTCODE) \
-    fGEN_TCG_loadalignb(fEA_RI(RsV, siV))
-#define fGEN_TCG_L4_loadalignb_ur(SHORTCODE) \
-    fGEN_TCG_loadalignb(fEA_IRs(UiV, RtV, uiV))
-#define fGEN_TCG_L2_loadalignb_pci(SHORTCODE) \
-    fGEN_TCG_loadalignb(GET_EA_pci)
-#define fGEN_TCG_L2_loadalignb_pcr(SHORTCODE) \
-    fGEN_TCG_loadalignb(GET_EA_pcr(0))
-#define fGEN_TCG_L4_loadalignb_ap(SHORTCODE) \
-    fGEN_TCG_loadalignb(GET_EA_ap)
-#define fGEN_TCG_L2_loadalignb_pr(SHORTCODE) \
-    fGEN_TCG_loadalignb(GET_EA_pr)
-#define fGEN_TCG_L2_loadalignb_pbr(SHORTCODE) \
-    fGEN_TCG_loadalignb(GET_EA_pbr)
-#define fGEN_TCG_L2_loadalignb_pi(SHORTCODE) \
-    fGEN_TCG_loadalignb(GET_EA_pi)
-
-/*
- * Predicated loads
- * Here is a primer to understand the tag names
- *
- * Predicate used
- *      t        true "old" value                  if (p0) r0 = memb(r2+#0)
- *      f        false "old" value                 if (!p0) r0 = memb(r2+#0)
- *      tnew     true "new" value                  if (p0.new) r0 = memb(r2+#0)
- *      fnew     false "new" value                 if (!p0.new) r0 = memb(r2+#0)
- */
-#define fGEN_TCG_PRED_LOAD(GET_EA, PRED, SIZE, SIGN) \
-    do { \
-        TCGv LSB = tcg_temp_local_new(); \
-        TCGLabel *label = gen_new_label(); \
-        GET_EA; \
-        PRED;  \
-        PRED_LOAD_CANCEL(LSB, EA); \
-        tcg_gen_movi_tl(RdV, 0); \
-        tcg_gen_brcondi_tl(TCG_COND_EQ, LSB, 0, label); \
-            fLOAD(1, SIZE, SIGN, EA, RdV); \
-        gen_set_label(label); \
-        tcg_temp_free(LSB); \
-    } while (0)
-
-#define fGEN_TCG_L2_ploadrubt_pi(SHORTCODE) \
-    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBOLD(PtV), 1, u)
-#define fGEN_TCG_L2_ploadrubf_pi(SHORTCODE) \
-    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBOLDNOT(PtV), 1, u)
-#define fGEN_TCG_L2_ploadrubtnew_pi(SHORTCODE) \
-    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBNEW(PtN), 1, u)
-#define fGEN_TCG_L2_ploadrubfnew_pi(SHORTCODE) \
-    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBNEWNOT(PtN), 1, u)
-#define fGEN_TCG_L2_ploadrbt_pi(SHORTCODE) \
-    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBOLD(PtV), 1, s)
-#define fGEN_TCG_L2_ploadrbf_pi(SHORTCODE) \
-    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBOLDNOT(PtV), 1, s)
-#define fGEN_TCG_L2_ploadrbtnew_pi(SHORTCODE) \
-    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBNEW(PtN), 1, s)
-#define fGEN_TCG_L2_ploadrbfnew_pi(SHORTCODE) \
-    fGEN_TCG_PRED_LOAD({ fEA_REG(RxV); fPM_I(RxV, siV); }, \
-                       fLSBNEWNOT(PtN), 1, s)
-
-#define fGEN_TCG_L2_ploadruht_pi(SHORTCODE) \
-    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBOLD(PtV), 2, u)
-#define fGEN_TCG_L2_ploadruhf_pi(SHORTCODE) \
-    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBOLDNOT(PtV), 2, u)
-#define fGEN_TCG_L2_ploadruhtnew_pi(SHORTCODE) \
-    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBNEW(PtN), 2, u)
-#define fGEN_TCG_L2_ploadruhfnew_pi(SHORTCODE) \
-    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBNEWNOT(PtN), 2, u)
-#define fGEN_TCG_L2_ploadrht_pi(SHORTCODE) \
-    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBOLD(PtV), 2, s)
-#define fGEN_TCG_L2_ploadrhf_pi(SHORTCODE) \
-    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBOLDNOT(PtV), 2, s)
-#define fGEN_TCG_L2_ploadrhtnew_pi(SHORTCODE) \
-    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBNEW(PtN), 2, s)
-#define fGEN_TCG_L2_ploadrhfnew_pi(SHORTCODE) \
-    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBNEWNOT(PtN), 2, s)
-
-#define fGEN_TCG_L2_ploadrit_pi(SHORTCODE) \
-    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBOLD(PtV), 4, u)
-#define fGEN_TCG_L2_ploadrif_pi(SHORTCODE) \
-    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBOLDNOT(PtV), 4, u)
-#define fGEN_TCG_L2_ploadritnew_pi(SHORTCODE) \
-    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBNEW(PtN), 4, u)
-#define fGEN_TCG_L2_ploadrifnew_pi(SHORTCODE) \
-    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBNEWNOT(PtN), 4, u)
-
-/* Predicated loads into a register pair */
-#define fGEN_TCG_PRED_LOAD_PAIR(GET_EA, PRED) \
-    do { \
-        TCGv LSB = tcg_temp_local_new(); \
-        TCGLabel *label = gen_new_label(); \
-        GET_EA; \
-        PRED;  \
-        PRED_LOAD_CANCEL(LSB, EA); \
-        tcg_gen_movi_i64(RddV, 0); \
-        tcg_gen_brcondi_tl(TCG_COND_EQ, LSB, 0, label); \
-            fLOAD(1, 8, u, EA, RddV); \
-        gen_set_label(label); \
-        tcg_temp_free(LSB); \
-    } while (0)
-
-#define fGEN_TCG_L2_ploadrdt_pi(SHORTCODE) \
-    fGEN_TCG_PRED_LOAD_PAIR(GET_EA_pi, fLSBOLD(PtV))
-#define fGEN_TCG_L2_ploadrdf_pi(SHORTCODE) \
-    fGEN_TCG_PRED_LOAD_PAIR(GET_EA_pi, fLSBOLDNOT(PtV))
-#define fGEN_TCG_L2_ploadrdtnew_pi(SHORTCODE) \
-    fGEN_TCG_PRED_LOAD_PAIR(GET_EA_pi, fLSBNEW(PtN))
-#define fGEN_TCG_L2_ploadrdfnew_pi(SHORTCODE) \
-    fGEN_TCG_PRED_LOAD_PAIR(GET_EA_pi, fLSBNEWNOT(PtN))
-
 /* load-locked and store-locked */
 #define fGEN_TCG_L2_loadw_locked(SHORTCODE) \
     SHORTCODE
@@ -428,95 +53,6 @@
 #define fGEN_TCG_S4_stored_locked(SHORTCODE) \
     do { SHORTCODE; READ_PREG(PdV, PdN); } while (0)
 
-#define fGEN_TCG_STORE(SHORTCODE) \
-    do { \
-        TCGv HALF = tcg_temp_new(); \
-        TCGv BYTE = tcg_temp_new(); \
-        SHORTCODE; \
-        tcg_temp_free(HALF); \
-        tcg_temp_free(BYTE); \
-    } while (0)
-
-#define fGEN_TCG_STORE_pcr(SHIFT, STORE) \
-    do { \
-        TCGv ireg = tcg_temp_new(); \
-        TCGv HALF = tcg_temp_new(); \
-        TCGv BYTE = tcg_temp_new(); \
-        tcg_gen_mov_tl(EA, RxV); \
-        gen_read_ireg(ireg, MuV, SHIFT); \
-        gen_helper_fcircadd(RxV, RxV, ireg, MuV, hex_gpr[HEX_REG_CS0 + MuN]); \
-        STORE; \
-        tcg_temp_free(ireg); \
-        tcg_temp_free(HALF); \
-        tcg_temp_free(BYTE); \
-    } while (0)
-
-#define fGEN_TCG_S2_storerb_pbr(SHORTCODE) \
-    fGEN_TCG_STORE(SHORTCODE)
-#define fGEN_TCG_S2_storerb_pci(SHORTCODE) \
-    fGEN_TCG_STORE(SHORTCODE)
-#define fGEN_TCG_S2_storerb_pcr(SHORTCODE) \
-    fGEN_TCG_STORE_pcr(0, fSTORE(1, 1, EA, fGETBYTE(0, RtV)))
-
-#define fGEN_TCG_S2_storerh_pbr(SHORTCODE) \
-    fGEN_TCG_STORE(SHORTCODE)
-#define fGEN_TCG_S2_storerh_pci(SHORTCODE) \
-    fGEN_TCG_STORE(SHORTCODE)
-#define fGEN_TCG_S2_storerh_pcr(SHORTCODE) \
-    fGEN_TCG_STORE_pcr(1, fSTORE(1, 2, EA, fGETHALF(0, RtV)))
-
-#define fGEN_TCG_S2_storerf_pbr(SHORTCODE) \
-    fGEN_TCG_STORE(SHORTCODE)
-#define fGEN_TCG_S2_storerf_pci(SHORTCODE) \
-    fGEN_TCG_STORE(SHORTCODE)
-#define fGEN_TCG_S2_storerf_pcr(SHORTCODE) \
-    fGEN_TCG_STORE_pcr(1, fSTORE(1, 2, EA, fGETHALF(1, RtV)))
-
-#define fGEN_TCG_S2_storeri_pbr(SHORTCODE) \
-    fGEN_TCG_STORE(SHORTCODE)
-#define fGEN_TCG_S2_storeri_pci(SHORTCODE) \
-    fGEN_TCG_STORE(SHORTCODE)
-#define fGEN_TCG_S2_storeri_pcr(SHORTCODE) \
-    fGEN_TCG_STORE_pcr(2, fSTORE(1, 4, EA, RtV))
-
-#define fGEN_TCG_S2_storerd_pbr(SHORTCODE) \
-    fGEN_TCG_STORE(SHORTCODE)
-#define fGEN_TCG_S2_storerd_pci(SHORTCODE) \
-    fGEN_TCG_STORE(SHORTCODE)
-#define fGEN_TCG_S2_storerd_pcr(SHORTCODE) \
-    fGEN_TCG_STORE_pcr(3, fSTORE(1, 8, EA, RttV))
-
-#define fGEN_TCG_S2_storerbnew_pbr(SHORTCODE) \
-    fGEN_TCG_STORE(SHORTCODE)
-#define fGEN_TCG_S2_storerbnew_pci(SHORTCODE) \
-    fGEN_TCG_STORE(SHORTCODE)
-#define fGEN_TCG_S2_storerbnew_pcr(SHORTCODE) \
-    fGEN_TCG_STORE_pcr(0, fSTORE(1, 1, EA, fGETBYTE(0, NtN)))
-
-#define fGEN_TCG_S2_storerhnew_pbr(SHORTCODE) \
-    fGEN_TCG_STORE(SHORTCODE)
-#define fGEN_TCG_S2_storerhnew_pci(SHORTCODE) \
-    fGEN_TCG_STORE(SHORTCODE)
-#define fGEN_TCG_S2_storerhnew_pcr(SHORTCODE) \
-    fGEN_TCG_STORE_pcr(1, fSTORE(1, 2, EA, fGETHALF(0, NtN)))
-
-#define fGEN_TCG_S2_storerinew_pbr(SHORTCODE) \
-    fGEN_TCG_STORE(SHORTCODE)
-#define fGEN_TCG_S2_storerinew_pci(SHORTCODE) \
-    fGEN_TCG_STORE(SHORTCODE)
-#define fGEN_TCG_S2_storerinew_pcr(SHORTCODE) \
-    fGEN_TCG_STORE_pcr(2, fSTORE(1, 4, EA, NtN))
-
-/*
- * Mathematical operations with more than one definition require
- * special handling
- */
-#define fGEN_TCG_A5_ACS(SHORTCODE) \
-    do { \
-        gen_helper_vacsh_pred(PeV, cpu_env, RxxV, RssV, RttV); \
-        gen_helper_vacsh_val(RxxV, cpu_env, RxxV, RssV, RttV); \
-    } while (0)
-
 /*
  * Approximate reciprocal
  * r3,p1 = sfrecipa(r0, r1)
@@ -549,70 +85,6 @@
         tcg_temp_free_i64(tmp); \
     } while (0)
 
-/*
- * Add or subtract with carry.
- * Predicate register is used as an extra input and output.
- * r5:4 = add(r1:0, r3:2, p1):carry
- */
-#define fGEN_TCG_A4_addp_c(SHORTCODE) \
-    do { \
-        TCGv_i64 carry = tcg_temp_new_i64(); \
-        TCGv_i64 zero = tcg_const_i64(0); \
-        tcg_gen_extu_i32_i64(carry, PxV); \
-        tcg_gen_andi_i64(carry, carry, 1); \
-        tcg_gen_add2_i64(RddV, carry, RssV, zero, carry, zero); \
-        tcg_gen_add2_i64(RddV, carry, RddV, carry, RttV, zero); \
-        tcg_gen_extrl_i64_i32(PxV, carry); \
-        gen_8bitsof(PxV, PxV); \
-        tcg_temp_free_i64(carry); \
-        tcg_temp_free_i64(zero); \
-    } while (0)
-
-/* r5:4 = sub(r1:0, r3:2, p1):carry */
-#define fGEN_TCG_A4_subp_c(SHORTCODE) \
-    do { \
-        TCGv_i64 carry = tcg_temp_new_i64(); \
-        TCGv_i64 zero = tcg_const_i64(0); \
-        TCGv_i64 not_RttV = tcg_temp_new_i64(); \
-        tcg_gen_extu_i32_i64(carry, PxV); \
-        tcg_gen_andi_i64(carry, carry, 1); \
-        tcg_gen_not_i64(not_RttV, RttV); \
-        tcg_gen_add2_i64(RddV, carry, RssV, zero, carry, zero); \
-        tcg_gen_add2_i64(RddV, carry, RddV, carry, not_RttV, zero); \
-        tcg_gen_extrl_i64_i32(PxV, carry); \
-        gen_8bitsof(PxV, PxV); \
-        tcg_temp_free_i64(carry); \
-        tcg_temp_free_i64(zero); \
-        tcg_temp_free_i64(not_RttV); \
-    } while (0)
-
-/*
- * Compare each of the 8 unsigned bytes
- * The minimum is placed in each byte of the destination.
- * Each bit of the predicate is set true if the bit from the first operand
- * is greater than the bit from the second operand.
- * r5:4,p1 = vminub(r1:0, r3:2)
- */
-#define fGEN_TCG_A6_vminub_RdP(SHORTCODE) \
-    do { \
-        TCGv left = tcg_temp_new(); \
-        TCGv right = tcg_temp_new(); \
-        TCGv tmp = tcg_temp_new(); \
-        tcg_gen_movi_tl(PeV, 0); \
-        tcg_gen_movi_i64(RddV, 0); \
-        for (int i = 0; i < 8; i++) { \
-            gen_get_byte_i64(left, i, RttV, false); \
-            gen_get_byte_i64(right, i, RssV, false); \
-            tcg_gen_setcond_tl(TCG_COND_GT, tmp, left, right); \
-            tcg_gen_deposit_tl(PeV, PeV, tmp, i, 1); \
-            tcg_gen_umin_tl(tmp, left, right); \
-            gen_set_byte_i64(i, RddV, tmp); \
-        } \
-        tcg_temp_free(left); \
-        tcg_temp_free(right); \
-        tcg_temp_free(tmp); \
-    } while (0)
-
 /* Floating point */
 #define fGEN_TCG_F2_conv_sf2df(SHORTCODE) \
     gen_helper_conv_sf2df(RddV, cpu_env, RsV)
diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index cf45c28f58..0e8378ac57 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -274,61 +274,6 @@ static inline void gen_write_ctrl_reg_pair(DisasContext *ctx, int reg_num,
     }
 }
 
-static TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign)
-{
-    if (sign) {
-        tcg_gen_sextract_tl(result, src, N * 8, 8);
-    } else {
-        tcg_gen_extract_tl(result, src, N * 8, 8);
-    }
-    return result;
-}
-
-static TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign)
-{
-    TCGv_i64 res64 = tcg_temp_new_i64();
-    if (sign) {
-        tcg_gen_sextract_i64(res64, src, N * 8, 8);
-    } else {
-        tcg_gen_extract_i64(res64, src, N * 8, 8);
-    }
-    tcg_gen_extrl_i64_i32(result, res64);
-    tcg_temp_free_i64(res64);
-
-    return result;
-}
-
-static inline TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign)
-{
-    if (sign) {
-        tcg_gen_sextract_tl(result, src, N * 16, 16);
-    } else {
-        tcg_gen_extract_tl(result, src, N * 16, 16);
-    }
-    return result;
-}
-
-static inline void gen_set_half(int N, TCGv result, TCGv src)
-{
-    tcg_gen_deposit_tl(result, result, src, N * 16, 16);
-}
-
-static inline void gen_set_half_i64(int N, TCGv_i64 result, TCGv src)
-{
-    TCGv_i64 src64 = tcg_temp_new_i64();
-    tcg_gen_extu_i32_i64(src64, src);
-    tcg_gen_deposit_i64(result, result, src64, N * 16, 16);
-    tcg_temp_free_i64(src64);
-}
-
-static void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src)
-{
-    TCGv_i64 src64 = tcg_temp_new_i64();
-    tcg_gen_extu_i32_i64(src64, src);
-    tcg_gen_deposit_i64(result, result, src64, N * 8, 8);
-    tcg_temp_free_i64(src64);
-}
-
 static inline void gen_load_locked4u(TCGv dest, TCGv vaddr, int mem_index)
 {
     tcg_gen_qemu_ld32u(dest, vaddr, mem_index);
@@ -417,42 +362,18 @@ void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
     gen_store32(ctx, vaddr, src, 1, slot);
 }
 
-static inline void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
-                               DisasContext *ctx, int slot)
-{
-    TCGv tmp = tcg_const_tl(src);
-    gen_store1(cpu_env, vaddr, tmp, ctx, slot);
-    tcg_temp_free(tmp);
-}
-
 void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
                 unsigned slot)
 {
     gen_store32(ctx, vaddr, src, 2, slot);
 }
 
-static inline void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
-                               DisasContext *ctx, int slot)
-{
-    TCGv tmp = tcg_const_tl(src);
-    gen_store2(cpu_env, vaddr, tmp, ctx, slot);
-    tcg_temp_free(tmp);
-}
-
 void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
                 unsigned slot)
 {
     gen_store32(ctx, vaddr, src, 4, slot);
 }
 
-static inline void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
-                               DisasContext *ctx, int slot)
-{
-    TCGv tmp = tcg_const_tl(src);
-    gen_store4(cpu_env, vaddr, tmp, ctx, slot);
-    tcg_temp_free(tmp);
-}
-
 void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src, DisasContext *ctx,
                 unsigned slot)
 {
@@ -462,25 +383,6 @@ void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src, DisasContext *ctx,
     ctx->store_width[slot] = 8;
 }
 
-static inline void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src,
-                               DisasContext *ctx, int slot)
-{
-    TCGv_i64 tmp = tcg_const_i64(src);
-    gen_store8(cpu_env, vaddr, tmp, ctx, slot);
-    tcg_temp_free_i64(tmp);
-}
-
-static TCGv gen_8bitsof(TCGv result, TCGv value)
-{
-    TCGv zero = tcg_const_tl(0);
-    TCGv ones = tcg_const_tl(0xff);
-    tcg_gen_movcond_tl(TCG_COND_NE, result, value, zero, ones, zero);
-    tcg_temp_free(zero);
-    tcg_temp_free(ones);
-
-    return result;
-}
-
 void gen_set_usr_field(int field, TCGv val)
 {
     tcg_gen_deposit_tl(hex_gpr[HEX_REG_USR], hex_gpr[HEX_REG_USR], val,
diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h
index 7d09501844..56d33dc144 100644
--- a/target/hexagon/macros.h
+++ b/target/hexagon/macros.h
@@ -67,105 +67,7 @@
                  reg_field_info[FIELD].offset, (VAL))
 #endif
 
-#ifdef QEMU_GENERATE
-/*
- * Section 5.5 of the Hexagon V67 Programmer's Reference Manual
- *
- * Slot 1 store with slot 0 load
- * A slot 1 store operation with a slot 0 load operation can appear in a packet.
- * The packet attribute :mem_noshuf inhibits the instruction reordering that
- * would otherwise be done by the assembler. For example:
- *     {
- *         memw(R5) = R2 // slot 1 store
- *         R3 = memh(R6) // slot 0 load
- *     }:mem_noshuf
- * Unlike most packetized operations, these memory operations are not executed
- * in parallel (Section 3.3.1). Instead, the store instruction in Slot 1
- * effectively executes first, followed by the load instruction in Slot 0. If
- * the addresses of the two operations are overlapping, the load will receive
- * the newly stored data. This feature is supported in processor versions
- * V65 or greater.
- *
- *
- * For qemu, we look for a load in slot 0 when there is  a store in slot 1
- * in the same packet.  When we see this, we call a helper that merges the
- * bytes from the store buffer with the value loaded from memory.
- */
-#define CHECK_NOSHUF \
-    do { \
-        if (insn->slot == 0 && pkt->pkt_has_store_s1) { \
-            process_store(ctx, pkt, 1); \
-        } \
-    } while (0)
-
-#define MEM_LOAD1s(DST, VA) \
-    do { \
-        CHECK_NOSHUF; \
-        tcg_gen_qemu_ld8s(DST, VA, ctx->mem_idx); \
-    } while (0)
-#define MEM_LOAD1u(DST, VA) \
-    do { \
-        CHECK_NOSHUF; \
-        tcg_gen_qemu_ld8u(DST, VA, ctx->mem_idx); \
-    } while (0)
-#define MEM_LOAD2s(DST, VA) \
-    do { \
-        CHECK_NOSHUF; \
-        tcg_gen_qemu_ld16s(DST, VA, ctx->mem_idx); \
-    } while (0)
-#define MEM_LOAD2u(DST, VA) \
-    do { \
-        CHECK_NOSHUF; \
-        tcg_gen_qemu_ld16u(DST, VA, ctx->mem_idx); \
-    } while (0)
-#define MEM_LOAD4s(DST, VA) \
-    do { \
-        CHECK_NOSHUF; \
-        tcg_gen_qemu_ld32s(DST, VA, ctx->mem_idx); \
-    } while (0)
-#define MEM_LOAD4u(DST, VA) \
-    do { \
-        CHECK_NOSHUF; \
-        tcg_gen_qemu_ld32s(DST, VA, ctx->mem_idx); \
-    } while (0)
-#define MEM_LOAD8u(DST, VA) \
-    do { \
-        CHECK_NOSHUF; \
-        tcg_gen_qemu_ld64(DST, VA, ctx->mem_idx); \
-    } while (0)
-
-#define MEM_STORE1_FUNC(X) \
-    __builtin_choose_expr(TYPE_INT(X), \
-        gen_store1i, \
-        __builtin_choose_expr(TYPE_TCGV(X), \
-            gen_store1, (void)0))
-#define MEM_STORE1(VA, DATA, SLOT) \
-    MEM_STORE1_FUNC(DATA)(cpu_env, VA, DATA, ctx, SLOT)
-
-#define MEM_STORE2_FUNC(X) \
-    __builtin_choose_expr(TYPE_INT(X), \
-        gen_store2i, \
-        __builtin_choose_expr(TYPE_TCGV(X), \
-            gen_store2, (void)0))
-#define MEM_STORE2(VA, DATA, SLOT) \
-    MEM_STORE2_FUNC(DATA)(cpu_env, VA, DATA, ctx, SLOT)
-
-#define MEM_STORE4_FUNC(X) \
-    __builtin_choose_expr(TYPE_INT(X), \
-        gen_store4i, \
-        __builtin_choose_expr(TYPE_TCGV(X), \
-            gen_store4, (void)0))
-#define MEM_STORE4(VA, DATA, SLOT) \
-    MEM_STORE4_FUNC(DATA)(cpu_env, VA, DATA, ctx, SLOT)
-
-#define MEM_STORE8_FUNC(X) \
-    __builtin_choose_expr(TYPE_INT(X), \
-        gen_store8i, \
-        __builtin_choose_expr(TYPE_TCGV_I64(X), \
-            gen_store8, (void)0))
-#define MEM_STORE8(VA, DATA, SLOT) \
-    MEM_STORE8_FUNC(DATA)(cpu_env, VA, DATA, ctx, SLOT)
-#else
+#ifndef QEMU_GENERATE
 #define MEM_LOAD1s(VA) ((int8_t)mem_load1(env, slot, VA))
 #define MEM_LOAD1u(VA) ((uint8_t)mem_load1(env, slot, VA))
 #define MEM_LOAD2s(VA) ((int16_t)mem_load2(env, slot, VA))
@@ -194,26 +96,6 @@ static inline void gen_cancel(unsigned slot)
 
 #define LOAD_CANCEL(EA) do { CANCEL; } while (0)
 
-#ifdef QEMU_GENERATE
-static inline void gen_pred_cancel(TCGv pred, unsigned slot_num)
- {
-    TCGv slot_mask = tcg_const_tl(1 << slot_num);
-    TCGv tmp = tcg_temp_new();
-    TCGv zero = tcg_const_tl(0);
-    TCGv one = tcg_const_tl(1);
-    tcg_gen_or_tl(slot_mask, hex_slot_cancelled, slot_mask);
-    tcg_gen_andi_tl(tmp, pred, 1);
-    tcg_gen_movcond_tl(TCG_COND_EQ, hex_slot_cancelled, tmp, zero,
-                       slot_mask, hex_slot_cancelled);
-    tcg_temp_free(slot_mask);
-    tcg_temp_free(tmp);
-    tcg_temp_free(zero);
-    tcg_temp_free(one);
-}
-#define PRED_LOAD_CANCEL(PRED, EA) \
-    gen_pred_cancel(PRED, insn->is_endloop ? 4 : insn->slot)
-#endif
-
 #define STORE_CANCEL(EA) { env->slot_cancelled |= (1 << slot); }
 
 #define fMAX(A, B) (((A) > (B)) ? (A) : (B))
@@ -241,41 +123,17 @@ static inline void gen_pred_cancel(TCGv pred, unsigned slot_num)
 
 #define f8BITSOF(VAL) ((VAL) ? 0xff : 0x00)
 
-#ifdef QEMU_GENERATE
-#define fLSBOLD(VAL) tcg_gen_andi_tl(LSB, (VAL), 1)
-#else
+#ifndef QEMU_GENERATE
 #define fLSBOLD(VAL)  ((VAL) & 1)
 #endif
 
-#ifdef QEMU_GENERATE
-#define fLSBNEW(PVAL)   tcg_gen_mov_tl(LSB, (PVAL))
-#define fLSBNEW0        tcg_gen_mov_tl(LSB, hex_new_pred_value[0])
-#define fLSBNEW1        tcg_gen_mov_tl(LSB, hex_new_pred_value[1])
-#else
+#ifndef QEMU_GENERATE
 #define fLSBNEW(PVAL)   (PVAL)
 #define fLSBNEW0        new_pred_value(env, 0)
 #define fLSBNEW1        new_pred_value(env, 1)
 #endif
 
-#ifdef QEMU_GENERATE
-static inline void gen_logical_not(TCGv dest, TCGv src)
-{
-    TCGv one = tcg_const_tl(1);
-    TCGv zero = tcg_const_tl(0);
-
-    tcg_gen_movcond_tl(TCG_COND_NE, dest, src, zero, zero, one);
-
-    tcg_temp_free(one);
-    tcg_temp_free(zero);
-}
-#define fLSBOLDNOT(VAL) \
-    do { \
-        tcg_gen_andi_tl(LSB, (VAL), 1); \
-        tcg_gen_xori_tl(LSB, LSB, 1); \
-    } while (0)
-#define fLSBNEWNOT(PNUM) \
-    gen_logical_not(LSB, (PNUM))
-#else
+#ifndef QEMU_GENERATE
 #define fLSBNEWNOT(PNUM) (!fLSBNEW(PNUM))
 #define fLSBOLDNOT(VAL) (!fLSBOLD(VAL))
 #define fLSBNEW0NOT (!fLSBNEW0)
@@ -481,21 +339,7 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift)
 #define fCAST8S_16S(A) (int128_exts64(A))
 #define fCAST16S_8S(A) (int128_getlo(A))
 
-#ifdef QEMU_GENERATE
-#define fEA_RI(REG, IMM) tcg_gen_addi_tl(EA, REG, IMM)
-#define fEA_RRs(REG, REG2, SCALE) \
-    do { \
-        TCGv tmp = tcg_temp_new(); \
-        tcg_gen_shli_tl(tmp, REG2, SCALE); \
-        tcg_gen_add_tl(EA, REG, tmp); \
-        tcg_temp_free(tmp); \
-    } while (0)
-#define fEA_IRs(IMM, REG, SCALE) \
-    do { \
-        tcg_gen_shli_tl(EA, REG, SCALE); \
-        tcg_gen_addi_tl(EA, EA, IMM); \
-    } while (0)
-#else
+#ifndef QEMU_GENERATE
 #define fEA_RI(REG, IMM) \
     do { \
         EA = REG + IMM; \
@@ -511,18 +355,7 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift)
 #endif
 
 #ifdef QEMU_GENERATE
-#define fEA_IMM(IMM) tcg_gen_movi_tl(EA, IMM)
 #define fEA_REG(REG) tcg_gen_mov_tl(EA, REG)
-#define fEA_BREVR(REG)      gen_helper_fbrev(EA, REG)
-#define fPM_I(REG, IMM)     tcg_gen_addi_tl(REG, REG, IMM)
-#define fPM_M(REG, MVAL)    tcg_gen_add_tl(REG, REG, MVAL)
-#define fPM_CIRI(REG, IMM, MVAL) \
-    do { \
-        TCGv tcgv_siV = tcg_const_tl(siV); \
-        gen_helper_fcircadd(REG, REG, tcgv_siV, MuV, \
-                            hex_gpr[HEX_REG_CS0 + MuN]); \
-        tcg_temp_free(tcgv_siV); \
-    } while (0)
 #else
 #define fEA_IMM(IMM)        do { EA = (IMM); } while (0)
 #define fEA_REG(REG)        do { EA = (REG); } while (0)
@@ -574,9 +407,7 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift)
 #define fASHIFTL(SRC, SHAMT, REGSTYPE) \
     (((SHAMT) >= (sizeof(SRC) * 8)) ? 0 : (fCAST##REGSTYPE##s(SRC) << (SHAMT)))
 
-#ifdef QEMU_GENERATE
-#define fLOAD(NUM, SIZE, SIGN, EA, DST) MEM_LOAD##SIZE##SIGN(DST, EA)
-#else
+#ifndef QEMU_GENERATE
 #define fLOAD(NUM, SIZE, SIGN, EA, DST) \
     DST = (size##SIZE##SIGN##_t)MEM_LOAD##SIZE##SIGN(EA)
 #endif
@@ -599,9 +430,7 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift)
     gen_load_locked##SIZE##SIGN(DST, EA, ctx->mem_idx);
 #endif
 
-#ifdef QEMU_GENERATE
-#define fSTORE(NUM, SIZE, EA, SRC) MEM_STORE##SIZE(EA, SRC, insn->slot)
-#else
+#ifndef QEMU_GENERATE
 #define fSTORE(NUM, SIZE, EA, SRC) MEM_STORE##SIZE(EA, SRC, slot)
 #endif
 
@@ -610,15 +439,7 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift)
     gen_store_conditional##SIZE(env, ctx, PdN, PRED, EA, SRC);
 #endif
 
-#ifdef QEMU_GENERATE
-#define GETBYTE_FUNC(X) \
-    __builtin_choose_expr(TYPE_TCGV(X), \
-        gen_get_byte, \
-        __builtin_choose_expr(TYPE_TCGV_I64(X), \
-            gen_get_byte_i64, (void)0))
-#define fGETBYTE(N, SRC) GETBYTE_FUNC(SRC)(BYTE, N, SRC, true)
-#define fGETUBYTE(N, SRC) GETBYTE_FUNC(SRC)(BYTE, N, SRC, false)
-#else
+#ifndef QEMU_GENERATE
 #define fGETBYTE(N, SRC) ((int8_t)((SRC >> ((N) * 8)) & 0xff))
 #define fGETUBYTE(N, SRC) ((uint8_t)((SRC >> ((N) * 8)) & 0xff))
 #endif
@@ -629,10 +450,7 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift)
         (((uint64_t)((VAL) & 0x0ffLL)) << ((N) * 8)); \
     } while (0)
 
-#ifdef QEMU_GENERATE
-#define fGETHALF(N, SRC)  gen_get_half(HALF, N, SRC, true)
-#define fGETUHALF(N, SRC) gen_get_half(HALF, N, SRC, false)
-#else
+#ifndef QEMU_GENERATE
 #define fGETHALF(N, SRC) ((int16_t)((SRC >> ((N) * 16)) & 0xffff))
 #define fGETUHALF(N, SRC) ((uint16_t)((SRC >> ((N) * 16)) & 0xffff))
 #endif
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 63dd685658..496975a394 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -45,23 +45,6 @@ void QEMU_NORETURN HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp)
     do_raise_exception_err(env, excp, 0);
 }
 
-static void log_reg_write(CPUHexagonState *env, int rnum,
-                          target_ulong val, uint32_t slot)
-{
-    HEX_DEBUG_LOG("log_reg_write[%d] = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")",
-                  rnum, val, val);
-    if (val == env->gpr[rnum]) {
-        HEX_DEBUG_LOG(" NO CHANGE");
-    }
-    HEX_DEBUG_LOG("\n");
-
-    env->new_value[rnum] = val;
-    if (HEX_DEBUG) {
-        /* Do this so HELPER(debug_commit_end) will know */
-        env->reg_written[rnum] = 1;
-    }
-}
-
 static void log_pred_write(CPUHexagonState *env, int pnum, target_ulong val)
 {
     HEX_DEBUG_LOG("log_pred_write[%d] = " TARGET_FMT_ld
@@ -77,46 +60,6 @@ static void log_pred_write(CPUHexagonState *env, int pnum, target_ulong val)
     }
 }
 
-static void log_store32(CPUHexagonState *env, target_ulong addr,
-                        target_ulong val, int width, int slot)
-{
-    HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
-                  ", %" PRId32 " [0x08%" PRIx32 "])\n",
-                  width, addr, val, val);
-    env->mem_log_stores[slot].va = addr;
-    env->mem_log_stores[slot].width = width;
-    env->mem_log_stores[slot].data32 = val;
-}
-
-static void log_store64(CPUHexagonState *env, target_ulong addr,
-                        int64_t val, int width, int slot)
-{
-    HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
-                  ", %" PRId64 " [0x016%" PRIx64 "])\n",
-                   width, addr, val, val);
-    env->mem_log_stores[slot].va = addr;
-    env->mem_log_stores[slot].width = width;
-    env->mem_log_stores[slot].data64 = val;
-}
-
-static void write_new_pc(CPUHexagonState *env, target_ulong addr)
-{
-    HEX_DEBUG_LOG("write_new_pc(0x" TARGET_FMT_lx ")\n", addr);
-
-    /*
-     * If more than one branch is taken in a packet, only the first one
-     * is actually done.
-     */
-    if (env->branch_taken) {
-        HEX_DEBUG_LOG("INFO: multiple branches taken in same packet, "
-                      "ignoring the second one\n");
-    } else {
-        fCHECK_PCALIGN(addr);
-        env->branch_taken = 1;
-        env->next_PC = addr;
-    }
-}
-
 /* Handy place to set a breakpoint */
 void HELPER(debug_start_packet)(CPUHexagonState *env)
 {
@@ -128,11 +71,6 @@ void HELPER(debug_start_packet)(CPUHexagonState *env)
     }
 }
 
-static int32_t new_pred_value(CPUHexagonState *env, int pnum)
-{
-    return env->new_pred_value[pnum];
-}
-
 /* Checks for bookkeeping errors between disassembly context and runtime */
 void HELPER(debug_check_store_width)(CPUHexagonState *env, int slot, int check)
 {
@@ -380,57 +318,6 @@ int32_t HELPER(vacsh_pred)(CPUHexagonState *env,
     return PeV;
 }
 
-/*
- * mem_noshuf
- * Section 5.5 of the Hexagon V67 Programmer's Reference Manual
- *
- * If the load is in slot 0 and there is a store in slot1 (that
- * wasn't cancelled), we have to do the store first.
- */
-static void check_noshuf(CPUHexagonState *env, uint32_t slot)
-{
-    if (slot == 0 && env->pkt_has_store_s1 &&
-        ((env->slot_cancelled & (1 << 1)) == 0)) {
-        HELPER(commit_store)(env, 1);
-    }
-}
-
-static uint8_t mem_load1(CPUHexagonState *env, uint32_t slot,
-                         target_ulong vaddr)
-{
-    uint8_t retval;
-    check_noshuf(env, slot);
-    get_user_u8(retval, vaddr);
-    return retval;
-}
-
-static uint16_t mem_load2(CPUHexagonState *env, uint32_t slot,
-                          target_ulong vaddr)
-{
-    uint16_t retval;
-    check_noshuf(env, slot);
-    get_user_u16(retval, vaddr);
-    return retval;
-}
-
-static uint32_t mem_load4(CPUHexagonState *env, uint32_t slot,
-                          target_ulong vaddr)
-{
-    uint32_t retval;
-    check_noshuf(env, slot);
-    get_user_u32(retval, vaddr);
-    return retval;
-}
-
-static uint64_t mem_load8(CPUHexagonState *env, uint32_t slot,
-                          target_ulong vaddr)
-{
-    uint64_t retval;
-    check_noshuf(env, slot);
-    get_user_u64(retval, vaddr);
-    return retval;
-}
-
 /* Floating point */
 float64 HELPER(conv_sf2df)(CPUHexagonState *env, float32 RsV)
 {
@@ -1172,12 +1059,6 @@ float64 HELPER(dfmpyhh)(CPUHexagonState *env, float64 RxxV,
     return RxxV;
 }
 
-static void cancel_slot(CPUHexagonState *env, uint32_t slot)
-{
-    HEX_DEBUG_LOG("Slot %d cancelled\n", slot);
-    env->slot_cancelled |= (1 << slot);
-}
-
 /* These macros can be referenced in the generated helper functions */
 #define warn(...) /* Nothing */
 #define fatal(...) g_assert_not_reached();
-- 
2.31.1



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

* [PATCH v5 13/14] target/hexagon: import additional tests
  2021-06-19  9:36 [PATCH v5 00/14] target/hexagon: introduce idef-parser Alessandro Di Federico via
                   ` (11 preceding siblings ...)
  2021-06-19  9:37 ` [PATCH v5 12/14] target/hexagon: remove unused macros and functions Alessandro Di Federico via
@ 2021-06-19  9:37 ` Alessandro Di Federico via
  2021-06-25 23:56   ` Taylor Simpson
  2021-06-19  9:37 ` [PATCH v5 14/14] gitlab-ci: do not use qemu-project Docker registry Alessandro Di Federico via
  13 siblings, 1 reply; 38+ messages in thread
From: Alessandro Di Federico via @ 2021-06-19  9:37 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  | 36 ++++++++++++++++-
 tests/tcg/hexagon/crt.S            | 28 +++++++++++++
 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_overflow.S  | 63 ++++++++++++++++++++++++++++++
 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, 1103 insertions(+), 1 deletion(-)
 create mode 100644 tests/tcg/hexagon/crt.S
 create mode 100644 tests/tcg/hexagon/test_abs.S
 create mode 100644 tests/tcg/hexagon/test_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_overflow.S
 create mode 100644 tests/tcg/hexagon/test_packet.S
 create mode 100644 tests/tcg/hexagon/test_reorder.S
 create mode 100644 tests/tcg/hexagon/test_round.S
 create mode 100644 tests/tcg/hexagon/test_vavgw.S
 create mode 100644 tests/tcg/hexagon/test_vcmpb.S
 create mode 100644 tests/tcg/hexagon/test_vcmpw.S
 create mode 100644 tests/tcg/hexagon/test_vcmpy.S
 create mode 100644 tests/tcg/hexagon/test_vlsrw.S
 create mode 100644 tests/tcg/hexagon/test_vmaxh.S
 create mode 100644 tests/tcg/hexagon/test_vminh.S
 create mode 100644 tests/tcg/hexagon/test_vpmpyh.S
 create mode 100644 tests/tcg/hexagon/test_vspliceb.S

diff --git a/tests/tcg/hexagon/Makefile.target b/tests/tcg/hexagon/Makefile.target
index 0992787d50..8f3827016c 100644
--- a/tests/tcg/hexagon/Makefile.target
+++ b/tests/tcg/hexagon/Makefile.target
@@ -33,7 +33,7 @@ CFLAGS += -fno-unroll-loops
 HEX_SRC=$(SRC_PATH)/tests/tcg/hexagon
 VPATH += $(HEX_SRC)
 
-first: $(HEX_SRC)/first.S
+%: $(HEX_SRC)/%.S $(HEX_SRC)/crt.S
 	$(CC) -static -mv67 -nostdlib $^ -o $@
 
 HEX_TESTS = first
@@ -49,4 +49,38 @@ HEX_TESTS += load_align
 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_overflow
+HEX_TESTS += test_packet
+HEX_TESTS += test_reorder
+HEX_TESTS += test_round
+HEX_TESTS += test_vavgw
+HEX_TESTS += test_vcmpb
+HEX_TESTS += test_vcmpw
+HEX_TESTS += test_vcmpy
+HEX_TESTS += test_vlsrw
+HEX_TESTS += test_vmaxh
+HEX_TESTS += test_vminh
+HEX_TESTS += test_vpmpyh
+HEX_TESTS += test_vspliceb
+
 TESTS += $(HEX_TESTS)
diff --git a/tests/tcg/hexagon/crt.S b/tests/tcg/hexagon/crt.S
new file mode 100644
index 0000000000..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/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_overflow.S b/tests/tcg/hexagon/test_overflow.S
new file mode 100644
index 0000000000..9e2a235616
--- /dev/null
+++ b/tests/tcg/hexagon/test_overflow.S
@@ -0,0 +1,63 @@
+// Purpose: test example, verify the soundness of the overflow bit
+//
+// a right shift with negative amount should make r0 saturate, setting the
+// overflow bit
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r0=#0x10000000
+        r1=#-2
+    }
+    {
+        r2=asr(r0, r1):sat
+    }
+    {
+        r4=USR
+    }
+    {
+        r5=and(r4,#1)
+    }
+    {
+        p0 = cmp.eq(r5, #0); if (p0.new) jump:t check_ovfl
+        jump fail
+    }
+check_ovfl:
+    {
+        r1=#-3
+    }
+    {
+        r2=asr(r0, r1):sat
+    }
+    {
+        r4=USR
+    }
+    {
+        r5=and(r4,#1)
+    }
+    {
+        p0 = cmp.eq(r5, #1); if (p0.new) jump:t check_sticky
+        jump fail
+    }
+check_sticky:
+    {
+        r1=#-2
+    }
+    {
+        r2=asr(r0, r1):sat
+    }
+    {
+        r4=USR
+    }
+    {
+        r5=and(r4,#1)
+    }
+    {
+        p0 = cmp.eq(r5, #1); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_packet.S b/tests/tcg/hexagon/test_packet.S
new file mode 100644
index 0000000000..d26e284be9
--- /dev/null
+++ b/tests/tcg/hexagon/test_packet.S
@@ -0,0 +1,26 @@
+/* Purpose: test that writes of a register in a packet are performed only after
+ * that packet has finished its execution.
+ */
+
+    .text
+    .globl _start
+
+_start:
+    {
+        call init
+    }
+    {
+        r2=#4
+        r3=#6
+    }
+    {
+        memw(sp+#0)=r2
+    }
+    {
+        r3=memw(sp+#0)
+        r0=add(r2,r3)
+    }
+    {
+        p0 = cmp.eq(r0, #10); if (p0.new) jump:t pass
+        jump fail
+    }
diff --git a/tests/tcg/hexagon/test_reorder.S b/tests/tcg/hexagon/test_reorder.S
new file mode 100644
index 0000000000..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.31.1



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

* [PATCH v5 14/14] gitlab-ci: do not use qemu-project Docker registry
  2021-06-19  9:36 [PATCH v5 00/14] target/hexagon: introduce idef-parser Alessandro Di Federico via
                   ` (12 preceding siblings ...)
  2021-06-19  9:37 ` [PATCH v5 13/14] target/hexagon: import additional tests Alessandro Di Federico via
@ 2021-06-19  9:37 ` Alessandro Di Federico via
  2021-06-29 14:26   ` Alessandro Di Federico via
  2021-06-29 14:37   ` Daniel P. Berrangé
  13 siblings, 2 replies; 38+ messages in thread
From: Alessandro Di Federico via @ 2021-06-19  9:37 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 commit is necessary in order to use container built by the current
run of the CI. If we don't do this, we use official containers which are
not affected by the additional dependencies we're introducing.

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

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



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

* Re: [PATCH v5 01/14] tcg: expose TCGCond manipulation routines
  2021-06-19  9:37 ` [PATCH v5 01/14] tcg: expose TCGCond manipulation routines Alessandro Di Federico via
@ 2021-06-19 13:51   ` Richard Henderson
  0 siblings, 0 replies; 38+ messages in thread
From: Richard Henderson @ 2021-06-19 13:51 UTC (permalink / raw)
  To: Alessandro Di Federico, qemu-devel
  Cc: Alessandro Di Federico, bcain, babush, tsimpson, nizzo, philmd

On 6/19/21 2:37 AM, Alessandro Di Federico wrote:
> From: Alessandro Di Federico<ale@rev.ng>
> 
> This commit moves into a separate file routines used to manipulate
> TCGCond. These will be employed by the idef-parser.
> 
> Signed-off-by: Alessandro Di Federico<ale@rev.ng>
> Signed-off-by: Paolo Montesel<babush@rev.ng>
> ---
>   include/tcg/tcg-cond.h | 101 +++++++++++++++++++++++++++++++++++++++++
>   include/tcg/tcg.h      |  70 +---------------------------
>   2 files changed, 102 insertions(+), 69 deletions(-)
>   create mode 100644 include/tcg/tcg-cond.h

Thanks, queued to tcg-next.


r~


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

* RE: [PATCH v5 10/14] target/hexagon: import parser for idef-parser
  2021-06-19  9:37 ` [PATCH v5 10/14] target/hexagon: import parser " Alessandro Di Federico via
@ 2021-06-22 22:35   ` Taylor Simpson
  2021-06-24  3:55   ` Taylor Simpson
  1 sibling, 0 replies; 38+ messages in thread
From: Taylor Simpson @ 2021-06-22 22:35 UTC (permalink / raw)
  To: Alessandro Di Federico, qemu-devel
  Cc: Alessandro Di Federico, Brian Cain, richard.henderson, babush,
	nizzo, philmd



> -----Original Message-----
> From: Alessandro Di Federico <ale.qemu@rev.ng>
> Sent: Saturday, June 19, 2021 3:37 AM
> To: qemu-devel@nongnu.org
> Cc: Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; babush@rev.ng; nizzo@rev.ng; philmd@redhat.com;
> richard.henderson@linaro.org; Alessandro Di Federico <ale@rev.ng>
> Subject: [PATCH v5 10/14] target/hexagon: import parser for idef-parser
> 
> From: Paolo Montesel <babush@rev.ng>
> 
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Paolo Montesel <babush@rev.ng>
> ---
> diff --git a/target/hexagon/idef-parser/parser-helpers.h
> b/target/hexagon/idef-parser/parser-helpers.h
> new file mode 100644
> index 0000000000..fec3ad7819
> --- /dev/null
> +++ b/target/hexagon/idef-parser/parser-helpers.h
> @@ -0,0 +1,347 @@
> +
> +#define OUT_IMPL(c, locp, x)                    \
> +    QEMU_GENERIC(typeof(*x),                \
> +        (char,      str_print),             \
> +        (uint64_t,  uint64_print),          \
> +        (int,       int_print),             \
> +        (unsigned,  uint_print),            \
> +        (HexValue,  rvalue_out),            \
> +        out_assert                          \
> +    )(c, locp, x);                          \
> +

QEMU_GENERIC has been removed

commit de51d8cbf0f9a9745ac02fb07e02063b7dfe35b9
Author: Richard Henderson <richard.henderson@linaro.org>
Date:   Mon Jun 14 16:31:42 2021 -0700

    qemu/compiler: Remove QEMU_GENERIC
    
    All previous users now use C11 _Generic.
    
    Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
    Reviewed-by: Alex Benn<C3><A9>e <alex.bennee@linaro.org>
    Message-Id: <20210614233143.1221879-8-richard.henderson@linaro.org>
    Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

You can now write this as

#define OUT_IMPL(c, locp, x)              \
    _Generic(*x,                          \
        char:      str_print,             \
        uint64_t:  uint64_print,          \
        int:       int_print,             \
        unsigned:  uint_print,            \
        HexValue:  rvalue_out,            \
        default: out_assert               \
    )(c, locp, x);


Thanks,
Taylor




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

* RE: [PATCH v5 06/14] target/hexagon: introduce new helper functions
  2021-06-19  9:37 ` [PATCH v5 06/14] target/hexagon: introduce new helper functions Alessandro Di Federico via
@ 2021-06-23 12:05   ` Taylor Simpson
  2021-06-23 18:49   ` Taylor Simpson
  1 sibling, 0 replies; 38+ messages in thread
From: Taylor Simpson @ 2021-06-23 12:05 UTC (permalink / raw)
  To: Alessandro Di Federico, qemu-devel
  Cc: Alessandro Di Federico, Brian Cain, richard.henderson, babush,
	nizzo, philmd



> -----Original Message-----
> From: Alessandro Di Federico <ale.qemu@rev.ng>
> Sent: Saturday, June 19, 2021 3:37 AM
> To: qemu-devel@nongnu.org
> Cc: Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; babush@rev.ng; nizzo@rev.ng; philmd@redhat.com;
> richard.henderson@linaro.org; Alessandro Di Federico <ale@rev.ng>
> Subject: [PATCH v5 06/14] target/hexagon: introduce new helper functions
> 
> 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 | 163
> ++++++++++++++++++++++++++++++++++++----
>  target/hexagon/genptr.h |  23 ++++++
>  target/hexagon/macros.h |   9 +++
>  3 files changed, 180 insertions(+), 15 deletions(-)
> 
> diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index
> 6f2816f6e2..cf45c28f58 100644
> --- a/target/hexagon/genptr.c


> +++ b/target/hexagon/genptr.c
> +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_deposit_tl(result, src, lo, 0, 16);
> +    tcg_gen_or_tl(result, result, lo);
> +
> +    tcg_temp_free(lo);
> +    tcg_temp_free(tmp1);
> +    tcg_temp_free(tmp2);
> +}

Remove this function and call gen_helper_fbrev instead.  This was feedback from Richard Henderson on one of my previous patch series.

Thanks,
Taylor

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

* RE: [PATCH v5 03/14] target/hexagon: import README for idef-parser
  2021-06-19  9:37 ` [PATCH v5 03/14] target/hexagon: import README " Alessandro Di Federico via
@ 2021-06-23 15:46   ` Taylor Simpson
  2021-06-24 13:51     ` Alessandro Di Federico via
  0 siblings, 1 reply; 38+ messages in thread
From: Taylor Simpson @ 2021-06-23 15:46 UTC (permalink / raw)
  To: Alessandro Di Federico, qemu-devel
  Cc: Alessandro Di Federico, Brian Cain, richard.henderson, babush,
	nizzo, philmd



> -----Original Message-----
> From: Alessandro Di Federico <ale.qemu@rev.ng>
> Sent: Saturday, June 19, 2021 3:37 AM
> To: qemu-devel@nongnu.org
> Cc: Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; babush@rev.ng; nizzo@rev.ng; philmd@redhat.com;
> richard.henderson@linaro.org; Alessandro Di Federico <ale@rev.ng>
> Subject: [PATCH v5 03/14] target/hexagon: import README for idef-parser
> 
> 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
> @@ -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

The output file is actually named idef_parser_input.h.inc


> a/target/hexagon/idef-parser/README.rst b/target/hexagon/idef-
> parser/README.rst
> new file mode 100644
> index 0000000000..f4cb416e8b
> --- /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 isn't actually indented, but it would be great if it were.  This is especially true for instructions where an "if" or "for" show up in the emitted code.

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

Is there a way to force the parser not to emit a particular instruction (i.e., fall back on the reference implementation)?



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

* RE: [PATCH v5 04/14] target/hexagon: make slot number an unsigned
  2021-06-19  9:37 ` [PATCH v5 04/14] target/hexagon: make slot number an unsigned Alessandro Di Federico via
@ 2021-06-23 15:58   ` Taylor Simpson
  0 siblings, 0 replies; 38+ messages in thread
From: Taylor Simpson @ 2021-06-23 15:58 UTC (permalink / raw)
  To: Alessandro Di Federico, qemu-devel
  Cc: Alessandro Di Federico, Brian Cain, richard.henderson, babush,
	nizzo, philmd



> -----Original Message-----
> From: Alessandro Di Federico <ale.qemu@rev.ng>
> Sent: Saturday, June 19, 2021 3:37 AM
> To: qemu-devel@nongnu.org
> Cc: Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; babush@rev.ng; nizzo@rev.ng; philmd@redhat.com;
> richard.henderson@linaro.org; Alessandro Di Federico <ale@rev.ng>
> Subject: [PATCH v5 04/14] target/hexagon: make slot number an unsigned

I'm curious why this is needed.  Is there a bug caused by having it be signed?

> 
> From: Paolo Montesel <babush@rev.ng>
> 
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Paolo Montesel <babush@rev.ng>
> Acked-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  target/hexagon/genptr.c | 6 ++++--
>  target/hexagon/macros.h | 2 +-

Run the following in your git repo so the .h files will appear first in the patch.
    git config diff.orderFile scripts/git.orderfile
This makes it easier for the community to review


>  2 files changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index
> 797a6c0cc9..3b8013d4e2 100644
> --- a/target/hexagon/genptr.c
> +++ b/target/hexagon/genptr.c
> @@ -33,7 +33,8 @@ static inline 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)

Let's use uint32_t to match insn->slot that is passed to these functions.




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

* Re: [PATCH v5 05/14] target/hexagon: make helper functions non-static
  2021-06-19  9:37 ` [PATCH v5 05/14] target/hexagon: make helper functions non-static Alessandro Di Federico via
@ 2021-06-23 18:29   ` Taylor Simpson
  0 siblings, 0 replies; 38+ messages in thread
From: Taylor Simpson @ 2021-06-23 18:29 UTC (permalink / raw)
  To: Alessandro Di Federico
  Cc: Alessandro Di Federico, bcain, richard.henderson, qemu-devel,
	babush, tsimpson, nizzo, philmd

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

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

On Sat, Jun 19, 2021 at 4:44 AM Alessandro Di Federico via <
qemu-devel@nongnu.org> 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>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  target/hexagon/genptr.c | 7 ++++---
>  target/hexagon/genptr.h | 6 ++++++
>  2 files changed, 10 insertions(+), 3 deletions(-)
>
>
>
>

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

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

* RE: [PATCH v5 06/14] target/hexagon: introduce new helper functions
  2021-06-19  9:37 ` [PATCH v5 06/14] target/hexagon: introduce new helper functions Alessandro Di Federico via
  2021-06-23 12:05   ` Taylor Simpson
@ 2021-06-23 18:49   ` Taylor Simpson
  1 sibling, 0 replies; 38+ messages in thread
From: Taylor Simpson @ 2021-06-23 18:49 UTC (permalink / raw)
  To: Alessandro Di Federico, qemu-devel
  Cc: Alessandro Di Federico, Brian Cain, richard.henderson, babush,
	nizzo, philmd



> -----Original Message-----
> From: Alessandro Di Federico <ale.qemu@rev.ng>
> Sent: Saturday, June 19, 2021 3:37 AM
> To: qemu-devel@nongnu.org
> Cc: Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; babush@rev.ng; nizzo@rev.ng; philmd@redhat.com;
> richard.henderson@linaro.org; Alessandro Di Federico <ale@rev.ng>
> Subject: [PATCH v5 06/14] target/hexagon: introduce new helper functions
> 
> 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 | 163
> ++++++++++++++++++++++++++++++++++++----
>  target/hexagon/genptr.h |  23 ++++++
>  target/hexagon/macros.h |   9 +++
>  3 files changed, 180 insertions(+), 15 deletions(-)
> 
> diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index
> 6f2816f6e2..cf45c28f58 100644
> --- a/target/hexagon/genptr.c
> +++ b/target/hexagon/genptr.c
> @@ -28,6 +28,12 @@
>  #include "gen_tcg.h"
>  #include "genptr.h"
> 
> +TCGv gen_read_reg(TCGv result, int num) {
> +    tcg_gen_mov_tl(result, hex_gpr[num]);
> +    return result;
> +}
> +
>  TCGv gen_read_preg(TCGv pred, uint8_t num)  {
>      tcg_gen_mov_tl(pred, hex_pred[num]); @@ -396,18 +402,19 @@ static
> inline void gen_store_conditional8(CPUHexagonState *env,
>      tcg_gen_movi_tl(hex_llsc_addr, ~0);  }
> 
> -static inline void gen_store32(TCGv vaddr, TCGv src, int width, int slot)
> +void gen_store32(DisasContext *ctx, TCGv vaddr, TCGv src, tcg_target_long
> width,
> +                 unsigned slot)

uint32_t

>  {
>      tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
>      tcg_gen_movi_tl(hex_store_width[slot], width);
>      tcg_gen_mov_tl(hex_store_val32[slot], src);
> +    ctx->store_width[slot] = width;
>  }
> 
> -static inline void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src,
> -                              DisasContext *ctx, int slot)
> +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;
> +    gen_store32(ctx, vaddr, src, 1, slot);
>  }
> 
>  static inline void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
> @@ -418,11 +425,10 @@ static inline void gen_store1i(TCGv_env cpu_env,
> TCGv vaddr, int32_t src,
>      tcg_temp_free(tmp);
>  }
> 
> -static inline void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src,
> -                              DisasContext *ctx, int slot)
> +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;
> +    gen_store32(ctx, vaddr, src, 2, slot);
>  }
> 
>  static inline void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
> @@ -433,11 +439,10 @@ static inline void gen_store2i(TCGv_env cpu_env,
> TCGv vaddr, int32_t src,
>      tcg_temp_free(tmp);
>  }
> 
> -static inline void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src,
> -                              DisasContext *ctx, int slot)
> +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;
> +    gen_store32(ctx, vaddr, src, 4, slot);
>  }
> 
>  static inline void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
> @@ -448,8 +453,8 @@ static inline void gen_store4i(TCGv_env cpu_env,
> TCGv vaddr, int32_t src,
>      tcg_temp_free(tmp);
>  }
> 
> -static inline void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src,
> -                              DisasContext *ctx, int slot)
> +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); @@ -476,5 +481,133 @@
> static TCGv gen_8bitsof(TCGv result, TCGv value)
>      return result;
>  }
> 
> +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) {
> +    TCGv max_val = tcg_const_i32((1 << (width - 1)) - 1);
> +    TCGv min_val = tcg_const_i32(-(1 << (width - 1)));

Use _tl suffix, not _i32.

> +    tcg_gen_smin_tl(dest, source, max_val);
> +    tcg_gen_smax_tl(dest, dest, min_val);
> +    tcg_temp_free_i32(max_val);
> +    tcg_temp_free_i32(min_val);

Ditto

> +}
> +
> +void gen_sat_i32_ext(TCGv ovfl, TCGv dest, TCGv source, int width) {

gen_set_i32_ovfl would be a better name - ditto for the other _ext flavors later in this file

> +    gen_sat_i32(dest, source, width);
> +    tcg_gen_setcond_i32(TCG_COND_NE, ovfl, source, dest); }
> +
> +void gen_satu_i32(TCGv dest, TCGv source, int width) {
> +    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);
> +    tcg_temp_free_i32(max_val);
> +    tcg_temp_free_i32(zero);

_tl instead of _i32 for all of the above

For Hexagon, use _tl for all 32 bit operations.

> +}
> +
> +void gen_satu_i32_ext(TCGv ovfl, TCGv dest, TCGv source, int width) {
> +    gen_satu_i32(dest, source, width);
> +    tcg_gen_setcond_i32(TCG_COND_NE, ovfl, source, dest); }
> +
> +void gen_sat_i64(TCGv_i64 dest, TCGv_i64 source, int width) {
> +    TCGv_i64 max_val = tcg_const_i64((1 << (width - 1)) - 1);
> +    TCGv_i64 min_val = tcg_const_i64(-(1 << (width - 1)));
> +    tcg_gen_smin_i64(dest, source, max_val);
> +    tcg_gen_smax_i64(dest, dest, min_val);
> +    tcg_temp_free_i64(max_val);
> +    tcg_temp_free_i64(min_val);
> +}
> +
> +void gen_sat_i64_ext(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int
> +width) {
> +    gen_sat_i64(dest, source, width);
> +    TCGv_i64 ovfl_64 = tcg_temp_new_i64();
> +    tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, dest, source);
> +    tcg_gen_trunc_i64_tl(ovfl, ovfl_64);
> +    tcg_temp_free_i64(ovfl_64);
> +}
> +
> +void gen_satu_i64(TCGv_i64 dest, TCGv_i64 source, int width) {
> +    TCGv_i64 max_val = tcg_const_i64((1 << width) - 1);
> +    tcg_gen_movcond_i64(TCG_COND_GTU, dest, source, max_val,
> max_val, source);
> +    TCGv_i64 zero = tcg_const_i64(0);
> +    tcg_gen_movcond_i64(TCG_COND_LT, dest, source, zero, zero, dest);
> +    tcg_temp_free_i64(max_val);
> +    tcg_temp_free_i64(zero);
> +}
> +
> +void gen_satu_i64_ext(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int
> +width) {
> +    gen_sat_i64(dest, source, width);
> +    TCGv_i64 ovfl_64 = tcg_temp_new_i64();
> +    tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, dest, source);
> +    tcg_gen_trunc_i64_tl(ovfl, ovfl_64);
> +    tcg_temp_free_i64(ovfl_64);
> +}
> +
> +void gen_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_deposit_tl(result, src, lo, 0, 16);
> +    tcg_gen_or_tl(result, result, lo);
> +
> +    tcg_temp_free(lo);
> +    tcg_temp_free(tmp1);
> +    tcg_temp_free(tmp2);
> +}
> +

Use gen_helper_fbrev instead of this one.

>  #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
> 709b8eb099..48d1a32f49 100644
> --- a/target/hexagon/genptr.h
> +++ b/target/hexagon/genptr.h
> @@ -24,8 +24,31 @@
> 
>  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(DisasContext *ctx, int pnum,
> TCGv val);
> +void gen_store32(DisasContext *ctx, 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_write_new_pc(TCGv addr);
> +void gen_set_usr_field(int field, TCGv val); void
> +gen_set_usr_fieldi(int field, int x); void gen_sat_i32(TCGv dest, TCGv
> +source, int width); void gen_sat_i32_ext(TCGv ovfl, TCGv dest, TCGv
> +source, int width); void gen_satu_i32(TCGv dest, TCGv source, int
> +width); void gen_satu_i32_ext(TCGv ovfl, TCGv dest, TCGv source, int
> +width); void gen_sat_i64(TCGv_i64 dest, TCGv_i64 source, int width);
> +void gen_sat_i64_ext(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int
> +width); void gen_satu_i64(TCGv_i64 dest, TCGv_i64 source, int width);
> +void gen_satu_i64_ext(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int
> +width); void gen_fbrev(TCGv result, TCGv src);
> 
>  #endif
> diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h index
> eadb7e5d05..7d09501844 100644
> --- a/target/hexagon/macros.h
> +++ b/target/hexagon/macros.h
> @@ -181,7 +181,16 @@
>  #define MEM_STORE8(VA, DATA, SLOT) log_store64(env, VA, DATA, 8,
> SLOT)  #endif
> 
> +#ifdef QEMU_GENERATE
> +static inline void gen_cancel(unsigned slot) {

uint32_t

> +    tcg_gen_ori_tl(hex_slot_cancelled, hex_slot_cancelled, 1 << slot);
> +}
> +
> +#define CANCEL gen_cancel(slot);
> +#else
>  #define CANCEL cancel_slot(env, slot)
> +#endif
> 
>  #define LOAD_CANCEL(EA) do { CANCEL; } while (0)
> 
> --
> 2.31.1


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

* RE: [PATCH v5 07/14] target/hexagon: expose next PC in DisasContext
  2021-06-19  9:37 ` [PATCH v5 07/14] target/hexagon: expose next PC in DisasContext Alessandro Di Federico via
@ 2021-06-23 18:54   ` Taylor Simpson
  0 siblings, 0 replies; 38+ messages in thread
From: Taylor Simpson @ 2021-06-23 18:54 UTC (permalink / raw)
  To: Alessandro Di Federico, qemu-devel
  Cc: Alessandro Di Federico, Brian Cain, richard.henderson, babush,
	nizzo, philmd



> -----Original Message-----
> From: Alessandro Di Federico <ale.qemu@rev.ng>
> Sent: Saturday, June 19, 2021 3:37 AM
> To: qemu-devel@nongnu.org
> Cc: Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; babush@rev.ng; nizzo@rev.ng; philmd@redhat.com;
> richard.henderson@linaro.org; Alessandro Di Federico <ale@rev.ng>
> Subject: [PATCH v5 07/14] target/hexagon: expose next PC in DisasContext
> 
> From: Paolo Montesel <babush@rev.ng>
> 
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Paolo Montesel <babush@rev.ng>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  target/hexagon/translate.c | 3 ++-
>  target/hexagon/translate.h | 1 +
>  2 files changed, 3 insertions(+), 1 deletion(-)

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


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

* RE: [PATCH v5 08/14] target/hexagon: prepare input for the idef-parser
  2021-06-19  9:37 ` [PATCH v5 08/14] target/hexagon: prepare input for the idef-parser Alessandro Di Federico via
@ 2021-06-23 19:37   ` Taylor Simpson
  0 siblings, 0 replies; 38+ messages in thread
From: Taylor Simpson @ 2021-06-23 19:37 UTC (permalink / raw)
  To: Alessandro Di Federico, qemu-devel
  Cc: Alessandro Di Federico, Brian Cain, richard.henderson, babush,
	nizzo, philmd



> -----Original Message-----
> From: Alessandro Di Federico <ale.qemu@rev.ng>
> Sent: Saturday, June 19, 2021 3:37 AM
> To: qemu-devel@nongnu.org
> Cc: Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; babush@rev.ng; nizzo@rev.ng; philmd@redhat.com;
> richard.henderson@linaro.org; Alessandro Di Federico <ale@rev.ng>
> Subject: [PATCH v5 08/14] target/hexagon: prepare input for the idef-parser
> 
> From: Alessandro Di Federico <ale@rev.ng>
> 
> Introduce infrastructure necessary to produce a file suitable for being parsed
> by the idef-parser.
> 
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> ---
>  target/hexagon/gen_idef_parser_funcs.py | 114 ++++++++++++++++++
>  target/hexagon/idef-parser/macros.inc   | 153
> ++++++++++++++++++++++++
>  target/hexagon/idef-parser/prepare      |  24 ++++
>  target/hexagon/meson.build              |  17 +++
>  4 files changed, 308 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/meson.build b/target/hexagon/meson.build
> index 6fd9360b74..bf4a0f76fa 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
> @@ -175,4 +176,20 @@ hexagon_ss.add(files(
>      'fma_emu.c',
>  ))
> 
> +idef_parser_input_generated = custom_target(
> +    'idef_parser_input.h.inc',
> +    output: 'idef_parser_input.h.inc',

Add depends: [semantics_generated],

> +    depend_files: [hex_common_py],

Add gen_tcg_h

> +    command: [python, files('gen_idef_parser_funcs.py'),
> +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],

Don't think this is needed.  If hex_common_py changes, the input will change.  But otherwise, this doesn't use hex_common.py.

> +    command: [idef_parser_dir / 'prepare', '@INPUT@', '-I' +
> +idef_parser_dir],

It would be more clear to add '-o', '@OUTPUT@' to the command.

> +)
> +
>  target_arch += {'hexagon': hexagon_ss}
> --
> 2.31.1
> 



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

* RE: [PATCH v5 09/14] target/hexagon: import lexer for idef-parser
  2021-06-19  9:37 ` [PATCH v5 09/14] target/hexagon: import lexer for idef-parser Alessandro Di Federico via
@ 2021-06-23 20:05   ` Taylor Simpson
  0 siblings, 0 replies; 38+ messages in thread
From: Taylor Simpson @ 2021-06-23 20:05 UTC (permalink / raw)
  To: Alessandro Di Federico, qemu-devel
  Cc: Alessandro Di Federico, Brian Cain, richard.henderson, babush,
	nizzo, philmd



> -----Original Message-----
> From: Alessandro Di Federico <ale.qemu@rev.ng>
> Sent: Saturday, June 19, 2021 3:37 AM
> To: qemu-devel@nongnu.org
> Cc: Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; babush@rev.ng; nizzo@rev.ng; philmd@redhat.com;
> richard.henderson@linaro.org; Alessandro Di Federico <ale@rev.ng>
> Subject: [PATCH v5 09/14] target/hexagon: import lexer for idef-parser
> 
> From: Paolo Montesel <babush@rev.ng>
> 
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Paolo Montesel <babush@rev.ng>
> ---
>  target/hexagon/idef-parser/idef-parser.h      | 262 ++++++++
>  target/hexagon/idef-parser/idef-parser.lex    | 597 ++++++++++++++++++
>  target/hexagon/meson.build                    |   4 +
>  tests/docker/dockerfiles/alpine.docker        |   1 +
>  tests/docker/dockerfiles/centos8.docker       |   1 +
>  tests/docker/dockerfiles/debian-amd64.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, 876 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

> +/**
> + * Types of control registers, assigned to the HexReg.id field  */
> +typedef enum {SP, FP, LR, GP, LC0, LC1, SA0, SA1} CregType;

Where is this used?  SP, FP, LR are not control registers - they are general purpose registers.


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


> +"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; }

This looks like the use where you are treating these as control registers.  Just lex them as general purpose registers with numbers 29, 30, 31.




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

* RE: [PATCH v5 10/14] target/hexagon: import parser for idef-parser
  2021-06-19  9:37 ` [PATCH v5 10/14] target/hexagon: import parser " Alessandro Di Federico via
  2021-06-22 22:35   ` Taylor Simpson
@ 2021-06-24  3:55   ` Taylor Simpson
  2021-06-29 14:26     ` Alessandro Di Federico via
                       ` (2 more replies)
  1 sibling, 3 replies; 38+ messages in thread
From: Taylor Simpson @ 2021-06-24  3:55 UTC (permalink / raw)
  To: Alessandro Di Federico, qemu-devel
  Cc: Alessandro Di Federico, Brian Cain, richard.henderson, babush,
	nizzo, philmd



> -----Original Message-----
> From: Alessandro Di Federico <ale.qemu@rev.ng>
> Sent: Saturday, June 19, 2021 3:37 AM
> To: qemu-devel@nongnu.org
> Cc: Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; babush@rev.ng; nizzo@rev.ng; philmd@redhat.com;
> richard.henderson@linaro.org; Alessandro Di Federico <ale@rev.ng>
> Subject: [PATCH v5 10/14] target/hexagon: import parser for idef-parser
> 
> From: Paolo Montesel <babush@rev.ng>
> 
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Paolo Montesel <babush@rev.ng>
> ---
> diff --git a/target/hexagon/idef-parser/idef-parser.y b/target/hexagon/idef-
> parser/idef-parser.y



> +for_statement : FOR '(' IMM '=' IMM ';' IMM '<' IMM ';' IMM PLUSPLUS ')'
> +                {
> +                    @1.last_column = @13.last_column;
> +                    OUT(c, &@1, "for (int ", &$3, " = ", &$5, "; ",
> +                        &$7, " < ", &$9);
> +                    OUT(c, &@1, "; ", &$11, "++) {\n");

Increase indent level here

> +                }
> +                code_block
> +                {

Decrease indent level

> +                    OUT(c, &@1, "}\n");
> +                }
> +              | FOR '(' IMM '=' IMM ';' IMM '<' IMM ';' IMM INC IMM ')'
> +                {
> +                    @1.last_column = @14.last_column;
> +                    OUT(c, &@1, "for (int ", &$3, " = ", &$5, "; ",
> +                        &$7, " < ", &$9);
> +                    OUT(c, &@1, "; ", &$11, " += ", &$13, ") {\n");

Increase indent

> +                }
> +                code_block
> +                {

Decrease indent

> +                    OUT(c, &@1, "}\n");
> +                }
> +              ;
> +
> +fpart1_statement : PART1
> +                   {
> +                       OUT(c, &@1, "if (insn->part1) {\n");

Increase indent

> +                   }
> +                   '(' statements ')'
> +                   {
> +                       @1.last_column = @3.last_column;

Emit the return first, then decrease indent before the curly

> +                       OUT(c, &@1, "return; }\n");
> +                   }
> +                 ;


> +       | rvalue '[' rvalue ']'
> +         {
> +             @1.last_column = @4.last_column;
> +             if ($3.type == IMMEDIATE) {
> +                 $$ = gen_tmp(c, &@1, $1.bit_width);
> +                 OUT(c, &@1, "tcg_gen_extract_i", &$$.bit_width, "(");
> +                 OUT(c, &@1, &$$, ", ", &$1, ", ", &$3, ", 1);\n");
> +             } else {
> +                 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);

Can this be done with a tcg_gen_extract_tl or tcg_gen_sextract_tl?

Do you need to worry about signed-ness?

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


> +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"};

SP, FP, LR shouldn't in this array.

> +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 */

Should we raise an error if we get here?

> +        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);

Why not handle this in reg_compose?

> +  } 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, "ctx->base.pc_next");
> +        break;
> +    case IMM_NPC:
> +        EMIT(c, "ctx->npc");
> +        break;
> +    case IMM_CONSTEXT:
> +        EMIT(c, "insn->extension_valid");

The extension_valid field is a bool indicating if the instruction has a constant extender.  Don't you want the actual value here?

> +        break;


> +
> +static HexValue get_ternary_cond(Context *c, YYLTYPE *locp)
> +{
> +    yyassert(c, locp, is_inside_ternary(c), "unexisting condition");
> +    Ternary *t = &g_array_index(c->ternary, Ternary, 0);
> +    HexValue cond = t->cond;
> +    if (t->state == IN_RIGHT) {
> +        cond = gen_rvalue_notl(c, locp, &cond);
> +    }
> +    for (unsigned i = 1; i < c->ternary->len; ++i) {
> +        Ternary *right = &g_array_index(c->ternary, Ternary, i);
> +        HexValue other = right->cond;
> +        /* Invert condition if we are on the right side */
> +        if (right->state == IN_RIGHT) {
> +            other = gen_rvalue_notl(c, locp, &other);
> +        }
> +        cond = gen_bin_op(c, locp, ANDL_OP, &cond, &other);
> +    }
> +    return cond;
> +}
> +
> +/* Temporary values creation */
> +HexValue gen_tmp(Context *c, YYLTYPE *locp, int bit_width)
> +{
> +    HexValue rvalue;
> +    rvalue.type = TEMP;
> +    bit_width = (bit_width == 64) ? 64 : 32;

Better to assert it's either 64 or 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;
> +    OUT(c, locp, "TCGv_i", &bit_width, " tmp_", &c->inst.tmp_count,
> +        " = tcg_temp_new_i", &bit_width, "();\n");
> +    c->inst.tmp_count++;
> +    return rvalue;
> +}
> +


> +
> +void rvalue_free(Context *c, YYLTYPE *locp, HexValue *rvalue)

Should be called gen_rvalue_free

> +{
> +    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");
> +    }
> +}


> +HexValue rvalue_extend(Context *c, YYLTYPE *locp, HexValue *rvalue)

Should be called gen_rvalue_extend

> +{
> +    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)

Should be called gen_rvalue_truncate

> +{
> +    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;
> +}
> +


> +void varid_allocate(Context *c,

gen_varid_allocate

> +                    YYLTYPE *locp,
> +                    HexValue *varid,
> +                    int width,
> +                    bool is_unsigned)
> +{
> +    varid->bit_width = width;
> +    const char *bit_suffix = width == 64 ? "64" : "32";
> +    int index = find_variable(c, locp, varid);
> +    bool found = index != -1;
> +    if (found) {
> +        Var *other = &g_array_index(c->inst.allocated, Var, index);
> +        varid->var.name = other->name;
> +        varid->bit_width = other->bit_width;
> +        varid->is_unsigned = other->is_unsigned;
> +    } else {
> +        EMIT_HEAD(c, "TCGv_i%s %s", bit_suffix, varid->var.name->str);
> +        EMIT_HEAD(c, " = tcg_temp_local_new_i%s();\n", bit_suffix);
> +        Var new_var = {
> +            .name = varid->var.name,
> +            .bit_width = width,
> +            .is_unsigned = is_unsigned,
> +        };
> +        g_array_append_val(c->inst.allocated, new_var);
> +    }
> +}
> +
> +void ea_free(Context *c, YYLTYPE *locp)

gen_ea_free

> +{
> +    OUT(c, locp, "tcg_temp_free(EA);\n");
> +}
> +HexValue gen_bin_cmp(Context *c,
> +                     YYLTYPE *locp,
> +                     TCGCond 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. */

This is duplicated elsewhere (e.g., gen_bin_op) - should be pulled into a single function.

> +    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;
> +        }
> +    }



> +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 *min = res->is_unsigned ? "tcg_gen_umin" : "tcg_gen_smin";
> +    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, min, "_i", &bit_width, "(");
> +        OUT(c, locp, res, ", ", &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, min, "_i", &bit_width, "(");
> +        OUT(c, locp, res, ", ", &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 *min = res->is_unsigned ? "tcg_gen_umax" : "tcg_gen_smax";
> +    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, min, "_i", &bit_width, "(");
> +        OUT(c, locp, res, ", ", &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, min, "_i", &bit_width, "(");
> +        OUT(c, locp, res, ", ", &op1, ", ", &op2, ");\n");
> +        break;
> +    }
> +    rvalue_free(c, locp, &op1);
> +    rvalue_free(c, locp, &op2);
> +}

These two look basically the same, create a single function with one extra are indicating min/max.


> +HexValue gen_cast_op(Context *c,
> +                     YYLTYPE *locp,
> +                     HexValue *source,
> +                     unsigned target_width) {

Don't you need to worry about signed-ness of the result?

> +    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);

Can't you do this with tcg_gen_extract?

> +    } else {
> +        OUT(c, locp, "tcg_gen_shl_i64(",
> +            &res, ", ", &value, ", ", &shift, ");\n");
> +        OUT(c, locp, "tcg_gen_sar_i64(",
> +            &res, ", ", &res, ", ", &shift, ");\n");

Can't you do this with get_gen_sectract?

> +    }
> +    OUT(c, locp, "tcg_gen_movcond_i64(TCG_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);
> +

Can't you do this with tcg_gen_deposit?

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

What's the difference between this and the gen_rdeposit_op above?


> +{
> +    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) {

What's the difference between this ant the gen_rextract_op above?

> +    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') {

What is this check telling us?

> +        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");

Change READ_REG to gen_read_reg - that's what the macro is.

> +        rvalue_free(c, locp, reg);
> +        return tmp;
> +    }
> +    return *reg;
> +}
> +


> +/* Circular addressing mode with auto-increment */
> +void gen_circ_op(Context *c,
> +                 YYLTYPE *locp,
> +                 HexValue *addr,
> +                 HexValue *increment,
> +                 HexValue *modifier) {
> +    HexValue increment_m = *increment;
> +    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");

Change READ_REG to gen_read_reg

> +    OUT(c,
> +        locp,
> +        "gen_helper_fcircadd(",
> +        addr,
> +        ", ",
> +        addr,
> +        ", ",
> +        &increment_m,
> +        ", ",
> +        modifier);
> +    OUT(c, locp, ", ", &cs, ");\n");
> +    rvalue_free(c, locp, &increment_m);
> +    rvalue_free(c, locp, modifier);
> +    rvalue_free(c, locp, &cs);
> +}



> +void gen_load(Context *c, YYLTYPE *locp, HexValue *num, HexValue *size,
> +              bool is_unsigned, HexValue *ea, HexValue *dst)
> +{
> +    /* Memop width is specified in the load macro */
> +    int bit_width = (size->imm.value > 4) ? 64 : 32;
> +    const char *sign_suffix = (size->imm.value > 4)
> +                              ? ""
> +                              : ((is_unsigned) ? "u" : "s");
> +    char size_suffix[4] = { 0 };
> +    /* Create temporary variable (if not present) */
> +    if (dst->type == VARID) {
> +        /* TODO: this is a common pattern, the parser should be varid-aware.
> */
> +        varid_allocate(c, locp, dst, bit_width, is_unsigned);
> +    }
> +    snprintf(size_suffix, 4, "%" PRIu64, size->imm.value * 8);
> +    if (bit_width == 32) {
> +        *dst = rvalue_truncate(c, locp, dst);
> +    } else {
> +        *dst = rvalue_extend(c, locp, dst);
> +    }

Why is the truncate/extend needed for the destination?

> +    int var_id = find_variable(c, locp, ea);
> +    yyassert(c, locp, var_id != -1, "Load variable must exist!\n");
> +    /* We need to enforce the variable size */
> +    ea->bit_width = g_array_index(c->inst.allocated, Var, var_id).bit_width;
> +    if (ea->bit_width != 32) {
> +        *ea = rvalue_truncate(c, locp, ea);
> +    }
> +    OUT(c, locp, "if (insn->slot == 0 && pkt->pkt_has_store_s1) {\n");
> +    OUT(c, locp, "process_store(ctx, pkt, 1);\n");

Indent

> +    OUT(c, locp, "}\n");
> +    OUT(c, locp, "tcg_gen_qemu_ld", size_suffix, sign_suffix);
> +    OUT(c, locp, "(", dst, ", ", ea, ", 0);\n");
> +    /* If the var in EA was truncated it is now a tmp HexValue, so free it. */
> +    rvalue_free(c, locp, ea);
> +}
> +
> +void gen_store(Context *c, YYLTYPE *locp, HexValue *num, HexValue
> *size,
> +               HexValue *ea, HexValue *src)
> +{
> +    /* Memop width is specified in the store macro */
> +    int mem_width = size->imm.value;
> +    /* Adjust operand bit width to memop bit width */
> +    if (mem_width < 8) {
> +        *src = rvalue_truncate(c, locp, src);
> +    } else {
> +        *src = rvalue_extend(c, locp, src);
> +    }

Why is this needed?

> +    assert(ea->type == VARID);
> +    int var_id = find_variable(c, locp, ea);
> +    yyassert(c, locp, var_id != -1, "Load variable must exist!\n");
> +    /* We need to enforce the variable size */
> +    ea->bit_width = g_array_index(c->inst.allocated, Var, var_id).bit_width;
> +    if (ea->bit_width != 32) {
> +        *ea = rvalue_truncate(c, locp, ea);
> +    }

How can ea be not 32 bits?

> +    *src = rvalue_materialize(c, locp, src);
> +    OUT(c, locp, "gen_store", &mem_width, "(cpu_env, ", ea, ", ", src);
> +    OUT(c, locp, ", ctx, insn->slot);\n");
> +    rvalue_free(c, locp, src);
> +    /* If the var in ea was truncated it is now a tmp HexValue, so free it. */
> +    rvalue_free(c, locp, ea);
> +}
> +


> +void gen_setbits(Context *c, YYLTYPE *locp, HexValue *hi, HexValue *lo,
> +                 HexValue *dst, HexValue *val)
> +{
> +    yyassert(c, locp, hi->type == IMMEDIATE &&
> +             hi->imm.type == VALUE &&
> +             lo->type == IMMEDIATE &&
> +             lo->imm.type == VALUE,
> +             "Range deposit needs immediate values!\n");
> +
> +    *val = rvalue_truncate(c, locp, val);
> +    unsigned len = hi->imm.value + 1 - lo->imm.value;
> +    HexValue tmp = gen_tmp(c, locp, 32);
> +    OUT(c, locp, "tcg_gen_neg_i32(", &tmp, ", ", val, ");\n");
> +    OUT(c, locp, "tcg_gen_deposit_i32(", dst, ", ", dst, ", ", &tmp, ", ");
> +    OUT(c, locp, lo, ", ", &len, ");\n");


This doesn't match the C semantics of fSETBITS

#define fSETBIT(N, DST, VAL) \
    do { \
        DST = (DST & ~(1ULL << (N))) | (((uint64_t)(VAL)) << (N)); \
    } while (0)

#define fGETBIT(N, SRC) (((SRC) >> N) & 1)
#define fSETBITS(HI, LO, DST, VAL) \
    do { \
        int j; \
        for (j = LO; j <= HI; j++) { \
            fSETBIT(j, DST, VAL); \
        } \
    } while (0)

You need to put len copies of LSB(val), so emit something like this
    TCGv zero = tcg_const_tl(0);
    TCGv ones = tcg_const_tl(~0);
    tcg_gen_andi_tl(tmp, val, 1);
    tcg_gen_movcond_tl(TCG_COND_NE, tmp, tmp, zero, ones, zero);
    tcg_gen_deposit_tl(dst, dst, tmp, lo, len);
    tcg_temp_free(zero);
    tcg_temp_free(ones);



> +HexValue gen_rvalue_pow(Context *c, YYLTYPE *locp, HexValue *l,
> HexValue *r)

Which instruction calls this?  I don't think there is one.  If not, remove the POW token from the lexer and the associated rules from the parser.



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

tcg_gen_abs_i<bit_width>

> +        OUT(c, locp, ", ", v, ", ", &res, ");\n");
> +        rvalue_free(c, locp, &zero);
> +        rvalue_free(c, locp, v);
> +    }
> +    return res;
> +}
> +
> +HexValue gen_rvalue_brev(Context *c, YYLTYPE *locp, HexValue *v)
> +{
> +    yyassert(c, locp, v->bit_width <= 32,
> +             "fbrev not implemented for 64-bit integers!");
> +    HexValue res = gen_tmp(c, locp, v->bit_width);
> +    *v = rvalue_materialize(c, locp, v);
> +    OUT(c, locp, "gen_fbrev(", &res, ", ", v, ");\n");

gen_helper_fbrev



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

> +#define OUT(c, locp, ...) FOR_EACH((c), (locp), OUT_IMPL, __VA_ARGS__)

You should be able to handle indenting here.  Unfortunately, many of the C statements generated use multiple OUT invocations.
Create two macros
	OUT			prints indentation, then the text		used for beginning a line of output
              OUT_CONTINUE	just print the text				used for continuing a line

> diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
> index 329219463f..a2257d41a5 100644
> --- a/target/hexagon/meson.build
> +++ b/target/hexagon/meson.build
> @@ -183,7 +183,7 @@ idef_parser_input_generated = custom_target(
>      command: [python, files('gen_idef_parser_funcs.py'),
> semantics_generated, attribs_def, gen_tcg_h, '@OUTPUT@'],
>  )
> 
> -idef_parser_input_generated_prep = custom_target(
> +preprocessed_idef_parser_input_generated = custom_target(

Don't change the name of this here, use the name you want in the patch where it was introduced.



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

* Re: [PATCH v5 03/14] target/hexagon: import README for idef-parser
  2021-06-23 15:46   ` Taylor Simpson
@ 2021-06-24 13:51     ` Alessandro Di Federico via
  0 siblings, 0 replies; 38+ messages in thread
From: Alessandro Di Federico via @ 2021-06-24 13:51 UTC (permalink / raw)
  To: Taylor Simpson
  Cc: qemu-devel, Brian Cain, babush, nizzo, philmd, richard.henderson

On Wed, 23 Jun 2021 15:46:22 +0000
Taylor Simpson <tsimpson@quicinc.com> wrote:

> The output isn't actually indented, but it would be great if it were.
>  This is especially true for instructions where an "if" or "for" show
> up in the emitted code.

Emitting whitespaces in the parser is a bit annoying and fragile, but
it can be done.

We post-process the parser output with `indent` internally. We could
run it after the output is produced, but that would mean a new
dependency.

I'd go for opportunistic indentation through `indent` if installed.

> Is there a way to force the parser not to emit a particular
> instruction (i.e., fall back on the reference implementation)?

Yes, see `gen_idef_parser_funcs.py`.

-- 
Alessandro Di Federico
rev.ng


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

* RE: [PATCH v5 11/14] target/hexagon: call idef-parser functions
  2021-06-19  9:37 ` [PATCH v5 11/14] target/hexagon: call idef-parser functions Alessandro Di Federico via
@ 2021-06-25 22:00   ` Taylor Simpson
  0 siblings, 0 replies; 38+ messages in thread
From: Taylor Simpson @ 2021-06-25 22:00 UTC (permalink / raw)
  To: Alessandro Di Federico, qemu-devel
  Cc: Alessandro Di Federico, Brian Cain, richard.henderson, babush,
	nizzo, philmd



> -----Original Message-----
> From: Alessandro Di Federico <ale.qemu@rev.ng>
> Sent: Saturday, June 19, 2021 3:37 AM
> To: qemu-devel@nongnu.org
> Cc: Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; babush@rev.ng; nizzo@rev.ng; philmd@redhat.com;
> richard.henderson@linaro.org; Alessandro Di Federico <ale@rev.ng>
> Subject: [PATCH v5 11/14] target/hexagon: call idef-parser functions
> 
> From: Alessandro Di Federico <ale@rev.ng>
> 
> Extend gen_tcg_funcs.py in order to emit calls to the functions emitted by
> the idef-parser, if available.
> 
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>

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


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

* Re: [PATCH v5 12/14] target/hexagon: remove unused macros and functions
  2021-06-19  9:37 ` [PATCH v5 12/14] target/hexagon: remove unused macros and functions Alessandro Di Federico via
@ 2021-06-25 22:02   ` Taylor Simpson
  0 siblings, 0 replies; 38+ messages in thread
From: Taylor Simpson @ 2021-06-25 22:02 UTC (permalink / raw)
  To: Alessandro Di Federico
  Cc: Alessandro Di Federico, bcain, richard.henderson, qemu-devel,
	babush, tsimpson, nizzo, philmd

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

Don't do this.  Keeping these around makes it easy to fall back to the
helper implementations for debugging.  Also, some of them are needed for
future HVX support.

Thanks,
Taylor

On Sat, Jun 19, 2021 at 4:48 AM Alessandro Di Federico via <
qemu-devel@nongnu.org> 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/gen_tcg.h   | 528 -------------------------------------
>  target/hexagon/genptr.c    |  98 -------
>  target/hexagon/macros.h    | 200 +-------------
>  target/hexagon/op_helper.c | 119 ---------
>  4 files changed, 9 insertions(+), 936 deletions(-)
>
> diff --git a/target/hexagon/gen_tcg.h b/target/hexagon/gen_tcg.h
> index 18fcdbc7e4..f1dd1b64c1 100644
> --- a/target/hexagon/gen_tcg.h
> +++ b/target/hexagon/gen_tcg.h
> @@ -43,381 +43,6 @@
>   *     _pcr      post increment circular register  r0 =
> memw(r1++I:circ(m0))
>   */
>
> -/* Macros for complex addressing modes */
> -#define GET_EA_ap \
> -    do { \
> -        fEA_IMM(UiV); \
> -        tcg_gen_movi_tl(ReV, UiV); \
> -    } while (0)
> -#define GET_EA_pr \
> -    do { \
> -        fEA_REG(RxV); \
> -        fPM_M(RxV, MuV); \
> -    } while (0)
> -#define GET_EA_pbr \
> -    do { \
> -        gen_helper_fbrev(EA, RxV); \
> -        tcg_gen_add_tl(RxV, RxV, MuV); \
> -    } while (0)
> -#define GET_EA_pi \
> -    do { \
> -        fEA_REG(RxV); \
> -        fPM_I(RxV, siV); \
> -    } while (0)
> -#define GET_EA_pci \
> -    do { \
> -        TCGv tcgv_siV = tcg_const_tl(siV); \
> -        tcg_gen_mov_tl(EA, RxV); \
> -        gen_helper_fcircadd(RxV, RxV, tcgv_siV, MuV, \
> -                            hex_gpr[HEX_REG_CS0 + MuN]); \
> -        tcg_temp_free(tcgv_siV); \
> -    } while (0)
> -#define GET_EA_pcr(SHIFT) \
> -    do { \
> -        TCGv ireg = tcg_temp_new(); \
> -        tcg_gen_mov_tl(EA, RxV); \
> -        gen_read_ireg(ireg, MuV, (SHIFT)); \
> -        gen_helper_fcircadd(RxV, RxV, ireg, MuV, hex_gpr[HEX_REG_CS0 +
> MuN]); \
> -        tcg_temp_free(ireg); \
> -    } while (0)
> -
> -/* Instructions with multiple definitions */
> -#define fGEN_TCG_LOAD_AP(RES, SIZE, SIGN) \
> -    do { \
> -        fMUST_IMMEXT(UiV); \
> -        fEA_IMM(UiV); \
> -        fLOAD(1, SIZE, SIGN, EA, RES); \
> -        tcg_gen_movi_tl(ReV, UiV); \
> -    } while (0)
> -
> -#define fGEN_TCG_L4_loadrub_ap(SHORTCODE) \
> -    fGEN_TCG_LOAD_AP(RdV, 1, u)
> -#define fGEN_TCG_L4_loadrb_ap(SHORTCODE) \
> -    fGEN_TCG_LOAD_AP(RdV, 1, s)
> -#define fGEN_TCG_L4_loadruh_ap(SHORTCODE) \
> -    fGEN_TCG_LOAD_AP(RdV, 2, u)
> -#define fGEN_TCG_L4_loadrh_ap(SHORTCODE) \
> -    fGEN_TCG_LOAD_AP(RdV, 2, s)
> -#define fGEN_TCG_L4_loadri_ap(SHORTCODE) \
> -    fGEN_TCG_LOAD_AP(RdV, 4, u)
> -#define fGEN_TCG_L4_loadrd_ap(SHORTCODE) \
> -    fGEN_TCG_LOAD_AP(RddV, 8, u)
> -
> -#define fGEN_TCG_L2_loadrub_pci(SHORTCODE)    SHORTCODE
> -#define fGEN_TCG_L2_loadrb_pci(SHORTCODE)     SHORTCODE
> -#define fGEN_TCG_L2_loadruh_pci(SHORTCODE)    SHORTCODE
> -#define fGEN_TCG_L2_loadrh_pci(SHORTCODE)     SHORTCODE
> -#define fGEN_TCG_L2_loadri_pci(SHORTCODE)     SHORTCODE
> -#define fGEN_TCG_L2_loadrd_pci(SHORTCODE)     SHORTCODE
> -
> -#define fGEN_TCG_LOAD_pcr(SHIFT, LOAD) \
> -    do { \
> -        TCGv ireg = tcg_temp_new(); \
> -        tcg_gen_mov_tl(EA, RxV); \
> -        gen_read_ireg(ireg, MuV, SHIFT); \
> -        gen_helper_fcircadd(RxV, RxV, ireg, MuV, hex_gpr[HEX_REG_CS0 +
> MuN]); \
> -        LOAD; \
> -        tcg_temp_free(ireg); \
> -    } while (0)
> -
> -#define fGEN_TCG_L2_loadrub_pcr(SHORTCODE) \
> -      fGEN_TCG_LOAD_pcr(0, fLOAD(1, 1, u, EA, RdV))
> -#define fGEN_TCG_L2_loadrb_pcr(SHORTCODE) \
> -      fGEN_TCG_LOAD_pcr(0, fLOAD(1, 1, s, EA, RdV))
> -#define fGEN_TCG_L2_loadruh_pcr(SHORTCODE) \
> -      fGEN_TCG_LOAD_pcr(1, fLOAD(1, 2, u, EA, RdV))
> -#define fGEN_TCG_L2_loadrh_pcr(SHORTCODE) \
> -      fGEN_TCG_LOAD_pcr(1, fLOAD(1, 2, s, EA, RdV))
> -#define fGEN_TCG_L2_loadri_pcr(SHORTCODE) \
> -      fGEN_TCG_LOAD_pcr(2, fLOAD(1, 4, u, EA, RdV))
> -#define fGEN_TCG_L2_loadrd_pcr(SHORTCODE) \
> -      fGEN_TCG_LOAD_pcr(3, fLOAD(1, 8, u, EA, RddV))
> -
> -#define fGEN_TCG_L2_loadrub_pr(SHORTCODE)      SHORTCODE
> -#define fGEN_TCG_L2_loadrub_pbr(SHORTCODE)     SHORTCODE
> -#define fGEN_TCG_L2_loadrub_pi(SHORTCODE)      SHORTCODE
> -#define fGEN_TCG_L2_loadrb_pr(SHORTCODE)       SHORTCODE
> -#define fGEN_TCG_L2_loadrb_pbr(SHORTCODE)      SHORTCODE
> -#define fGEN_TCG_L2_loadrb_pi(SHORTCODE)       SHORTCODE
> -#define fGEN_TCG_L2_loadruh_pr(SHORTCODE)      SHORTCODE
> -#define fGEN_TCG_L2_loadruh_pbr(SHORTCODE)     SHORTCODE
> -#define fGEN_TCG_L2_loadruh_pi(SHORTCODE)      SHORTCODE
> -#define fGEN_TCG_L2_loadrh_pr(SHORTCODE)       SHORTCODE
> -#define fGEN_TCG_L2_loadrh_pbr(SHORTCODE)      SHORTCODE
> -#define fGEN_TCG_L2_loadrh_pi(SHORTCODE)       SHORTCODE
> -#define fGEN_TCG_L2_loadri_pr(SHORTCODE)       SHORTCODE
> -#define fGEN_TCG_L2_loadri_pbr(SHORTCODE)      SHORTCODE
> -#define fGEN_TCG_L2_loadri_pi(SHORTCODE)       SHORTCODE
> -#define fGEN_TCG_L2_loadrd_pr(SHORTCODE)       SHORTCODE
> -#define fGEN_TCG_L2_loadrd_pbr(SHORTCODE)      SHORTCODE
> -#define fGEN_TCG_L2_loadrd_pi(SHORTCODE)       SHORTCODE
> -
> -/*
> - * These instructions load 2 bytes and places them in
> - * two halves of the destination register.
> - * The GET_EA macro determines the addressing mode.
> - * The SIGN argument determines whether to zero-extend or
> - * sign-extend.
> - */
> -#define fGEN_TCG_loadbXw2(GET_EA, SIGN) \
> -    do { \
> -        TCGv tmp = tcg_temp_new(); \
> -        TCGv byte = tcg_temp_new(); \
> -        GET_EA; \
> -        fLOAD(1, 2, u, EA, tmp); \
> -        tcg_gen_movi_tl(RdV, 0); \
> -        for (int i = 0; i < 2; i++) { \
> -            gen_set_half(i, RdV, gen_get_byte(byte, i, tmp, (SIGN))); \
> -        } \
> -        tcg_temp_free(tmp); \
> -        tcg_temp_free(byte); \
> -    } while (0)
> -
> -#define fGEN_TCG_L2_loadbzw2_io(SHORTCODE) \
> -    fGEN_TCG_loadbXw2(fEA_RI(RsV, siV), false)
> -#define fGEN_TCG_L4_loadbzw2_ur(SHORTCODE) \
> -    fGEN_TCG_loadbXw2(fEA_IRs(UiV, RtV, uiV), false)
> -#define fGEN_TCG_L2_loadbsw2_io(SHORTCODE) \
> -    fGEN_TCG_loadbXw2(fEA_RI(RsV, siV), true)
> -#define fGEN_TCG_L4_loadbsw2_ur(SHORTCODE) \
> -    fGEN_TCG_loadbXw2(fEA_IRs(UiV, RtV, uiV), true)
> -#define fGEN_TCG_L4_loadbzw2_ap(SHORTCODE) \
> -    fGEN_TCG_loadbXw2(GET_EA_ap, false)
> -#define fGEN_TCG_L2_loadbzw2_pr(SHORTCODE) \
> -    fGEN_TCG_loadbXw2(GET_EA_pr, false)
> -#define fGEN_TCG_L2_loadbzw2_pbr(SHORTCODE) \
> -    fGEN_TCG_loadbXw2(GET_EA_pbr, false)
> -#define fGEN_TCG_L2_loadbzw2_pi(SHORTCODE) \
> -    fGEN_TCG_loadbXw2(GET_EA_pi, false)
> -#define fGEN_TCG_L4_loadbsw2_ap(SHORTCODE) \
> -    fGEN_TCG_loadbXw2(GET_EA_ap, true)
> -#define fGEN_TCG_L2_loadbsw2_pr(SHORTCODE) \
> -    fGEN_TCG_loadbXw2(GET_EA_pr, true)
> -#define fGEN_TCG_L2_loadbsw2_pbr(SHORTCODE) \
> -    fGEN_TCG_loadbXw2(GET_EA_pbr, true)
> -#define fGEN_TCG_L2_loadbsw2_pi(SHORTCODE) \
> -    fGEN_TCG_loadbXw2(GET_EA_pi, true)
> -#define fGEN_TCG_L2_loadbzw2_pci(SHORTCODE) \
> -    fGEN_TCG_loadbXw2(GET_EA_pci, false)
> -#define fGEN_TCG_L2_loadbsw2_pci(SHORTCODE) \
> -    fGEN_TCG_loadbXw2(GET_EA_pci, true)
> -#define fGEN_TCG_L2_loadbzw2_pcr(SHORTCODE) \
> -    fGEN_TCG_loadbXw2(GET_EA_pcr(1), false)
> -#define fGEN_TCG_L2_loadbsw2_pcr(SHORTCODE) \
> -    fGEN_TCG_loadbXw2(GET_EA_pcr(1), true)
> -
> -/*
> - * These instructions load 4 bytes and places them in
> - * four halves of the destination register pair.
> - * The GET_EA macro determines the addressing mode.
> - * The SIGN argument determines whether to zero-extend or
> - * sign-extend.
> - */
> -#define fGEN_TCG_loadbXw4(GET_EA, SIGN) \
> -    do { \
> -        TCGv tmp = tcg_temp_new(); \
> -        TCGv byte = tcg_temp_new(); \
> -        GET_EA; \
> -        fLOAD(1, 4, u, EA, tmp);  \
> -        tcg_gen_movi_i64(RddV, 0); \
> -        for (int i = 0; i < 4; i++) { \
> -            gen_set_half_i64(i, RddV, gen_get_byte(byte, i, tmp,
> (SIGN)));  \
> -        }  \
> -        tcg_temp_free(tmp); \
> -        tcg_temp_free(byte); \
> -    } while (0)
> -
> -#define fGEN_TCG_L2_loadbzw4_io(SHORTCODE) \
> -    fGEN_TCG_loadbXw4(fEA_RI(RsV, siV), false)
> -#define fGEN_TCG_L4_loadbzw4_ur(SHORTCODE) \
> -    fGEN_TCG_loadbXw4(fEA_IRs(UiV, RtV, uiV), false)
> -#define fGEN_TCG_L2_loadbsw4_io(SHORTCODE) \
> -    fGEN_TCG_loadbXw4(fEA_RI(RsV, siV), true)
> -#define fGEN_TCG_L4_loadbsw4_ur(SHORTCODE) \
> -    fGEN_TCG_loadbXw4(fEA_IRs(UiV, RtV, uiV), true)
> -#define fGEN_TCG_L2_loadbzw4_pci(SHORTCODE) \
> -    fGEN_TCG_loadbXw4(GET_EA_pci, false)
> -#define fGEN_TCG_L2_loadbsw4_pci(SHORTCODE) \
> -    fGEN_TCG_loadbXw4(GET_EA_pci, true)
> -#define fGEN_TCG_L2_loadbzw4_pcr(SHORTCODE) \
> -    fGEN_TCG_loadbXw4(GET_EA_pcr(2), false)
> -#define fGEN_TCG_L2_loadbsw4_pcr(SHORTCODE) \
> -    fGEN_TCG_loadbXw4(GET_EA_pcr(2), true)
> -#define fGEN_TCG_L4_loadbzw4_ap(SHORTCODE) \
> -    fGEN_TCG_loadbXw4(GET_EA_ap, false)
> -#define fGEN_TCG_L2_loadbzw4_pr(SHORTCODE) \
> -    fGEN_TCG_loadbXw4(GET_EA_pr, false)
> -#define fGEN_TCG_L2_loadbzw4_pbr(SHORTCODE) \
> -    fGEN_TCG_loadbXw4(GET_EA_pbr, false)
> -#define fGEN_TCG_L2_loadbzw4_pi(SHORTCODE) \
> -    fGEN_TCG_loadbXw4(GET_EA_pi, false)
> -#define fGEN_TCG_L4_loadbsw4_ap(SHORTCODE) \
> -    fGEN_TCG_loadbXw4(GET_EA_ap, true)
> -#define fGEN_TCG_L2_loadbsw4_pr(SHORTCODE) \
> -    fGEN_TCG_loadbXw4(GET_EA_pr, true)
> -#define fGEN_TCG_L2_loadbsw4_pbr(SHORTCODE) \
> -    fGEN_TCG_loadbXw4(GET_EA_pbr, true)
> -#define fGEN_TCG_L2_loadbsw4_pi(SHORTCODE) \
> -    fGEN_TCG_loadbXw4(GET_EA_pi, true)
> -
> -/*
> - * These instructions load a half word, shift the destination right by 16
> bits
> - * and place the loaded value in the high half word of the destination
> pair.
> - * The GET_EA macro determines the addressing mode.
> - */
> -#define fGEN_TCG_loadalignh(GET_EA) \
> -    do { \
> -        TCGv tmp = tcg_temp_new(); \
> -        TCGv_i64 tmp_i64 = tcg_temp_new_i64(); \
> -        GET_EA;  \
> -        fLOAD(1, 2, u, EA, tmp);  \
> -        tcg_gen_extu_i32_i64(tmp_i64, tmp); \
> -        tcg_gen_shri_i64(RyyV, RyyV, 16); \
> -        tcg_gen_deposit_i64(RyyV, RyyV, tmp_i64, 48, 16); \
> -        tcg_temp_free(tmp); \
> -        tcg_temp_free_i64(tmp_i64); \
> -    } while (0)
> -
> -#define fGEN_TCG_L4_loadalignh_ur(SHORTCODE) \
> -    fGEN_TCG_loadalignh(fEA_IRs(UiV, RtV, uiV))
> -#define fGEN_TCG_L2_loadalignh_io(SHORTCODE) \
> -    fGEN_TCG_loadalignh(fEA_RI(RsV, siV))
> -#define fGEN_TCG_L2_loadalignh_pci(SHORTCODE) \
> -    fGEN_TCG_loadalignh(GET_EA_pci)
> -#define fGEN_TCG_L2_loadalignh_pcr(SHORTCODE) \
> -    fGEN_TCG_loadalignh(GET_EA_pcr(1))
> -#define fGEN_TCG_L4_loadalignh_ap(SHORTCODE) \
> -    fGEN_TCG_loadalignh(GET_EA_ap)
> -#define fGEN_TCG_L2_loadalignh_pr(SHORTCODE) \
> -    fGEN_TCG_loadalignh(GET_EA_pr)
> -#define fGEN_TCG_L2_loadalignh_pbr(SHORTCODE) \
> -    fGEN_TCG_loadalignh(GET_EA_pbr)
> -#define fGEN_TCG_L2_loadalignh_pi(SHORTCODE) \
> -    fGEN_TCG_loadalignh(GET_EA_pi)
> -
> -/* Same as above, but loads a byte instead of half word */
> -#define fGEN_TCG_loadalignb(GET_EA) \
> -    do { \
> -        TCGv tmp = tcg_temp_new(); \
> -        TCGv_i64 tmp_i64 = tcg_temp_new_i64(); \
> -        GET_EA;  \
> -        fLOAD(1, 1, u, EA, tmp);  \
> -        tcg_gen_extu_i32_i64(tmp_i64, tmp); \
> -        tcg_gen_shri_i64(RyyV, RyyV, 8); \
> -        tcg_gen_deposit_i64(RyyV, RyyV, tmp_i64, 56, 8); \
> -        tcg_temp_free(tmp); \
> -        tcg_temp_free_i64(tmp_i64); \
> -    } while (0)
> -
> -#define fGEN_TCG_L2_loadalignb_io(SHORTCODE) \
> -    fGEN_TCG_loadalignb(fEA_RI(RsV, siV))
> -#define fGEN_TCG_L4_loadalignb_ur(SHORTCODE) \
> -    fGEN_TCG_loadalignb(fEA_IRs(UiV, RtV, uiV))
> -#define fGEN_TCG_L2_loadalignb_pci(SHORTCODE) \
> -    fGEN_TCG_loadalignb(GET_EA_pci)
> -#define fGEN_TCG_L2_loadalignb_pcr(SHORTCODE) \
> -    fGEN_TCG_loadalignb(GET_EA_pcr(0))
> -#define fGEN_TCG_L4_loadalignb_ap(SHORTCODE) \
> -    fGEN_TCG_loadalignb(GET_EA_ap)
> -#define fGEN_TCG_L2_loadalignb_pr(SHORTCODE) \
> -    fGEN_TCG_loadalignb(GET_EA_pr)
> -#define fGEN_TCG_L2_loadalignb_pbr(SHORTCODE) \
> -    fGEN_TCG_loadalignb(GET_EA_pbr)
> -#define fGEN_TCG_L2_loadalignb_pi(SHORTCODE) \
> -    fGEN_TCG_loadalignb(GET_EA_pi)
> -
> -/*
> - * Predicated loads
> - * Here is a primer to understand the tag names
> - *
> - * Predicate used
> - *      t        true "old" value                  if (p0) r0 =
> memb(r2+#0)
> - *      f        false "old" value                 if (!p0) r0 =
> memb(r2+#0)
> - *      tnew     true "new" value                  if (p0.new) r0 =
> memb(r2+#0)
> - *      fnew     false "new" value                 if (!p0.new) r0 =
> memb(r2+#0)
> - */
> -#define fGEN_TCG_PRED_LOAD(GET_EA, PRED, SIZE, SIGN) \
> -    do { \
> -        TCGv LSB = tcg_temp_local_new(); \
> -        TCGLabel *label = gen_new_label(); \
> -        GET_EA; \
> -        PRED;  \
> -        PRED_LOAD_CANCEL(LSB, EA); \
> -        tcg_gen_movi_tl(RdV, 0); \
> -        tcg_gen_brcondi_tl(TCG_COND_EQ, LSB, 0, label); \
> -            fLOAD(1, SIZE, SIGN, EA, RdV); \
> -        gen_set_label(label); \
> -        tcg_temp_free(LSB); \
> -    } while (0)
> -
> -#define fGEN_TCG_L2_ploadrubt_pi(SHORTCODE) \
> -    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBOLD(PtV), 1, u)
> -#define fGEN_TCG_L2_ploadrubf_pi(SHORTCODE) \
> -    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBOLDNOT(PtV), 1, u)
> -#define fGEN_TCG_L2_ploadrubtnew_pi(SHORTCODE) \
> -    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBNEW(PtN), 1, u)
> -#define fGEN_TCG_L2_ploadrubfnew_pi(SHORTCODE) \
> -    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBNEWNOT(PtN), 1, u)
> -#define fGEN_TCG_L2_ploadrbt_pi(SHORTCODE) \
> -    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBOLD(PtV), 1, s)
> -#define fGEN_TCG_L2_ploadrbf_pi(SHORTCODE) \
> -    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBOLDNOT(PtV), 1, s)
> -#define fGEN_TCG_L2_ploadrbtnew_pi(SHORTCODE) \
> -    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBNEW(PtN), 1, s)
> -#define fGEN_TCG_L2_ploadrbfnew_pi(SHORTCODE) \
> -    fGEN_TCG_PRED_LOAD({ fEA_REG(RxV); fPM_I(RxV, siV); }, \
> -                       fLSBNEWNOT(PtN), 1, s)
> -
> -#define fGEN_TCG_L2_ploadruht_pi(SHORTCODE) \
> -    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBOLD(PtV), 2, u)
> -#define fGEN_TCG_L2_ploadruhf_pi(SHORTCODE) \
> -    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBOLDNOT(PtV), 2, u)
> -#define fGEN_TCG_L2_ploadruhtnew_pi(SHORTCODE) \
> -    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBNEW(PtN), 2, u)
> -#define fGEN_TCG_L2_ploadruhfnew_pi(SHORTCODE) \
> -    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBNEWNOT(PtN), 2, u)
> -#define fGEN_TCG_L2_ploadrht_pi(SHORTCODE) \
> -    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBOLD(PtV), 2, s)
> -#define fGEN_TCG_L2_ploadrhf_pi(SHORTCODE) \
> -    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBOLDNOT(PtV), 2, s)
> -#define fGEN_TCG_L2_ploadrhtnew_pi(SHORTCODE) \
> -    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBNEW(PtN), 2, s)
> -#define fGEN_TCG_L2_ploadrhfnew_pi(SHORTCODE) \
> -    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBNEWNOT(PtN), 2, s)
> -
> -#define fGEN_TCG_L2_ploadrit_pi(SHORTCODE) \
> -    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBOLD(PtV), 4, u)
> -#define fGEN_TCG_L2_ploadrif_pi(SHORTCODE) \
> -    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBOLDNOT(PtV), 4, u)
> -#define fGEN_TCG_L2_ploadritnew_pi(SHORTCODE) \
> -    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBNEW(PtN), 4, u)
> -#define fGEN_TCG_L2_ploadrifnew_pi(SHORTCODE) \
> -    fGEN_TCG_PRED_LOAD(GET_EA_pi, fLSBNEWNOT(PtN), 4, u)
> -
> -/* Predicated loads into a register pair */
> -#define fGEN_TCG_PRED_LOAD_PAIR(GET_EA, PRED) \
> -    do { \
> -        TCGv LSB = tcg_temp_local_new(); \
> -        TCGLabel *label = gen_new_label(); \
> -        GET_EA; \
> -        PRED;  \
> -        PRED_LOAD_CANCEL(LSB, EA); \
> -        tcg_gen_movi_i64(RddV, 0); \
> -        tcg_gen_brcondi_tl(TCG_COND_EQ, LSB, 0, label); \
> -            fLOAD(1, 8, u, EA, RddV); \
> -        gen_set_label(label); \
> -        tcg_temp_free(LSB); \
> -    } while (0)
> -
> -#define fGEN_TCG_L2_ploadrdt_pi(SHORTCODE) \
> -    fGEN_TCG_PRED_LOAD_PAIR(GET_EA_pi, fLSBOLD(PtV))
> -#define fGEN_TCG_L2_ploadrdf_pi(SHORTCODE) \
> -    fGEN_TCG_PRED_LOAD_PAIR(GET_EA_pi, fLSBOLDNOT(PtV))
> -#define fGEN_TCG_L2_ploadrdtnew_pi(SHORTCODE) \
> -    fGEN_TCG_PRED_LOAD_PAIR(GET_EA_pi, fLSBNEW(PtN))
> -#define fGEN_TCG_L2_ploadrdfnew_pi(SHORTCODE) \
> -    fGEN_TCG_PRED_LOAD_PAIR(GET_EA_pi, fLSBNEWNOT(PtN))
> -
>  /* load-locked and store-locked */
>  #define fGEN_TCG_L2_loadw_locked(SHORTCODE) \
>      SHORTCODE
> @@ -428,95 +53,6 @@
>  #define fGEN_TCG_S4_stored_locked(SHORTCODE) \
>      do { SHORTCODE; READ_PREG(PdV, PdN); } while (0)
>
> -#define fGEN_TCG_STORE(SHORTCODE) \
> -    do { \
> -        TCGv HALF = tcg_temp_new(); \
> -        TCGv BYTE = tcg_temp_new(); \
> -        SHORTCODE; \
> -        tcg_temp_free(HALF); \
> -        tcg_temp_free(BYTE); \
> -    } while (0)
> -
> -#define fGEN_TCG_STORE_pcr(SHIFT, STORE) \
> -    do { \
> -        TCGv ireg = tcg_temp_new(); \
> -        TCGv HALF = tcg_temp_new(); \
> -        TCGv BYTE = tcg_temp_new(); \
> -        tcg_gen_mov_tl(EA, RxV); \
> -        gen_read_ireg(ireg, MuV, SHIFT); \
> -        gen_helper_fcircadd(RxV, RxV, ireg, MuV, hex_gpr[HEX_REG_CS0 +
> MuN]); \
> -        STORE; \
> -        tcg_temp_free(ireg); \
> -        tcg_temp_free(HALF); \
> -        tcg_temp_free(BYTE); \
> -    } while (0)
> -
> -#define fGEN_TCG_S2_storerb_pbr(SHORTCODE) \
> -    fGEN_TCG_STORE(SHORTCODE)
> -#define fGEN_TCG_S2_storerb_pci(SHORTCODE) \
> -    fGEN_TCG_STORE(SHORTCODE)
> -#define fGEN_TCG_S2_storerb_pcr(SHORTCODE) \
> -    fGEN_TCG_STORE_pcr(0, fSTORE(1, 1, EA, fGETBYTE(0, RtV)))
> -
> -#define fGEN_TCG_S2_storerh_pbr(SHORTCODE) \
> -    fGEN_TCG_STORE(SHORTCODE)
> -#define fGEN_TCG_S2_storerh_pci(SHORTCODE) \
> -    fGEN_TCG_STORE(SHORTCODE)
> -#define fGEN_TCG_S2_storerh_pcr(SHORTCODE) \
> -    fGEN_TCG_STORE_pcr(1, fSTORE(1, 2, EA, fGETHALF(0, RtV)))
> -
> -#define fGEN_TCG_S2_storerf_pbr(SHORTCODE) \
> -    fGEN_TCG_STORE(SHORTCODE)
> -#define fGEN_TCG_S2_storerf_pci(SHORTCODE) \
> -    fGEN_TCG_STORE(SHORTCODE)
> -#define fGEN_TCG_S2_storerf_pcr(SHORTCODE) \
> -    fGEN_TCG_STORE_pcr(1, fSTORE(1, 2, EA, fGETHALF(1, RtV)))
> -
> -#define fGEN_TCG_S2_storeri_pbr(SHORTCODE) \
> -    fGEN_TCG_STORE(SHORTCODE)
> -#define fGEN_TCG_S2_storeri_pci(SHORTCODE) \
> -    fGEN_TCG_STORE(SHORTCODE)
> -#define fGEN_TCG_S2_storeri_pcr(SHORTCODE) \
> -    fGEN_TCG_STORE_pcr(2, fSTORE(1, 4, EA, RtV))
> -
> -#define fGEN_TCG_S2_storerd_pbr(SHORTCODE) \
> -    fGEN_TCG_STORE(SHORTCODE)
> -#define fGEN_TCG_S2_storerd_pci(SHORTCODE) \
> -    fGEN_TCG_STORE(SHORTCODE)
> -#define fGEN_TCG_S2_storerd_pcr(SHORTCODE) \
> -    fGEN_TCG_STORE_pcr(3, fSTORE(1, 8, EA, RttV))
> -
> -#define fGEN_TCG_S2_storerbnew_pbr(SHORTCODE) \
> -    fGEN_TCG_STORE(SHORTCODE)
> -#define fGEN_TCG_S2_storerbnew_pci(SHORTCODE) \
> -    fGEN_TCG_STORE(SHORTCODE)
> -#define fGEN_TCG_S2_storerbnew_pcr(SHORTCODE) \
> -    fGEN_TCG_STORE_pcr(0, fSTORE(1, 1, EA, fGETBYTE(0, NtN)))
> -
> -#define fGEN_TCG_S2_storerhnew_pbr(SHORTCODE) \
> -    fGEN_TCG_STORE(SHORTCODE)
> -#define fGEN_TCG_S2_storerhnew_pci(SHORTCODE) \
> -    fGEN_TCG_STORE(SHORTCODE)
> -#define fGEN_TCG_S2_storerhnew_pcr(SHORTCODE) \
> -    fGEN_TCG_STORE_pcr(1, fSTORE(1, 2, EA, fGETHALF(0, NtN)))
> -
> -#define fGEN_TCG_S2_storerinew_pbr(SHORTCODE) \
> -    fGEN_TCG_STORE(SHORTCODE)
> -#define fGEN_TCG_S2_storerinew_pci(SHORTCODE) \
> -    fGEN_TCG_STORE(SHORTCODE)
> -#define fGEN_TCG_S2_storerinew_pcr(SHORTCODE) \
> -    fGEN_TCG_STORE_pcr(2, fSTORE(1, 4, EA, NtN))
> -
> -/*
> - * Mathematical operations with more than one definition require
> - * special handling
> - */
> -#define fGEN_TCG_A5_ACS(SHORTCODE) \
> -    do { \
> -        gen_helper_vacsh_pred(PeV, cpu_env, RxxV, RssV, RttV); \
> -        gen_helper_vacsh_val(RxxV, cpu_env, RxxV, RssV, RttV); \
> -    } while (0)
> -
>  /*
>   * Approximate reciprocal
>   * r3,p1 = sfrecipa(r0, r1)
> @@ -549,70 +85,6 @@
>          tcg_temp_free_i64(tmp); \
>      } while (0)
>
> -/*
> - * Add or subtract with carry.
> - * Predicate register is used as an extra input and output.
> - * r5:4 = add(r1:0, r3:2, p1):carry
> - */
> -#define fGEN_TCG_A4_addp_c(SHORTCODE) \
> -    do { \
> -        TCGv_i64 carry = tcg_temp_new_i64(); \
> -        TCGv_i64 zero = tcg_const_i64(0); \
> -        tcg_gen_extu_i32_i64(carry, PxV); \
> -        tcg_gen_andi_i64(carry, carry, 1); \
> -        tcg_gen_add2_i64(RddV, carry, RssV, zero, carry, zero); \
> -        tcg_gen_add2_i64(RddV, carry, RddV, carry, RttV, zero); \
> -        tcg_gen_extrl_i64_i32(PxV, carry); \
> -        gen_8bitsof(PxV, PxV); \
> -        tcg_temp_free_i64(carry); \
> -        tcg_temp_free_i64(zero); \
> -    } while (0)
> -
> -/* r5:4 = sub(r1:0, r3:2, p1):carry */
> -#define fGEN_TCG_A4_subp_c(SHORTCODE) \
> -    do { \
> -        TCGv_i64 carry = tcg_temp_new_i64(); \
> -        TCGv_i64 zero = tcg_const_i64(0); \
> -        TCGv_i64 not_RttV = tcg_temp_new_i64(); \
> -        tcg_gen_extu_i32_i64(carry, PxV); \
> -        tcg_gen_andi_i64(carry, carry, 1); \
> -        tcg_gen_not_i64(not_RttV, RttV); \
> -        tcg_gen_add2_i64(RddV, carry, RssV, zero, carry, zero); \
> -        tcg_gen_add2_i64(RddV, carry, RddV, carry, not_RttV, zero); \
> -        tcg_gen_extrl_i64_i32(PxV, carry); \
> -        gen_8bitsof(PxV, PxV); \
> -        tcg_temp_free_i64(carry); \
> -        tcg_temp_free_i64(zero); \
> -        tcg_temp_free_i64(not_RttV); \
> -    } while (0)
> -
> -/*
> - * Compare each of the 8 unsigned bytes
> - * The minimum is placed in each byte of the destination.
> - * Each bit of the predicate is set true if the bit from the first operand
> - * is greater than the bit from the second operand.
> - * r5:4,p1 = vminub(r1:0, r3:2)
> - */
> -#define fGEN_TCG_A6_vminub_RdP(SHORTCODE) \
> -    do { \
> -        TCGv left = tcg_temp_new(); \
> -        TCGv right = tcg_temp_new(); \
> -        TCGv tmp = tcg_temp_new(); \
> -        tcg_gen_movi_tl(PeV, 0); \
> -        tcg_gen_movi_i64(RddV, 0); \
> -        for (int i = 0; i < 8; i++) { \
> -            gen_get_byte_i64(left, i, RttV, false); \
> -            gen_get_byte_i64(right, i, RssV, false); \
> -            tcg_gen_setcond_tl(TCG_COND_GT, tmp, left, right); \
> -            tcg_gen_deposit_tl(PeV, PeV, tmp, i, 1); \
> -            tcg_gen_umin_tl(tmp, left, right); \
> -            gen_set_byte_i64(i, RddV, tmp); \
> -        } \
> -        tcg_temp_free(left); \
> -        tcg_temp_free(right); \
> -        tcg_temp_free(tmp); \
> -    } while (0)
> -
>  /* Floating point */
>  #define fGEN_TCG_F2_conv_sf2df(SHORTCODE) \
>      gen_helper_conv_sf2df(RddV, cpu_env, RsV)
> diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
> index cf45c28f58..0e8378ac57 100644
> --- a/target/hexagon/genptr.c
> +++ b/target/hexagon/genptr.c
> @@ -274,61 +274,6 @@ static inline void
> gen_write_ctrl_reg_pair(DisasContext *ctx, int reg_num,
>      }
>  }
>
> -static TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign)
> -{
> -    if (sign) {
> -        tcg_gen_sextract_tl(result, src, N * 8, 8);
> -    } else {
> -        tcg_gen_extract_tl(result, src, N * 8, 8);
> -    }
> -    return result;
> -}
> -
> -static TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign)
> -{
> -    TCGv_i64 res64 = tcg_temp_new_i64();
> -    if (sign) {
> -        tcg_gen_sextract_i64(res64, src, N * 8, 8);
> -    } else {
> -        tcg_gen_extract_i64(res64, src, N * 8, 8);
> -    }
> -    tcg_gen_extrl_i64_i32(result, res64);
> -    tcg_temp_free_i64(res64);
> -
> -    return result;
> -}
> -
> -static inline TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign)
> -{
> -    if (sign) {
> -        tcg_gen_sextract_tl(result, src, N * 16, 16);
> -    } else {
> -        tcg_gen_extract_tl(result, src, N * 16, 16);
> -    }
> -    return result;
> -}
> -
> -static inline void gen_set_half(int N, TCGv result, TCGv src)
> -{
> -    tcg_gen_deposit_tl(result, result, src, N * 16, 16);
> -}
> -
> -static inline void gen_set_half_i64(int N, TCGv_i64 result, TCGv src)
> -{
> -    TCGv_i64 src64 = tcg_temp_new_i64();
> -    tcg_gen_extu_i32_i64(src64, src);
> -    tcg_gen_deposit_i64(result, result, src64, N * 16, 16);
> -    tcg_temp_free_i64(src64);
> -}
> -
> -static void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src)
> -{
> -    TCGv_i64 src64 = tcg_temp_new_i64();
> -    tcg_gen_extu_i32_i64(src64, src);
> -    tcg_gen_deposit_i64(result, result, src64, N * 8, 8);
> -    tcg_temp_free_i64(src64);
> -}
> -
>  static inline void gen_load_locked4u(TCGv dest, TCGv vaddr, int mem_index)
>  {
>      tcg_gen_qemu_ld32u(dest, vaddr, mem_index);
> @@ -417,42 +362,18 @@ void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv
> src, DisasContext *ctx,
>      gen_store32(ctx, vaddr, src, 1, slot);
>  }
>
> -static inline void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
> -                               DisasContext *ctx, int slot)
> -{
> -    TCGv tmp = tcg_const_tl(src);
> -    gen_store1(cpu_env, vaddr, tmp, ctx, slot);
> -    tcg_temp_free(tmp);
> -}
> -
>  void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
>                  unsigned slot)
>  {
>      gen_store32(ctx, vaddr, src, 2, slot);
>  }
>
> -static inline void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
> -                               DisasContext *ctx, int slot)
> -{
> -    TCGv tmp = tcg_const_tl(src);
> -    gen_store2(cpu_env, vaddr, tmp, ctx, slot);
> -    tcg_temp_free(tmp);
> -}
> -
>  void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
>                  unsigned slot)
>  {
>      gen_store32(ctx, vaddr, src, 4, slot);
>  }
>
> -static inline void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
> -                               DisasContext *ctx, int slot)
> -{
> -    TCGv tmp = tcg_const_tl(src);
> -    gen_store4(cpu_env, vaddr, tmp, ctx, slot);
> -    tcg_temp_free(tmp);
> -}
> -
>  void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src, DisasContext
> *ctx,
>                  unsigned slot)
>  {
> @@ -462,25 +383,6 @@ void gen_store8(TCGv_env cpu_env, TCGv vaddr,
> TCGv_i64 src, DisasContext *ctx,
>      ctx->store_width[slot] = 8;
>  }
>
> -static inline void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src,
> -                               DisasContext *ctx, int slot)
> -{
> -    TCGv_i64 tmp = tcg_const_i64(src);
> -    gen_store8(cpu_env, vaddr, tmp, ctx, slot);
> -    tcg_temp_free_i64(tmp);
> -}
> -
> -static TCGv gen_8bitsof(TCGv result, TCGv value)
> -{
> -    TCGv zero = tcg_const_tl(0);
> -    TCGv ones = tcg_const_tl(0xff);
> -    tcg_gen_movcond_tl(TCG_COND_NE, result, value, zero, ones, zero);
> -    tcg_temp_free(zero);
> -    tcg_temp_free(ones);
> -
> -    return result;
> -}
> -
>  void gen_set_usr_field(int field, TCGv val)
>  {
>      tcg_gen_deposit_tl(hex_gpr[HEX_REG_USR], hex_gpr[HEX_REG_USR], val,
> diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h
> index 7d09501844..56d33dc144 100644
> --- a/target/hexagon/macros.h
> +++ b/target/hexagon/macros.h
> @@ -67,105 +67,7 @@
>                   reg_field_info[FIELD].offset, (VAL))
>  #endif
>
> -#ifdef QEMU_GENERATE
> -/*
> - * Section 5.5 of the Hexagon V67 Programmer's Reference Manual
> - *
> - * Slot 1 store with slot 0 load
> - * A slot 1 store operation with a slot 0 load operation can appear in a
> packet.
> - * The packet attribute :mem_noshuf inhibits the instruction reordering
> that
> - * would otherwise be done by the assembler. For example:
> - *     {
> - *         memw(R5) = R2 // slot 1 store
> - *         R3 = memh(R6) // slot 0 load
> - *     }:mem_noshuf
> - * Unlike most packetized operations, these memory operations are not
> executed
> - * in parallel (Section 3.3.1). Instead, the store instruction in Slot 1
> - * effectively executes first, followed by the load instruction in Slot
> 0. If
> - * the addresses of the two operations are overlapping, the load will
> receive
> - * the newly stored data. This feature is supported in processor versions
> - * V65 or greater.
> - *
> - *
> - * For qemu, we look for a load in slot 0 when there is  a store in slot 1
> - * in the same packet.  When we see this, we call a helper that merges the
> - * bytes from the store buffer with the value loaded from memory.
> - */
> -#define CHECK_NOSHUF \
> -    do { \
> -        if (insn->slot == 0 && pkt->pkt_has_store_s1) { \
> -            process_store(ctx, pkt, 1); \
> -        } \
> -    } while (0)
> -
> -#define MEM_LOAD1s(DST, VA) \
> -    do { \
> -        CHECK_NOSHUF; \
> -        tcg_gen_qemu_ld8s(DST, VA, ctx->mem_idx); \
> -    } while (0)
> -#define MEM_LOAD1u(DST, VA) \
> -    do { \
> -        CHECK_NOSHUF; \
> -        tcg_gen_qemu_ld8u(DST, VA, ctx->mem_idx); \
> -    } while (0)
> -#define MEM_LOAD2s(DST, VA) \
> -    do { \
> -        CHECK_NOSHUF; \
> -        tcg_gen_qemu_ld16s(DST, VA, ctx->mem_idx); \
> -    } while (0)
> -#define MEM_LOAD2u(DST, VA) \
> -    do { \
> -        CHECK_NOSHUF; \
> -        tcg_gen_qemu_ld16u(DST, VA, ctx->mem_idx); \
> -    } while (0)
> -#define MEM_LOAD4s(DST, VA) \
> -    do { \
> -        CHECK_NOSHUF; \
> -        tcg_gen_qemu_ld32s(DST, VA, ctx->mem_idx); \
> -    } while (0)
> -#define MEM_LOAD4u(DST, VA) \
> -    do { \
> -        CHECK_NOSHUF; \
> -        tcg_gen_qemu_ld32s(DST, VA, ctx->mem_idx); \
> -    } while (0)
> -#define MEM_LOAD8u(DST, VA) \
> -    do { \
> -        CHECK_NOSHUF; \
> -        tcg_gen_qemu_ld64(DST, VA, ctx->mem_idx); \
> -    } while (0)
> -
> -#define MEM_STORE1_FUNC(X) \
> -    __builtin_choose_expr(TYPE_INT(X), \
> -        gen_store1i, \
> -        __builtin_choose_expr(TYPE_TCGV(X), \
> -            gen_store1, (void)0))
> -#define MEM_STORE1(VA, DATA, SLOT) \
> -    MEM_STORE1_FUNC(DATA)(cpu_env, VA, DATA, ctx, SLOT)
> -
> -#define MEM_STORE2_FUNC(X) \
> -    __builtin_choose_expr(TYPE_INT(X), \
> -        gen_store2i, \
> -        __builtin_choose_expr(TYPE_TCGV(X), \
> -            gen_store2, (void)0))
> -#define MEM_STORE2(VA, DATA, SLOT) \
> -    MEM_STORE2_FUNC(DATA)(cpu_env, VA, DATA, ctx, SLOT)
> -
> -#define MEM_STORE4_FUNC(X) \
> -    __builtin_choose_expr(TYPE_INT(X), \
> -        gen_store4i, \
> -        __builtin_choose_expr(TYPE_TCGV(X), \
> -            gen_store4, (void)0))
> -#define MEM_STORE4(VA, DATA, SLOT) \
> -    MEM_STORE4_FUNC(DATA)(cpu_env, VA, DATA, ctx, SLOT)
> -
> -#define MEM_STORE8_FUNC(X) \
> -    __builtin_choose_expr(TYPE_INT(X), \
> -        gen_store8i, \
> -        __builtin_choose_expr(TYPE_TCGV_I64(X), \
> -            gen_store8, (void)0))
> -#define MEM_STORE8(VA, DATA, SLOT) \
> -    MEM_STORE8_FUNC(DATA)(cpu_env, VA, DATA, ctx, SLOT)
> -#else
> +#ifndef QEMU_GENERATE
>  #define MEM_LOAD1s(VA) ((int8_t)mem_load1(env, slot, VA))
>  #define MEM_LOAD1u(VA) ((uint8_t)mem_load1(env, slot, VA))
>  #define MEM_LOAD2s(VA) ((int16_t)mem_load2(env, slot, VA))
> @@ -194,26 +96,6 @@ static inline void gen_cancel(unsigned slot)
>
>  #define LOAD_CANCEL(EA) do { CANCEL; } while (0)
>
> -#ifdef QEMU_GENERATE
> -static inline void gen_pred_cancel(TCGv pred, unsigned slot_num)
> - {
> -    TCGv slot_mask = tcg_const_tl(1 << slot_num);
> -    TCGv tmp = tcg_temp_new();
> -    TCGv zero = tcg_const_tl(0);
> -    TCGv one = tcg_const_tl(1);
> -    tcg_gen_or_tl(slot_mask, hex_slot_cancelled, slot_mask);
> -    tcg_gen_andi_tl(tmp, pred, 1);
> -    tcg_gen_movcond_tl(TCG_COND_EQ, hex_slot_cancelled, tmp, zero,
> -                       slot_mask, hex_slot_cancelled);
> -    tcg_temp_free(slot_mask);
> -    tcg_temp_free(tmp);
> -    tcg_temp_free(zero);
> -    tcg_temp_free(one);
> -}
> -#define PRED_LOAD_CANCEL(PRED, EA) \
> -    gen_pred_cancel(PRED, insn->is_endloop ? 4 : insn->slot)
> -#endif
> -
>  #define STORE_CANCEL(EA) { env->slot_cancelled |= (1 << slot); }
>
>  #define fMAX(A, B) (((A) > (B)) ? (A) : (B))
> @@ -241,41 +123,17 @@ static inline void gen_pred_cancel(TCGv pred,
> unsigned slot_num)
>
>  #define f8BITSOF(VAL) ((VAL) ? 0xff : 0x00)
>
> -#ifdef QEMU_GENERATE
> -#define fLSBOLD(VAL) tcg_gen_andi_tl(LSB, (VAL), 1)
> -#else
> +#ifndef QEMU_GENERATE
>  #define fLSBOLD(VAL)  ((VAL) & 1)
>  #endif
>
> -#ifdef QEMU_GENERATE
> -#define fLSBNEW(PVAL)   tcg_gen_mov_tl(LSB, (PVAL))
> -#define fLSBNEW0        tcg_gen_mov_tl(LSB, hex_new_pred_value[0])
> -#define fLSBNEW1        tcg_gen_mov_tl(LSB, hex_new_pred_value[1])
> -#else
> +#ifndef QEMU_GENERATE
>  #define fLSBNEW(PVAL)   (PVAL)
>  #define fLSBNEW0        new_pred_value(env, 0)
>  #define fLSBNEW1        new_pred_value(env, 1)
>  #endif
>
> -#ifdef QEMU_GENERATE
> -static inline void gen_logical_not(TCGv dest, TCGv src)
> -{
> -    TCGv one = tcg_const_tl(1);
> -    TCGv zero = tcg_const_tl(0);
> -
> -    tcg_gen_movcond_tl(TCG_COND_NE, dest, src, zero, zero, one);
> -
> -    tcg_temp_free(one);
> -    tcg_temp_free(zero);
> -}
> -#define fLSBOLDNOT(VAL) \
> -    do { \
> -        tcg_gen_andi_tl(LSB, (VAL), 1); \
> -        tcg_gen_xori_tl(LSB, LSB, 1); \
> -    } while (0)
> -#define fLSBNEWNOT(PNUM) \
> -    gen_logical_not(LSB, (PNUM))
> -#else
> +#ifndef QEMU_GENERATE
>  #define fLSBNEWNOT(PNUM) (!fLSBNEW(PNUM))
>  #define fLSBOLDNOT(VAL) (!fLSBOLD(VAL))
>  #define fLSBNEW0NOT (!fLSBNEW0)
> @@ -481,21 +339,7 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv
> val, int shift)
>  #define fCAST8S_16S(A) (int128_exts64(A))
>  #define fCAST16S_8S(A) (int128_getlo(A))
>
> -#ifdef QEMU_GENERATE
> -#define fEA_RI(REG, IMM) tcg_gen_addi_tl(EA, REG, IMM)
> -#define fEA_RRs(REG, REG2, SCALE) \
> -    do { \
> -        TCGv tmp = tcg_temp_new(); \
> -        tcg_gen_shli_tl(tmp, REG2, SCALE); \
> -        tcg_gen_add_tl(EA, REG, tmp); \
> -        tcg_temp_free(tmp); \
> -    } while (0)
> -#define fEA_IRs(IMM, REG, SCALE) \
> -    do { \
> -        tcg_gen_shli_tl(EA, REG, SCALE); \
> -        tcg_gen_addi_tl(EA, EA, IMM); \
> -    } while (0)
> -#else
> +#ifndef QEMU_GENERATE
>  #define fEA_RI(REG, IMM) \
>      do { \
>          EA = REG + IMM; \
> @@ -511,18 +355,7 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv
> val, int shift)
>  #endif
>
>  #ifdef QEMU_GENERATE
> -#define fEA_IMM(IMM) tcg_gen_movi_tl(EA, IMM)
>  #define fEA_REG(REG) tcg_gen_mov_tl(EA, REG)
> -#define fEA_BREVR(REG)      gen_helper_fbrev(EA, REG)
> -#define fPM_I(REG, IMM)     tcg_gen_addi_tl(REG, REG, IMM)
> -#define fPM_M(REG, MVAL)    tcg_gen_add_tl(REG, REG, MVAL)
> -#define fPM_CIRI(REG, IMM, MVAL) \
> -    do { \
> -        TCGv tcgv_siV = tcg_const_tl(siV); \
> -        gen_helper_fcircadd(REG, REG, tcgv_siV, MuV, \
> -                            hex_gpr[HEX_REG_CS0 + MuN]); \
> -        tcg_temp_free(tcgv_siV); \
> -    } while (0)
>  #else
>  #define fEA_IMM(IMM)        do { EA = (IMM); } while (0)
>  #define fEA_REG(REG)        do { EA = (REG); } while (0)
> @@ -574,9 +407,7 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv
> val, int shift)
>  #define fASHIFTL(SRC, SHAMT, REGSTYPE) \
>      (((SHAMT) >= (sizeof(SRC) * 8)) ? 0 : (fCAST##REGSTYPE##s(SRC) <<
> (SHAMT)))
>
> -#ifdef QEMU_GENERATE
> -#define fLOAD(NUM, SIZE, SIGN, EA, DST) MEM_LOAD##SIZE##SIGN(DST, EA)
> -#else
> +#ifndef QEMU_GENERATE
>  #define fLOAD(NUM, SIZE, SIGN, EA, DST) \
>      DST = (size##SIZE##SIGN##_t)MEM_LOAD##SIZE##SIGN(EA)
>  #endif
> @@ -599,9 +430,7 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv
> val, int shift)
>      gen_load_locked##SIZE##SIGN(DST, EA, ctx->mem_idx);
>  #endif
>
> -#ifdef QEMU_GENERATE
> -#define fSTORE(NUM, SIZE, EA, SRC) MEM_STORE##SIZE(EA, SRC, insn->slot)
> -#else
> +#ifndef QEMU_GENERATE
>  #define fSTORE(NUM, SIZE, EA, SRC) MEM_STORE##SIZE(EA, SRC, slot)
>  #endif
>
> @@ -610,15 +439,7 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv
> val, int shift)
>      gen_store_conditional##SIZE(env, ctx, PdN, PRED, EA, SRC);
>  #endif
>
> -#ifdef QEMU_GENERATE
> -#define GETBYTE_FUNC(X) \
> -    __builtin_choose_expr(TYPE_TCGV(X), \
> -        gen_get_byte, \
> -        __builtin_choose_expr(TYPE_TCGV_I64(X), \
> -            gen_get_byte_i64, (void)0))
> -#define fGETBYTE(N, SRC) GETBYTE_FUNC(SRC)(BYTE, N, SRC, true)
> -#define fGETUBYTE(N, SRC) GETBYTE_FUNC(SRC)(BYTE, N, SRC, false)
> -#else
> +#ifndef QEMU_GENERATE
>  #define fGETBYTE(N, SRC) ((int8_t)((SRC >> ((N) * 8)) & 0xff))
>  #define fGETUBYTE(N, SRC) ((uint8_t)((SRC >> ((N) * 8)) & 0xff))
>  #endif
> @@ -629,10 +450,7 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv
> val, int shift)
>          (((uint64_t)((VAL) & 0x0ffLL)) << ((N) * 8)); \
>      } while (0)
>
> -#ifdef QEMU_GENERATE
> -#define fGETHALF(N, SRC)  gen_get_half(HALF, N, SRC, true)
> -#define fGETUHALF(N, SRC) gen_get_half(HALF, N, SRC, false)
> -#else
> +#ifndef QEMU_GENERATE
>  #define fGETHALF(N, SRC) ((int16_t)((SRC >> ((N) * 16)) & 0xffff))
>  #define fGETUHALF(N, SRC) ((uint16_t)((SRC >> ((N) * 16)) & 0xffff))
>  #endif
> diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
> index 63dd685658..496975a394 100644
> --- a/target/hexagon/op_helper.c
> +++ b/target/hexagon/op_helper.c
> @@ -45,23 +45,6 @@ void QEMU_NORETURN
> HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp)
>      do_raise_exception_err(env, excp, 0);
>  }
>
> -static void log_reg_write(CPUHexagonState *env, int rnum,
> -                          target_ulong val, uint32_t slot)
> -{
> -    HEX_DEBUG_LOG("log_reg_write[%d] = " TARGET_FMT_ld " (0x"
> TARGET_FMT_lx ")",
> -                  rnum, val, val);
> -    if (val == env->gpr[rnum]) {
> -        HEX_DEBUG_LOG(" NO CHANGE");
> -    }
> -    HEX_DEBUG_LOG("\n");
> -
> -    env->new_value[rnum] = val;
> -    if (HEX_DEBUG) {
> -        /* Do this so HELPER(debug_commit_end) will know */
> -        env->reg_written[rnum] = 1;
> -    }
> -}
> -
>  static void log_pred_write(CPUHexagonState *env, int pnum, target_ulong
> val)
>  {
>      HEX_DEBUG_LOG("log_pred_write[%d] = " TARGET_FMT_ld
> @@ -77,46 +60,6 @@ static void log_pred_write(CPUHexagonState *env, int
> pnum, target_ulong val)
>      }
>  }
>
> -static void log_store32(CPUHexagonState *env, target_ulong addr,
> -                        target_ulong val, int width, int slot)
> -{
> -    HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
> -                  ", %" PRId32 " [0x08%" PRIx32 "])\n",
> -                  width, addr, val, val);
> -    env->mem_log_stores[slot].va = addr;
> -    env->mem_log_stores[slot].width = width;
> -    env->mem_log_stores[slot].data32 = val;
> -}
> -
> -static void log_store64(CPUHexagonState *env, target_ulong addr,
> -                        int64_t val, int width, int slot)
> -{
> -    HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
> -                  ", %" PRId64 " [0x016%" PRIx64 "])\n",
> -                   width, addr, val, val);
> -    env->mem_log_stores[slot].va = addr;
> -    env->mem_log_stores[slot].width = width;
> -    env->mem_log_stores[slot].data64 = val;
> -}
> -
> -static void write_new_pc(CPUHexagonState *env, target_ulong addr)
> -{
> -    HEX_DEBUG_LOG("write_new_pc(0x" TARGET_FMT_lx ")\n", addr);
> -
> -    /*
> -     * If more than one branch is taken in a packet, only the first one
> -     * is actually done.
> -     */
> -    if (env->branch_taken) {
> -        HEX_DEBUG_LOG("INFO: multiple branches taken in same packet, "
> -                      "ignoring the second one\n");
> -    } else {
> -        fCHECK_PCALIGN(addr);
> -        env->branch_taken = 1;
> -        env->next_PC = addr;
> -    }
> -}
> -
>  /* Handy place to set a breakpoint */
>  void HELPER(debug_start_packet)(CPUHexagonState *env)
>  {
> @@ -128,11 +71,6 @@ void HELPER(debug_start_packet)(CPUHexagonState *env)
>      }
>  }
>
> -static int32_t new_pred_value(CPUHexagonState *env, int pnum)
> -{
> -    return env->new_pred_value[pnum];
> -}
> -
>  /* Checks for bookkeeping errors between disassembly context and runtime
> */
>  void HELPER(debug_check_store_width)(CPUHexagonState *env, int slot, int
> check)
>  {
> @@ -380,57 +318,6 @@ int32_t HELPER(vacsh_pred)(CPUHexagonState *env,
>      return PeV;
>  }
>
> -/*
> - * mem_noshuf
> - * Section 5.5 of the Hexagon V67 Programmer's Reference Manual
> - *
> - * If the load is in slot 0 and there is a store in slot1 (that
> - * wasn't cancelled), we have to do the store first.
> - */
> -static void check_noshuf(CPUHexagonState *env, uint32_t slot)
> -{
> -    if (slot == 0 && env->pkt_has_store_s1 &&
> -        ((env->slot_cancelled & (1 << 1)) == 0)) {
> -        HELPER(commit_store)(env, 1);
> -    }
> -}
> -
> -static uint8_t mem_load1(CPUHexagonState *env, uint32_t slot,
> -                         target_ulong vaddr)
> -{
> -    uint8_t retval;
> -    check_noshuf(env, slot);
> -    get_user_u8(retval, vaddr);
> -    return retval;
> -}
> -
> -static uint16_t mem_load2(CPUHexagonState *env, uint32_t slot,
> -                          target_ulong vaddr)
> -{
> -    uint16_t retval;
> -    check_noshuf(env, slot);
> -    get_user_u16(retval, vaddr);
> -    return retval;
> -}
> -
> -static uint32_t mem_load4(CPUHexagonState *env, uint32_t slot,
> -                          target_ulong vaddr)
> -{
> -    uint32_t retval;
> -    check_noshuf(env, slot);
> -    get_user_u32(retval, vaddr);
> -    return retval;
> -}
> -
> -static uint64_t mem_load8(CPUHexagonState *env, uint32_t slot,
> -                          target_ulong vaddr)
> -{
> -    uint64_t retval;
> -    check_noshuf(env, slot);
> -    get_user_u64(retval, vaddr);
> -    return retval;
> -}
> -
>  /* Floating point */
>  float64 HELPER(conv_sf2df)(CPUHexagonState *env, float32 RsV)
>  {
> @@ -1172,12 +1059,6 @@ float64 HELPER(dfmpyhh)(CPUHexagonState *env,
> float64 RxxV,
>      return RxxV;
>  }
>
> -static void cancel_slot(CPUHexagonState *env, uint32_t slot)
> -{
> -    HEX_DEBUG_LOG("Slot %d cancelled\n", slot);
> -    env->slot_cancelled |= (1 << slot);
> -}
> -
>  /* These macros can be referenced in the generated helper functions */
>  #define warn(...) /* Nothing */
>  #define fatal(...) g_assert_not_reached();
> --
> 2.31.1
>
>
>

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

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

* Re: [PATCH v5 13/14] target/hexagon: import additional tests
  2021-06-19  9:37 ` [PATCH v5 13/14] target/hexagon: import additional tests Alessandro Di Federico via
@ 2021-06-25 23:56   ` Taylor Simpson
  2021-06-28 22:39     ` Taylor Simpson
  2021-07-05 16:50     ` Alessandro Di Federico via
  0 siblings, 2 replies; 38+ messages in thread
From: Taylor Simpson @ 2021-06-25 23:56 UTC (permalink / raw)
  To: Alessandro Di Federico
  Cc: Alessandro Di Federico, bcain, richard.henderson, qemu-devel,
	babush, tsimpson, nizzo, philmd

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

On Sat, Jun 19, 2021 at 4:49 AM Alessandro Di Federico via <
qemu-devel@nongnu.org> wrote:

> From: Niccolò Izzo <nizzo@rev.ng>
>
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Niccolò Izzo <nizzo@rev.ng>
> ---
>


> diff --git a/tests/tcg/hexagon/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
> +    }
>

You don't need to alloc/dealloc the frame, just a single packet { r0 =
#256; jumpr r31 }

Then again, why is this function needed at all?


+
> +    .space 240
>

Why is this space needed?

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

This is already tested in misc.c

+
> +    .text
> +    .globl _start
> +
> +_start:
> +    {
> +        r1+=sub(r2,r3)
>

Remove this - r1, r2, and r3 are uninitialized.  Then, you overwrite r1 in
the next packet.


> +        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_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; }
>

Assign to r0 directly


> +    {
> +        r2=#256
> +    }
> +    { r1=r2; }
>

Assign to r1 directly

+    { trap0(#7); }
>

This doesn't print anything - the syscall number goes in r6.  Is the intent
to invoke SYS_write?  If so, look at first.S to see how this is done.

+    {
> +        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_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.
> + */
>

How does 0xDEADBEEF get into r2?

Do we need this test given that every other test relies on this idiom to
check pass/fail?

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

CPU dump sounds like something you have locally.  The check-tcg tests
should not rely on this.

+    .text
> +    .globl _start
> +
> +_start:
> +    {
> +        call init
> +    }
> +    {
> +        r0=#1
> +        memw(sp+#0)=r0.new
> +    }
>

You haven't set up the stack, so you shouldn't use sp.  Even if the stack
were set up, you should allocframe first.

+    {
> +        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).
> + */
>

 This is already tested in dual_stores.c

+
> +    .text
> +    .globl _start
> +
> +_start:
> +    {
> +        call init
> +    }
> +    {
> +        r0=#1
> +        r1=#2
> +    }
> +    {
> +        memw(sp+#0)=r0
> +        memw(sp+#0)=r1
> +    }
>

Stack setup ...

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

The CPU dump comment doesn't apply


> + */
> +
> +    .text
> +    .globl _start
> +
> +_start:
> +    {
> +        call init
> +    }
> +    {
> +        r2=##-559038737
> +    }
> +    {
> +        p0 = cmp.eq(r2, ##-559038737); if (p0.new) jump:t pass
> +        jump fail
> +    }
>


> +++ b/tests/tcg/hexagon/test_hello.S
> @@ -0,0 +1,21 @@
> +/* Purpose: simple hello world program. */
>

This is already tested in first.S

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

This doesn't actually print anything.


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

What value does this test have beyond the others in this set?

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

Stack problem

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

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

Each of these are very small, so I recommend putting them into misc.c or
combine all the assembly into a small number of executables.

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

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

* Re: [PATCH v5 13/14] target/hexagon: import additional tests
  2021-06-25 23:56   ` Taylor Simpson
@ 2021-06-28 22:39     ` Taylor Simpson
  2021-07-05 16:50     ` Alessandro Di Federico via
  1 sibling, 0 replies; 38+ messages in thread
From: Taylor Simpson @ 2021-06-28 22:39 UTC (permalink / raw)
  To: Alessandro Di Federico
  Cc: Alessandro Di Federico, bcain, richard.henderson, qemu-devel,
	babush, tsimpson, nizzo, philmd

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

On Fri, Jun 25, 2021 at 6:56 PM Taylor Simpson <taylor.qemu@gmail.com>
wrote:

>
>
> On Sat, Jun 19, 2021 at 4:49 AM Alessandro Di Federico via <
> qemu-devel@nongnu.org> wrote:
>
>> From: Niccolò Izzo <nizzo@rev.ng>
>>
>> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
>> Signed-off-by: Niccolò Izzo <nizzo@rev.ng>
>> ---
>>
>
>
>
> +    .text
>> +    .globl _start
>> +
>> +_start:
>> +    {
>> +        call init
>> +    }
>> +    {
>> +        r0=#1
>> +        memw(sp+#0)=r0.new
>> +    }
>>
>
> You haven't set up the stack, so you shouldn't use sp.  Even if the stack
> were set up, you should allocframe first.
>
>
My apologies - the stack *is* set up in linux-user mode.  So, it is OK to
reference sp after you do an allocframe.

You can disregard the other comments in the review about setting up the
stack.


Thanks,
Taylor

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

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

* Re: [PATCH v5 14/14] gitlab-ci: do not use qemu-project Docker registry
  2021-06-19  9:37 ` [PATCH v5 14/14] gitlab-ci: do not use qemu-project Docker registry Alessandro Di Federico via
@ 2021-06-29 14:26   ` Alessandro Di Federico via
  2021-06-29 14:37   ` Daniel P. Berrangé
  1 sibling, 0 replies; 38+ messages in thread
From: Alessandro Di Federico via @ 2021-06-29 14:26 UTC (permalink / raw)
  To: qemu-devel, alex.bennee
  Cc: tsimpson, bcain, babush, nizzo, philmd, richard.henderson

On Sat, 19 Jun 2021 11:37:13 +0200
Alessandro Di Federico <ale.qemu@rev.ng> wrote:

> From: Alessandro Di Federico <ale@rev.ng>
> 
> This commit is necessary in order to use container built by the
> current run of the CI. If we don't do this, we use official
> containers which are not affected by the additional dependencies
> we're introducing.
> 
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>

Alex, what do you think about this?

-- 
Alessandro Di Federico
rev.ng


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

* Re: [PATCH v5 10/14] target/hexagon: import parser for idef-parser
  2021-06-24  3:55   ` Taylor Simpson
@ 2021-06-29 14:26     ` Alessandro Di Federico via
  2021-06-30 16:51     ` Paolo Montesel
  2021-07-05 16:47     ` Alessandro Di Federico via
  2 siblings, 0 replies; 38+ messages in thread
From: Alessandro Di Federico via @ 2021-06-29 14:26 UTC (permalink / raw)
  To: qemu-devel
  Cc: Taylor Simpson, Brian Cain, babush, nizzo, philmd, richard.henderson

On Thu, 24 Jun 2021 03:55:35 +0000
Taylor Simpson <tsimpson@quicinc.com> wrote:

> > +       | rvalue '[' rvalue ']'
> > +         {
> > +             @1.last_column = @4.last_column;
> > +             if ($3.type == IMMEDIATE) {
> > +                 $$ = gen_tmp(c, &@1, $1.bit_width);
> > +                 OUT(c, &@1, "tcg_gen_extract_i", &$$.bit_width,
> > "(");
> > +                 OUT(c, &@1, &$$, ", ", &$1, ", ", &$3, ", 1);\n");
> > +             } else {
> > +                 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);  
> 
> Can this be done with a tcg_gen_extract_tl or tcg_gen_sextract_tl?

Those require translation-time constants as offsets while we need TCGv:

    tcg_gen_extract_i32(TCGv_i32 ret,
                        TCGv_i32 arg,
                        unsigned int ofs,
                        unsigned int len);

> Do you need to worry about signed-ness?

`gen_bin_op` should take care of that.

On Thu, 24 Jun 2021 03:55:35 +0000
Taylor Simpson <tsimpson@quicinc.com> wrote:

> > +void imm_print(Context *c, YYLTYPE *locp, HexImm *imm)
> > +{
> > +    switch (imm->type) {
> > +    case I:
> > +        EMIT(c, "i");
> > +        break;
> > +    case VARIABLE:
> > +        EMIT(c, "%ciV", imm->id);
> > +        break;
> > +    case VALUE:
> > +        EMIT(c, "((int64_t)%" PRIu64 "ULL)", (int64_t)imm->value);
> > +        break;
> > +    case QEMU_TMP:
> > +        EMIT(c, "qemu_tmp_%" PRIu64, imm->index);
> > +        break;
> > +    case IMM_PC:
> > +        EMIT(c, "ctx->base.pc_next");
> > +        break;
> > +    case IMM_NPC:
> > +        EMIT(c, "ctx->npc");
> > +        break;
> > +    case IMM_CONSTEXT:
> > +        EMIT(c, "insn->extension_valid");  
> 
> The extension_valid field is a bool indicating if the instruction has
> a constant extender.  Don't you want the actual value here?

No, this maps to Constant_extended:

    #define fREAD_GP() (Constant_extended ? (0) : GP)

Constant extensions is handle for us externally.

On Thu, 24 Jun 2021 03:55:35 +0000
Taylor Simpson <tsimpson@quicinc.com> wrote:

> > +    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)  
> 
> What's the difference between this and the gen_rdeposit_op above?

`gen_rdeposit_op` is general purpose, it takes start and width of the
deposit.
`gen_deposit_op` is more tailored to handle `fINSERT_BITS`.

We will improve `gen_rdeposit_op` in order to handle the immediate
case efficiently and then implement `gen_deposit_op` with
`gen_rdeposit_op`.

-- 
Alessandro Di Federico
rev.ng


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

* Re: [PATCH v5 14/14] gitlab-ci: do not use qemu-project Docker registry
  2021-06-19  9:37 ` [PATCH v5 14/14] gitlab-ci: do not use qemu-project Docker registry Alessandro Di Federico via
  2021-06-29 14:26   ` Alessandro Di Federico via
@ 2021-06-29 14:37   ` Daniel P. Berrangé
  2021-07-08 16:00     ` Alessandro Di Federico via
  1 sibling, 1 reply; 38+ messages in thread
From: Daniel P. Berrangé @ 2021-06-29 14:37 UTC (permalink / raw)
  To: Alessandro Di Federico
  Cc: Alessandro Di Federico, bcain, richard.henderson, qemu-devel,
	babush, tsimpson, nizzo, philmd

On Sat, Jun 19, 2021 at 11:37:13AM +0200, Alessandro Di Federico via wrote:
> From: Alessandro Di Federico <ale@rev.ng>
> 
> This commit is necessary in order to use container built by the current
> run of the CI. If we don't do this, we use official containers which are
> not affected by the additional dependencies we're introducing.
> 
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> ---
>  .gitlab-ci.d/container-cross.yml    | 2 +-
>  .gitlab-ci.d/container-template.yml | 4 ++--
>  2 files changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/.gitlab-ci.d/container-cross.yml b/.gitlab-ci.d/container-cross.yml
> index 0fcebe363a..eb134e927d 100644
> --- a/.gitlab-ci.d/container-cross.yml
> +++ b/.gitlab-ci.d/container-cross.yml
> @@ -63,7 +63,7 @@ hexagon-cross-container:
>      - docker:dind
>    before_script:
>      - export TAG="$CI_REGISTRY_IMAGE/qemu/$NAME:latest"
> -    - export COMMON_TAG="$CI_REGISTRY/qemu-project/qemu/qemu/$NAME:latest"
> +    - export COMMON_TAG="$CI_REGISTRY_IMAGE/qemu/$NAME:latest"

This isn't right.

We have either one or two images.  If this is a new user fork,
we only have the $COMMON_TAG image in the main QEMU registry.
If this is a existing fork, we might have two images, one in
the main QEMU registry and one in the user's fork registry.
Both of the images are to be used as a cache source, with
the container tools figuring out which has matching image
layers, if any.

This proposed change makes TAG and COMMON_TAG identical
which means we loose inheritance from the main QEMU
registry, which almost always has suitable cached content.


>      - docker info
>      - docker login $CI_REGISTRY -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD"
>    script:
> diff --git a/.gitlab-ci.d/container-template.yml b/.gitlab-ci.d/container-template.yml
> index 1baecd9460..c85ae377b8 100644
> --- a/.gitlab-ci.d/container-template.yml
> +++ b/.gitlab-ci.d/container-template.yml
> @@ -5,7 +5,7 @@
>      - docker:dind
>    before_script:
>      - export TAG="$CI_REGISTRY_IMAGE/qemu/$NAME:latest"
> -    - export COMMON_TAG="$CI_REGISTRY/qemu-project/qemu/$NAME:latest"
> +    - export COMMON_TAG="$CI_REGISTRY_IMAGE/qemu/$NAME:latest"
>      - apk add python3
>      - docker info
>      - docker login $CI_REGISTRY -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD"

Again this is wrong.


> @@ -14,7 +14,7 @@
>      - echo "COMMON_TAG:$COMMON_TAG"
>      - ./tests/docker/docker.py --engine docker build
>            -t "qemu/$NAME" -f "tests/docker/dockerfiles/$NAME.docker"
> -          -r $CI_REGISTRY/qemu-project/qemu
> +          -r $CI_REGISTRY_IMAGE

I'm not sure about this one though.

>      - docker tag "qemu/$NAME" "$TAG"
>      - docker push "$TAG"
>    after_script:

Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|



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

* Re: [PATCH v5 10/14] target/hexagon: import parser for idef-parser
  2021-06-24  3:55   ` Taylor Simpson
  2021-06-29 14:26     ` Alessandro Di Federico via
@ 2021-06-30 16:51     ` Paolo Montesel
  2021-07-05 16:47     ` Alessandro Di Federico via
  2 siblings, 0 replies; 38+ messages in thread
From: Paolo Montesel @ 2021-06-30 16:51 UTC (permalink / raw)
  To: Taylor Simpson
  Cc: Alessandro Di Federico, Brian Cain, richard.henderson,
	qemu-devel, Alessandro Di Federico, nizzo, philmd

> > +void gen_setbits(Context *c, YYLTYPE *locp, HexValue *hi, HexValue *lo,
> > +                 HexValue *dst, HexValue *val)
> > +{
> > +    yyassert(c, locp, hi->type == IMMEDIATE &&
> > +             hi->imm.type == VALUE &&
> > +             lo->type == IMMEDIATE &&
> > +             lo->imm.type == VALUE,
> > +             "Range deposit needs immediate values!\n");
> > +
> > +    *val = rvalue_truncate(c, locp, val);
> > +    unsigned len = hi->imm.value + 1 - lo->imm.value;
> > +    HexValue tmp = gen_tmp(c, locp, 32);
> > +    OUT(c, locp, "tcg_gen_neg_i32(", &tmp, ", ", val, ");\n");
> > +    OUT(c, locp, "tcg_gen_deposit_i32(", dst, ", ", dst, ", ", &tmp, ", ");
> > +    OUT(c, locp, lo, ", ", &len, ");\n");
>
>
> This doesn't match the C semantics of fSETBITS
>
> #define fSETBIT(N, DST, VAL) \
>     do { \
>         DST = (DST & ~(1ULL << (N))) | (((uint64_t)(VAL)) << (N)); \
>     } while (0)
>
> #define fGETBIT(N, SRC) (((SRC) >> N) & 1)
> #define fSETBITS(HI, LO, DST, VAL) \
>     do { \
>         int j; \
>         for (j = LO; j <= HI; j++) { \
>             fSETBIT(j, DST, VAL); \
>         } \
>     } while (0)
>
> You need to put len copies of LSB(val), so emit something like this
>     TCGv zero = tcg_const_tl(0);
>     TCGv ones = tcg_const_tl(~0);
>     tcg_gen_andi_tl(tmp, val, 1);
>     tcg_gen_movcond_tl(TCG_COND_NE, tmp, tmp, zero, ones, zero);
>     tcg_gen_deposit_tl(dst, dst, tmp, lo, len);
>     tcg_temp_free(zero);
>     tcg_temp_free(ones);

The change was suggested by (I think) Richard some patchset ago and I
think it is semantically equivalent.
I checked `compare.idef` and every value of `VAL` comes from a
comparison, which has value either `0` or `1`.
Applying `neg` turns it into either `0` or `0xFFFFFFFF`, making the
`deposit` work as intended.

Am I missing something?


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

* Re: [PATCH v5 10/14] target/hexagon: import parser for idef-parser
  2021-06-24  3:55   ` Taylor Simpson
  2021-06-29 14:26     ` Alessandro Di Federico via
  2021-06-30 16:51     ` Paolo Montesel
@ 2021-07-05 16:47     ` Alessandro Di Federico via
  2 siblings, 0 replies; 38+ messages in thread
From: Alessandro Di Federico via @ 2021-07-05 16:47 UTC (permalink / raw)
  To: Taylor Simpson
  Cc: Alessandro Di Federico, qemu-devel, Brian Cain, babush, nizzo,
	philmd, richard.henderson

On Thu, 24 Jun 2021 03:55:35 +0000
Taylor Simpson <tsimpson@quicinc.com> wrote:

> > +void gen_deposit_op(Context *c,
> > +                    YYLTYPE *locp,
> > +                    HexValue *dest,
> > +                    HexValue *value,
> > +                    HexValue *index,
> > +                    HexCast *cast)  
> 
> What's the difference between this and the gen_rdeposit_op above?

`gen_deposit_op` expects index and width (cast) to be immediates, while
`gen_rdeposit_op` does not.
We could merge them together, but it would just be a big "if" over the
whole function.

> > +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) {  
> 
> What's the difference between this ant the gen_rextract_op above?

As before.

-- 
Alessandro Di Federico
rev.ng


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

* Re: [PATCH v5 13/14] target/hexagon: import additional tests
  2021-06-25 23:56   ` Taylor Simpson
  2021-06-28 22:39     ` Taylor Simpson
@ 2021-07-05 16:50     ` Alessandro Di Federico via
  1 sibling, 0 replies; 38+ messages in thread
From: Alessandro Di Federico via @ 2021-07-05 16:50 UTC (permalink / raw)
  To: Taylor Simpson
  Cc: Alessandro Di Federico, qemu-devel, tsimpson, bcain, babush,
	nizzo, philmd, richard.henderson

On Fri, 25 Jun 2021 18:56:57 -0500
Taylor Simpson <taylor.qemu@gmail.com> wrote:

> Each of these are very small, so I recommend putting them into misc.c
> or combine all the assembly into a small number of executables.

These tests are designed to run without libc and test in isolation very
specific functionality making as little assumptions as possible about
what instructions are working correctly.

Now that we are mature enough it might not make much sense this
approach, but starting from scratch (and also considering phase 2) they
might be helpful.

With some refactoring and ".include" directives I can probably make a
single executable out of them, but it's not superelegant.

For the rest, I've dropped several outdated comments and superflous
tests.

Thanks for looking into this.

-- 
Alessandro Di Federico
rev.ng


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

* Re: [PATCH v5 14/14] gitlab-ci: do not use qemu-project Docker registry
  2021-06-29 14:37   ` Daniel P. Berrangé
@ 2021-07-08 16:00     ` Alessandro Di Federico via
  0 siblings, 0 replies; 38+ messages in thread
From: Alessandro Di Federico via @ 2021-07-08 16:00 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: bcain, richard.henderson, qemu-devel, babush, tsimpson, nizzo, philmd

On Tue, 29 Jun 2021 15:37:21 +0100
Daniel P. Berrangé <berrange@redhat.com> wrote:

> We have either one or two images.  If this is a new user fork,
> we only have the $COMMON_TAG image in the main QEMU registry.
> If this is a existing fork, we might have two images, one in
> the main QEMU registry and one in the user's fork registry.
> Both of the images are to be used as a cache source, with
> the container tools figuring out which has matching image
> layers, if any.
>
> This proposed change makes TAG and COMMON_TAG identical
> which means we loose inheritance from the main QEMU
> registry, which almost always has suitable cached content.

I understand. This patch was aimed at pointing out a problem more than
offering a proper solution.

I'll try and take a look at how to do this right, but I think this
outside the scope of this patchset (and my area of expertise).

-- 
Alessandro Di Federico
rev.ng


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

end of thread, other threads:[~2021-07-08 16:43 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-19  9:36 [PATCH v5 00/14] target/hexagon: introduce idef-parser Alessandro Di Federico via
2021-06-19  9:37 ` [PATCH v5 01/14] tcg: expose TCGCond manipulation routines Alessandro Di Federico via
2021-06-19 13:51   ` Richard Henderson
2021-06-19  9:37 ` [PATCH v5 02/14] target/hexagon: update MAINTAINERS for idef-parser Alessandro Di Federico via
2021-06-19  9:37 ` [PATCH v5 03/14] target/hexagon: import README " Alessandro Di Federico via
2021-06-23 15:46   ` Taylor Simpson
2021-06-24 13:51     ` Alessandro Di Federico via
2021-06-19  9:37 ` [PATCH v5 04/14] target/hexagon: make slot number an unsigned Alessandro Di Federico via
2021-06-23 15:58   ` Taylor Simpson
2021-06-19  9:37 ` [PATCH v5 05/14] target/hexagon: make helper functions non-static Alessandro Di Federico via
2021-06-23 18:29   ` Taylor Simpson
2021-06-19  9:37 ` [PATCH v5 06/14] target/hexagon: introduce new helper functions Alessandro Di Federico via
2021-06-23 12:05   ` Taylor Simpson
2021-06-23 18:49   ` Taylor Simpson
2021-06-19  9:37 ` [PATCH v5 07/14] target/hexagon: expose next PC in DisasContext Alessandro Di Federico via
2021-06-23 18:54   ` Taylor Simpson
2021-06-19  9:37 ` [PATCH v5 08/14] target/hexagon: prepare input for the idef-parser Alessandro Di Federico via
2021-06-23 19:37   ` Taylor Simpson
2021-06-19  9:37 ` [PATCH v5 09/14] target/hexagon: import lexer for idef-parser Alessandro Di Federico via
2021-06-23 20:05   ` Taylor Simpson
2021-06-19  9:37 ` [PATCH v5 10/14] target/hexagon: import parser " Alessandro Di Federico via
2021-06-22 22:35   ` Taylor Simpson
2021-06-24  3:55   ` Taylor Simpson
2021-06-29 14:26     ` Alessandro Di Federico via
2021-06-30 16:51     ` Paolo Montesel
2021-07-05 16:47     ` Alessandro Di Federico via
2021-06-19  9:37 ` [PATCH v5 11/14] target/hexagon: call idef-parser functions Alessandro Di Federico via
2021-06-25 22:00   ` Taylor Simpson
2021-06-19  9:37 ` [PATCH v5 12/14] target/hexagon: remove unused macros and functions Alessandro Di Federico via
2021-06-25 22:02   ` Taylor Simpson
2021-06-19  9:37 ` [PATCH v5 13/14] target/hexagon: import additional tests Alessandro Di Federico via
2021-06-25 23:56   ` Taylor Simpson
2021-06-28 22:39     ` Taylor Simpson
2021-07-05 16:50     ` Alessandro Di Federico via
2021-06-19  9:37 ` [PATCH v5 14/14] gitlab-ci: do not use qemu-project Docker registry Alessandro Di Federico via
2021-06-29 14:26   ` Alessandro Di Federico via
2021-06-29 14:37   ` Daniel P. Berrangé
2021-07-08 16:00     ` Alessandro Di Federico via

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