* [PATCH v8 00/12] target/hexagon: introduce idef-parser
@ 2022-02-09 17:03 Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 01/12] target/hexagon: update MAINTAINERS for idef-parser Anton Johansson via
` (11 more replies)
0 siblings, 12 replies; 23+ messages in thread
From: Anton Johansson via @ 2022-02-09 17:03 UTC (permalink / raw)
To: qemu-devel
Cc: ale, tsimpson, bcain, mlambert, babush, nizzo, richard.henderson
This patchset introduces the idef-parser for target/hexagon.
It's the eight iteration of the patchset and includes fixes suggested in
previous iterations.
`idef-parser` is a build-time tool built using flex and bison. Its aim
is to generate a large part of the tiny code generator frontend for
Hexagon. The prototype of idef-parser has been presented at KVM Forum
2019 ("QEMU-Hexagon: Automatic Translation of the ISA Manual Pseudocode
to Tiny Code Instructions"):
https://www.youtube.com/watch?v=3EpnTYBOXCI
`target/hexagon/idef-parser/README.rst` provides an overview of the
parser and its inner working.
A couple of notes:
* These commits build successfully on the CI (including using clang),
with one notable exception. Presently, the `build-user-hexagon` job
fails due to not being able to find `flex`. We believe this to be
caused by `debian-hexagon-cross` not being built by the CI.
As such the `debian-hexagon-cross` container will have to be manually
rebuilt before merging.
* The eight patch, which introduces flex and bison as new build pre-
requisites using `libvirt-ci` currently points to a fork, not yet
merged upstream. This will have to be corrected before the final
version of the patchset.
Alessandro Di Federico (4):
target/hexagon: update MAINTAINERS for idef-parser
target/hexagon: import README for idef-parser
target/hexagon: prepare input for the idef-parser
target/hexagon: call idef-parser functions
Anton Johansson (2):
target/hexagon: import flex/bison to docker files
target/hexagon: import parser for idef-parser
Niccolò Izzo (2):
target/hexagon: introduce new helper functions
target/hexagon: import additional tests
Paolo Montesel (4):
target/hexagon: make slot number an unsigned
target/hexagon: make helper functions non-static
target/hexagon: expose next PC in DisasContext
target/hexagon: import lexer for idef-parser
.gitlab-ci.d/cirrus/freebsd-12.vars | 2 +-
.gitlab-ci.d/cirrus/freebsd-13.vars | 2 +-
.gitlab-ci.d/windows.yml | 2 +
.gitmodules | 3 +-
MAINTAINERS | 9 +
meson_options.txt | 3 +
target/hexagon/README | 5 +
target/hexagon/gen_helper_funcs.py | 17 +-
target/hexagon/gen_helper_protos.py | 17 +-
target/hexagon/gen_idef_parser_funcs.py | 125 +
target/hexagon/gen_tcg_funcs.py | 41 +-
target/hexagon/genptr.c | 230 +-
target/hexagon/genptr.h | 44 +
target/hexagon/hex_common.py | 10 +
target/hexagon/idef-parser/README.rst | 722 +++++
target/hexagon/idef-parser/idef-parser.h | 254 ++
target/hexagon/idef-parser/idef-parser.lex | 566 ++++
target/hexagon/idef-parser/idef-parser.y | 1039 +++++++
target/hexagon/idef-parser/macros.inc | 140 +
target/hexagon/idef-parser/parser-helpers.c | 2551 +++++++++++++++++
target/hexagon/idef-parser/parser-helpers.h | 375 +++
target/hexagon/idef-parser/prepare | 24 +
target/hexagon/macros.h | 11 +-
target/hexagon/meson.build | 138 +-
target/hexagon/op_helper.c | 29 +-
target/hexagon/op_helper.h | 37 +
target/hexagon/translate.c | 3 +-
target/hexagon/translate.h | 1 +
tests/docker/dockerfiles/alpine.docker | 5 +-
tests/docker/dockerfiles/centos8.docker | 7 +-
tests/docker/dockerfiles/debian-amd64.docker | 2 +
tests/docker/dockerfiles/debian-native.docker | 3 +
.../dockerfiles/debian-riscv64-cross.docker | 3 +
.../dockerfiles/debian-tricore-cross.docker | 1 +
tests/docker/dockerfiles/debian10.docker | 3 +
.../dockerfiles/fedora-i386-cross.docker | 3 +
.../dockerfiles/fedora-win32-cross.docker | 3 +
.../dockerfiles/fedora-win64-cross.docker | 3 +
tests/docker/dockerfiles/fedora.docker | 5 +-
tests/docker/dockerfiles/opensuse-leap.docker | 7 +-
tests/docker/dockerfiles/ubuntu1804.docker | 7 +-
tests/docker/dockerfiles/ubuntu2004.docker | 7 +-
tests/lcitool/libvirt-ci | 2 +-
tests/lcitool/projects/qemu.yml | 2 +
tests/lcitool/refresh | 2 +-
tests/tcg/hexagon/Makefile.target | 28 +-
tests/tcg/hexagon/crt.S | 14 +
tests/tcg/hexagon/test_abs.S | 17 +
tests/tcg/hexagon/test_bitcnt.S | 40 +
tests/tcg/hexagon/test_bitsplit.S | 22 +
tests/tcg/hexagon/test_call.S | 64 +
tests/tcg/hexagon/test_clobber.S | 29 +
tests/tcg/hexagon/test_cmp.S | 31 +
tests/tcg/hexagon/test_dotnew.S | 38 +
tests/tcg/hexagon/test_ext.S | 13 +
tests/tcg/hexagon/test_fibonacci.S | 30 +
tests/tcg/hexagon/test_hl.S | 16 +
tests/tcg/hexagon/test_hwloops.S | 19 +
tests/tcg/hexagon/test_jmp.S | 22 +
tests/tcg/hexagon/test_lsr.S | 36 +
tests/tcg/hexagon/test_mpyi.S | 17 +
tests/tcg/hexagon/test_packet.S | 29 +
tests/tcg/hexagon/test_reorder.S | 33 +
tests/tcg/hexagon/test_round.S | 29 +
tests/tcg/hexagon/test_vavgw.S | 31 +
tests/tcg/hexagon/test_vcmpb.S | 30 +
tests/tcg/hexagon/test_vcmpw.S | 30 +
tests/tcg/hexagon/test_vlsrw.S | 20 +
tests/tcg/hexagon/test_vmaxh.S | 35 +
tests/tcg/hexagon/test_vminh.S | 35 +
tests/tcg/hexagon/test_vpmpyh.S | 28 +
tests/tcg/hexagon/test_vspliceb.S | 31 +
72 files changed, 7125 insertions(+), 107 deletions(-)
create mode 100644 target/hexagon/gen_idef_parser_funcs.py
create mode 100644 target/hexagon/idef-parser/README.rst
create mode 100644 target/hexagon/idef-parser/idef-parser.h
create mode 100644 target/hexagon/idef-parser/idef-parser.lex
create mode 100644 target/hexagon/idef-parser/idef-parser.y
create mode 100644 target/hexagon/idef-parser/macros.inc
create mode 100644 target/hexagon/idef-parser/parser-helpers.c
create mode 100644 target/hexagon/idef-parser/parser-helpers.h
create mode 100755 target/hexagon/idef-parser/prepare
create mode 100644 target/hexagon/op_helper.h
create mode 100644 tests/tcg/hexagon/crt.S
create mode 100644 tests/tcg/hexagon/test_abs.S
create mode 100644 tests/tcg/hexagon/test_bitcnt.S
create mode 100644 tests/tcg/hexagon/test_bitsplit.S
create mode 100644 tests/tcg/hexagon/test_call.S
create mode 100644 tests/tcg/hexagon/test_clobber.S
create mode 100644 tests/tcg/hexagon/test_cmp.S
create mode 100644 tests/tcg/hexagon/test_dotnew.S
create mode 100644 tests/tcg/hexagon/test_ext.S
create mode 100644 tests/tcg/hexagon/test_fibonacci.S
create mode 100644 tests/tcg/hexagon/test_hl.S
create mode 100644 tests/tcg/hexagon/test_hwloops.S
create mode 100644 tests/tcg/hexagon/test_jmp.S
create mode 100644 tests/tcg/hexagon/test_lsr.S
create mode 100644 tests/tcg/hexagon/test_mpyi.S
create mode 100644 tests/tcg/hexagon/test_packet.S
create mode 100644 tests/tcg/hexagon/test_reorder.S
create mode 100644 tests/tcg/hexagon/test_round.S
create mode 100644 tests/tcg/hexagon/test_vavgw.S
create mode 100644 tests/tcg/hexagon/test_vcmpb.S
create mode 100644 tests/tcg/hexagon/test_vcmpw.S
create mode 100644 tests/tcg/hexagon/test_vlsrw.S
create mode 100644 tests/tcg/hexagon/test_vmaxh.S
create mode 100644 tests/tcg/hexagon/test_vminh.S
create mode 100644 tests/tcg/hexagon/test_vpmpyh.S
create mode 100644 tests/tcg/hexagon/test_vspliceb.S
--
2.34.1
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH v8 01/12] target/hexagon: update MAINTAINERS for idef-parser
2022-02-09 17:03 [PATCH v8 00/12] target/hexagon: introduce idef-parser Anton Johansson via
@ 2022-02-09 17:03 ` Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 02/12] target/hexagon: import README " Anton Johansson via
` (10 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Anton Johansson via @ 2022-02-09 17:03 UTC (permalink / raw)
To: qemu-devel
Cc: ale, tsimpson, bcain, mlambert, babush, nizzo, richard.henderson
From: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Taylor Simpson <tsimpson@quicinc.com>
---
MAINTAINERS | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 9814580975..1195edf040 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -200,6 +200,8 @@ Hexagon TCG CPUs
M: Taylor Simpson <tsimpson@quicinc.com>
S: Supported
F: target/hexagon/
+X: target/hexagon/idef-parser/
+X: target/hexagon/gen_idef_parser_funcs.py
F: linux-user/hexagon/
F: tests/tcg/hexagon/
F: disas/hexagon.c
@@ -207,6 +209,13 @@ F: configs/targets/hexagon-linux-user/default.mak
F: docker/dockerfiles/debian-hexagon-cross.docker
F: docker/dockerfiles/debian-hexagon-cross.docker.d/build-toolchain.sh
+Hexagon idef-parser
+M: Alessandro Di Federico <ale@rev.ng>
+M: Anton Johansson <anjo@rev.ng>
+S: Supported
+F: target/hexagon/idef-parser/
+F: target/hexagon/gen_idef_parser_funcs.py
+
HPPA (PA-RISC) TCG CPUs
M: Richard Henderson <richard.henderson@linaro.org>
S: Maintained
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v8 02/12] target/hexagon: import README for idef-parser
2022-02-09 17:03 [PATCH v8 00/12] target/hexagon: introduce idef-parser Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 01/12] target/hexagon: update MAINTAINERS for idef-parser Anton Johansson via
@ 2022-02-09 17:03 ` Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 03/12] target/hexagon: make slot number an unsigned Anton Johansson via
` (9 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Anton Johansson via @ 2022-02-09 17:03 UTC (permalink / raw)
To: qemu-devel
Cc: ale, tsimpson, bcain, mlambert, babush, nizzo, richard.henderson
From: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Taylor Simpson <tsimpson@quicinc.com>
---
target/hexagon/README | 5 +
target/hexagon/idef-parser/README.rst | 722 ++++++++++++++++++++++++++
2 files changed, 727 insertions(+)
create mode 100644 target/hexagon/idef-parser/README.rst
diff --git a/target/hexagon/README b/target/hexagon/README
index 372e24747c..6cb5affddb 100644
--- a/target/hexagon/README
+++ b/target/hexagon/README
@@ -27,6 +27,10 @@ Hexagon-specific code are
encode*.def Encoding patterns for each instruction
iclass.def Instruction class definitions used to determine
legal VLIW slots for each instruction
+ qemu/target/hexagon/idef-parser
+ Parser that, given the high-level definitions of an instruction,
+ produces a C function generating equivalent tiny code instructions.
+ See README.rst.
qemu/linux-user/hexagon
Helpers for loading the ELF file and making Linux system calls,
signals, etc
@@ -47,6 +51,7 @@ header files in <BUILD_DIR>/target/hexagon
gen_tcg_funcs.py -> tcg_funcs_generated.c.inc
gen_tcg_func_table.py -> tcg_func_table_generated.c.inc
gen_helper_funcs.py -> helper_funcs_generated.c.inc
+ gen_idef_parser_funcs.py -> idef_parser_input.h
Qemu helper functions have 3 parts
DEF_HELPER declaration indicates the signature of the helper
diff --git a/target/hexagon/idef-parser/README.rst b/target/hexagon/idef-parser/README.rst
new file mode 100644
index 0000000000..65e6bf4ee5
--- /dev/null
+++ b/target/hexagon/idef-parser/README.rst
@@ -0,0 +1,722 @@
+Hexagon ISA instruction definitions to tinycode generator compiler
+------------------------------------------------------------------
+
+idef-parser is a small compiler able to translate the Hexagon ISA description
+language into tinycode generator code, that can be easily integrated into QEMU.
+
+Compilation Example
+-------------------
+
+To better understand the scope of the idef-parser, we'll explore an applicative
+example. Let's start by one of the simplest Hexagon instruction: the ``add``.
+
+The ISA description language represents the ``add`` instruction as
+follows:
+
+.. code:: c
+
+ A2_add(RdV, in RsV, in RtV) {
+ { RdV=RsV+RtV;}
+ }
+
+idef-parser will compile the above code into the following code:
+
+.. code:: c
+
+ /* A2_add */
+ void emit_A2_add(DisasContext *ctx, Insn *insn, Packet *pkt, TCGv_i32 RdV,
+ TCGv_i32 RsV, TCGv_i32 RtV)
+ /* { RdV=RsV+RtV;} */
+ {
+ TCGv_i32 tmp_0 = tcg_temp_new_i32();
+ tcg_gen_add_i32(tmp_0, RsV, RtV);
+ tcg_gen_mov_i32(RdV, tmp_0);
+ tcg_temp_free_i32(tmp_0);
+ }
+
+The output of the compilation process will be a function, containing the
+tinycode generator code, implementing the correct semantics. That function will
+not access any global variable, because all the accessed data structures will be
+passed explicitly as function parameters. Among the passed parameters we will
+have TCGv (tinycode variables) representing the input and output registers of
+the architecture, integers representing the immediates that come from the code,
+and other data structures which hold information about the disassemblation
+context (``DisasContext`` struct).
+
+Let's begin by describing the input code. The ``add`` instruction is associated
+with a unique identifier, in this case ``A2_add``, which allows to distinguish
+variants of the same instruction, and expresses the class to which the
+instruction belongs, in this case ``A2`` corresponds to the Hexagon
+``ALU32/ALU`` instruction subclass.
+
+After the instruction identifier, we have a series of parameters that represents
+TCG variables that will be passed to the generated function. Parameters marked
+with ``in`` are already initialized, while the others are output parameters.
+
+We will leverage this information to infer several information:
+
+- Fill in the output function signature with the correct TCGv registers
+- Fill in the output function signature with the immediate integers
+- Keep track of which registers, among the declared one, have been
+ initialized
+
+Let's now observe the actual instruction description code, in this case:
+
+.. code:: c
+
+ { RdV=RsV+RtV;}
+
+This code is composed by a subset of the C syntax, and is the result of the
+application of some macro definitions contained in the ``macros.h`` file.
+
+This file is used to reduce the complexity of the input language where complex
+variants of similar constructs can be mapped to a unique primitive, so that the
+idef-parser has to handle a lower number of computation primitives.
+
+As you may notice, the description code modifies the registers which have been
+declared by the declaration statements. In this case all the three registers
+will be declared, ``RsV`` and ``RtV`` will also be read and ``RdV`` will be
+written.
+
+Now let's have a quick look at the generated code, line by line.
+
+::
+
+ TCGv_i32 tmp_0 = tcg_temp_new_i32();
+
+This code starts by declaring a temporary TCGv to hold the result from the sum
+operation.
+
+::
+
+ tcg_gen_add_i32(tmp_0, RsV, RtV);
+
+Then, we are generating the sum tinycode operator between the selected
+registers, storing the result in the just declared temporary.
+
+::
+
+ tcg_gen_mov_i32(RdV, tmp_0);
+
+The result of the addition is now stored in the temporary, we move it into the
+correct destination register. This code may seem inefficient, but QEMU will
+perform some optimizations on the tinycode, reducing the unnecessary copy.
+
+::
+
+ tcg_temp_free_i32(tmp_0);
+
+Finally, we free the temporary we used to hold the addition result.
+
+Parser Input
+------------
+
+Before moving on to the structure of idef-parser itself, let us spend some words
+on its' input. There are two preprocessing steps applied to the generated
+instruction semantics in ``semantics_generated.pyinc`` that we need to consider.
+Firstly,
+
+::
+
+ gen_idef_parser_funcs.py
+
+which takes instruction semantics in ``semantics_generated.pyinc`` to C-like
+pseudo code, output into ``idef_parser_input.h.inc``. For instance, the
+``J2_jumpr`` instruction which jumps to an address stored in a register
+argument. This is instruction is defined as
+
+::
+
+ SEMANTICS( \
+ "J2_jumpr", \
+ "jumpr Rs32", \
+ """{fJUMPR(RsN,RsV,COF_TYPE_JUMPR);}""" \
+ )
+
+in ``semantics_generated.pyinc``. Running ``gen_idef_parser_funcs.py``
+we obtain the pseudo code
+
+::
+
+ J2_jumpr(in RsV) {
+ {fJUMPR(RsN,RsV,COF_TYPE_JUMPR);}
+ }
+
+with macros such as ``fJUMPR`` intact.
+
+The second step is to expand macros into a form suitable for our parser.
+These macros are defined in ``idef-parser/macros.inc`` and the step is
+carried out by the ``prepare`` script which runs the C preprocessor on
+``idef_parser_input.h.inc`` to produce
+``idef_parser_input.preprocessed.h.inc``.
+
+To finish the above example, after preprocessing ``J2_jumpr`` we obtain
+
+::
+
+ J2_jumpr(in RsV) {
+ {(PC = RsV);}
+ }
+
+where ``fJUMPR(RsN,RsV,COF_TYPE_JUMPR);`` was expanded to ``(PC = RsV)``,
+signifying a write to the Program Counter ``PC``. Note, that ``PC`` in
+this expression is not a variable in the strict C sense since it is not
+declared anywhere, but rather a symbol which is easy to match in
+idef-parser later on.
+
+Parser Structure
+----------------
+
+The idef-parser is built using the ``flex`` and ``bison``.
+
+``flex`` is used to split the input string into tokens, each described using a
+regular expression. The token description is contained in the
+``idef-parser.lex`` source file. The flex-generated scanner takes care also to
+extract from the input text other meaningful information, e.g., the numerical
+value in case of an immediate constant, and decorates the token with the
+extracted information.
+
+``bison`` is used to generate the actual parser, starting from the parsing
+description contained in the ``idef-parser.y`` file. The generated parser
+executes the ``main`` function at the end of the ``idef-parser.y`` file, which
+opens input and output files, creates the parsing context, and eventually calls
+the ``yyparse()`` function, which starts the execution of the LALR(1) parser
+(see `Wikipedia <https://en.wikipedia.org/wiki/LALR_parser>`__ for more
+information about LALR parsing techniques). The LALR(1) parser, whenever it has
+to shift a token, calls the ``yylex()`` function, which is defined by the
+flex-generated code, and reads the input file returning the next scanned token.
+
+The tokens are mapped on the source language grammar, defined in the
+``idef-parser.y`` file to build a unique syntactic tree, according to the
+specified operator precedences and associativity rules.
+
+The grammar describes the whole file which contains the Hexagon instruction
+descriptions, therefore it starts from the ``input`` nonterminal, which is a
+list of instructions, each instruction is represented by the following grammar
+rule, representing the structure of the input file shown above:
+
+::
+
+ instruction : INAME arguments code
+ | error
+
+ arguments : '(' ')'
+ | '(' argument_list ')';
+
+ argument_list : argument_decl ',' argument_list
+ | argument_decl
+
+ argument_decl : REG
+ | PRED
+ | IN REG
+ | IN PRED
+ | IMM
+ | var
+ ;
+
+ code : '{' statements '}'
+
+ statements : statements statement
+ | statement
+
+ statement : control_statement
+ | var_decl ';'
+ | rvalue ';'
+ | code_block
+ | ';'
+
+ code_block : '{' statements '}'
+ | '{' '}'
+
+With this initial portion of the grammar we are defining the instruction, its'
+arguments, and its' statements. Each argument is defined by the
+``argument_decl`` rule, and can be either
+
+::
+
+ Description Example
+ ----------------------------------------
+ output register RsV
+ output predicate register P0
+ input register in RsV
+ input predicate register in P0
+ immediate value 1234
+ local variable EA
+
+Note, the only local variable allowed to be used as an argument is the effective
+address ``EA``. Similarly, each statement can be a ``control_statement``, a
+variable declaration such as ``int a;``, a code block, which is just a
+bracket-enclosed list of statements, a ``';'``, which is a ``nop`` instruction,
+and an ``rvalue ';'``.
+
+Expressions
+~~~~~~~~~~~
+
+Allowed in the input code are C language expressions with a few exceptions
+to simplify parsing. For instance, variable names such as ``RdV``, ``RssV``,
+``PdV``, ``CsV``, and other idiomatic register names from Hexagon, are
+reserved specifically for register arguments. These arguments then map to
+``TCGv_i32`` or ``TCGv_i64`` depending on the register size. Similarly, ``UiV``,
+``riV``, etc. refer to immediate arguments and will map to C integers.
+
+Also, as mentioned earlier, the names ``PC``, ``SP``, ``FP``, etc. are used to
+refer to Hexagon registers such as the program counter, stack pointer, and frame
+pointer seen here. Writes to these registers then correspond to assignments
+``PC = ...``, and reads correspond to uses of the variable ``PC``.
+
+Moreover, another example of one such exception is the selective expansion of
+macros present in ``macros.h``. As an example, consider the ``fABS`` macro which
+in plain C is defined as
+
+::
+
+ #define fABS(A) (((A) < 0) ? (-(A)) : (A))
+
+and returns the absolute value of the argument ``A``. This macro is not included
+in ``idef-parser/macros.inc`` and as such is not expanded and kept as a "call"
+``fABS(...)``. Reason being, that ``fABS`` is easier to match and map to
+``tcg_gen_abs_<width>``, compared to the full ternary expression above. Loads of
+macros in ``macros.h`` are kept unexpanded to aid in parsing, as seen in the
+example above, for more information see ``idef-parser/idef-parser.lex``.
+
+Finally, in mapping these input expressions to tinycode generators, idef-parser
+tries to perform as much as possible in plain C. Such as, performing binary
+operations in C instead of tinycode generators, thus effectively constant
+folding the expression.
+
+Variables and Variable Declarations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Similarly to C, variables in the input code must be explicitly declared, such as
+``int var1;`` which declares an uninitialized variable ``var1``. Initialization
+``int var2 = 0;`` is also allowed and behaves as expected. In tinycode
+generators the previous declarations are mapped to
+
+::
+
+ int var1; -> TCGv_i32 var1 = tcg_temp_local_new_i32();
+
+ int var2 = 0; -> TCGv_i32 var1 = tcg_temp_local_new_i32();
+ tcg_gen_movi_i32(j, ((int64_t) 0ULL));
+
+which are later automatically freed at the end of the function they're declared
+in. Contrary to C, we only allow variables to be declared with an integer type
+specified in the following table (without permutation of keywords)
+
+::
+
+ type bit-width signedness
+ ----------------------------------------------------------
+ int 32 signed
+ signed
+ signed int
+
+ unsigned 32 unsigned
+ unsigned int
+
+ long 64 signed
+ long int
+ signed long
+ signed long int
+
+ unsigned long 64 unsigned
+ unsigned long int
+
+ long long 64 signed
+ long long int
+ signed long long
+ signed long long int
+
+ unsigned long long 64 unsigned
+ unsigned long long int
+
+ size[1,2,4,8][s,u]_t 8-64 signed or unsigned
+
+In idef-parser, variable names are matched by a generic ``VARID`` token,
+which will feature the variable name as a decoration. For a variable declaration
+idef-parser calls ``gen_varid_allocate`` with the ``VARID`` token to save the
+name, size, and bit width of the newly declared variable. In addition, this
+function also ensures that variables aren't declared multiple times, and prints
+and error message if that is the case. Upon use of a variable, the ``VARID``
+token is used to lookup the size and bit width of the variable.
+
+Type System
+~~~~~~~~~~~
+
+idef-parser features a simple type system which is used to correctly implement
+the signedness and bit width of the operations.
+
+The type of each ``rvalue`` is determined by two attributes: its bit width
+(``unsigned bit_width``) and its signedness (``HexSignedness signedness``).
+
+For each operation, the type of ``rvalue``\ s influence the way in which the
+operands are handled and emitted. For example a right shift between signed
+operators will be an arithmetic shift, while one between unsigned operators
+will be a logical shift. If one of the two operands is signed, and the other
+is unsigned, the operation will be signed.
+
+The bit width also influences the outcome of the operations, in particular while
+the input languages features a fine granularity type system, with types of 8,
+16, 32, 64 (and more for vectorial instructions) bits, the tinycode only
+features 32 and 64 bit widths. We propagate as much as possible the fine
+granularity type, until the value has to be used inside an operation between
+``rvalue``\ s; in that case if one of the two operands is greater than 32 bits
+we promote the whole operation to 64 bit, taking care of properly extending the
+two operands. Fortunately, the most critical instructions already feature
+explicit casts and zero/sign extensions which are properly propagated down to
+our parser.
+
+The combination of ``rvalue``\ s are handled through the use of the
+``gen_bin_op`` and ``gen_bin_cmp`` helper functions. These two functions handle
+the appropriate compile-time or run-time emission of operations to perform the
+required computation.
+
+Control Statements
+~~~~~~~~~~~~~~~~~~
+
+``control_statement``\ s are all the statements which modify the order of
+execution of the generated code according to input parameters. They are expanded
+by the following grammar rule:
+
+::
+
+ control_statement : frame_check
+ | cancel_statement
+ | if_statement
+ | for_statement
+ | fpart1_statement
+
+``if_statement``\ s require the emission of labels and branch instructions which
+effectively perform conditional jumps (``tcg_gen_brcondi``) according to the
+value of an expression. Note, the tinycode generators we produce for conditional
+statements do not perfectly mirror what would be expected in C, for instance we
+do not reproduce short-circuiting of the ``&&`` operator, and use of the ``||``
+operator is disallowed. All the predicated instructions, and in general all the
+instructions where there could be alternative values assigned to an ``lvalue``,
+like C-style ternary expressions:
+
+::
+
+ rvalue : rvalue QMARK rvalue COLON rvalue
+
+are handled using the conditional move tinycode instruction
+(``tcg_gen_movcond``), which avoids the additional complexity of managing labels
+and jumps.
+
+Instead, regarding the ``for`` loops, exploiting the fact that they always
+iterate on immediate values, therefore their iteration ranges are always known
+at compile time, we implemented those emitting plain C ``for`` loops. This is
+possible because the loops will be executed in the QEMU code, leading to the
+consequential unrolling of the for loop, since the tinycode generator
+instructions will be executed multiple times, and the respective generated
+tinycode will represent the unrolled execution of the loop.
+
+Parsing Context
+~~~~~~~~~~~~~~~
+
+All the helper functions in ``idef-parser.y`` carry two fixed parameters, which
+are the parsing context ``c`` and the ``YYLLOC`` location information. The
+context is explicitly passed to all the functions because the parser we generate
+is a reentrant one, meaning that it does not have any global variable, and
+therefore the instruction compilation could easily be parallelized in the
+future. Finally for each rule we propagate information about the location of the
+involved tokens to generate pretty error reporting, able to highlight the
+portion of the input code which generated each error.
+
+Debugging
+---------
+
+Developing the idef-parser can lead to two types of errors: compile-time errors
+and parsing errors.
+
+Compile-time errors in Bison-generated parsers are usually due to conflicts in
+the described grammar. Conflicts forbid the grammar to produce a unique
+derivation tree, thus must be solved (except for the dangling else problem,
+which is marked as expected through the ``%expect 1`` Bison option).
+
+For solving conflicts you need a basic understanding of `shift-reduce conflicts
+<https://www.gnu.org/software/Bison/manual/html_node/Shift_002fReduce.html>`__
+and `reduce-reduce conflicts
+<https://www.gnu.org/software/Bison/manual/html_node/Reduce_002fReduce.html>`__,
+then, if you are using a Bison version > 3.7.1 you can ask Bison to generate
+some counterexamples which highlight ambiguous derivations, passing the
+``-Wcex`` option to Bison. In general shift/reduce conflicts are solved by
+redesigning the grammar in an unambiguous way or by setting the token priority
+correctly, while reduce/reduce conflicts are solved by redesigning the
+interested part of the grammar.
+
+Run-time errors can be divided between lexing and parsing errors, lexing errors
+are hard to detect, since the ``var`` token will catch everything which is not
+catched by other tokens, but easy to fix, because most of the time a simple
+regex editing will be enough.
+
+idef-parser features a fancy parsing error reporting scheme, which for each
+parsing error reports the fragment of the input text which was involved in the
+parsing rule that generated an error.
+
+Implementing an instruction goes through several sequential steps, here are some
+suggestions to make each instruction proceed to the next step.
+
+- not-emitted
+
+ Means that the parsing of the input code relative to that instruction failed,
+ this could be due to a lexical error or to some mismatch between the order of
+ valid tokens and a parser rule. You should check that tokens are correctly
+ identified and mapped, and that there is a rule matching the token sequence
+ that you need to parse.
+
+- emitted
+
+ This instruction class contains all the instructions which are emitted but
+ fail to compile when included in QEMU. The compilation errors are shown by
+ the QEMU building process and will lead to fixing the bug. Most common
+ errors regard the mismatch of parameters for tinycode generator functions,
+ which boil down to errors in the idef-parser type system.
+
+- compiled
+
+ These instruction generate valid tinycode generator code, which however fail
+ the QEMU or the harness tests, these cases must be handled manually by
+ looking into the failing tests and looking at the generated tinycode
+ generator instruction and at the generated tinycode itself. Tip: handle the
+ failing harness tests first, because they usually feature only a single
+ instruction, thus will require less execution trace navigation. If a
+ multi-threaded test fail, fixing all the other tests will be the easier
+ option, hoping that the multi-threaded one will be indirectly fixed.
+
+ An example of debugging this type of failure is provided in the following
+ section.
+
+- tests-passed
+
+ This is the final goal for each instruction, meaning that the instruction
+ passes the test suite.
+
+Another approach to fix QEMU system test, where many instructions might fail, is
+to compare the execution trace of your implementation with the reference
+implementations already present in QEMU. To do so you should obtain a QEMU build
+where the instruction pass the test, and run it with the following command:
+
+::
+
+ sudo unshare -p sudo -u <USER> bash -c \
+ 'env -i <qemu-hexagon full path> -d cpu <TEST>'
+
+And do the same for your implementation, the generated execution traces will be
+inherently aligned and can be inspected for behavioral differences using the
+``diff`` tool.
+
+Example of debugging erroneous tinycode generator code
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The goal of this section is to provide a complete example of debugging
+incorrectly emitted tinycode generator for a single instruction.
+
+Let's first introduce a bug in the tinycode generator of the ``A2_add``
+instruction,
+
+::
+
+ void emit_A2_add(DisasContext *ctx, Insn *insn, Packet *pkt, TCGv_i32 RdV,
+ TCGv_i32 RsV, TCGv_i32 RtV)
+ /* RdV=RsV+RtV;} */
+ {
+ TCGv_i32 tmp_0 = tcg_temp_new_i32();
+ tcg_gen_add_i32(tmp_0, RsV, RsV);
+ tcg_gen_mov_i32(RdV, tmp_0);
+ tcg_temp_free_i32(tmp_0);
+ }
+
+Here the bug, albeit hard to spot, is in ``tcg_gen_add_i32(tmp_0, RsV, RsV);``
+where we compute ``RsV + RsV`` instead of ``RsV + RtV``, as would be expected.
+This particular bug is a bit tricky to pinpoint when debugging, since the
+``A2_add`` instruction is so ubiquitous. As a result, pretty much all tests will
+fail and therefore not provide a lot of information about the bug.
+
+For example, let's run the ``check-tcg`` tests
+
+::
+
+ make check-tcg TIMEOUT=1200 \
+ DOCKER_IMAGE=debian-hexagon-cross \
+ ENGINE=podman V=1 \
+ DOCKER_CROSS_CC_GUEST=hexagon-unknown-linux-musl-clang
+
+In the output, we find a failure in the very first test case ``float_convs``
+due to a segmentation fault. Similarly, all harness and libc tests will fail as
+well. At this point we have no clue where the actual bug lies, and need to start
+ruling out instructions. As such a good starting point is to utilize the debug
+options ``-d in_asm,cpu`` of QEMU to inspect the Hexagon instructions being run,
+alongside the CPU state. We additionally need a working version of the emulator
+to compare our buggy CPU state against, running
+
+::
+
+ meson configure -Dhexagon_idef_parser_enabled=false
+
+will disable the idef-parser for all instructions and fallback on manual
+tinycode generator overrides, or on helper function implementations. Recompiling
+gives us ``qemu-hexagon`` which passes all tests. If ``qemu-heaxgon-buggy`` is
+our binary with the incorrect tinycode generators, we can compare the CPU state
+between the two versions
+
+::
+
+ ./qemu-hexagon-buggy -d in_asm,cpu float_convs &> out_buggy
+ ./qemu-hexagon -d in_asm,cpu float_convs &> out_working
+
+Looking at ``diff -u out_buggy out_working`` shows us that the CPU state begins
+to diverge on line 141, with an incorrect value in the ``R1`` register
+
+::
+
+ @@ -138,7 +138,7 @@
+
+ General Purpose Registers = {
+ r0 = 0x4100f9c0
+ - r1 = 0x00042108
+ + r1 = 0x00000000
+ r2 = 0x00021084
+ r3 = 0x00000000
+ r4 = 0x00000000
+
+If we also look into ``out_buggy`` directly we can inspect the input assembly
+which the caused the incorrect CPU state, around line 141 we find
+
+::
+
+ 116 | ----------------
+ 117 | IN: _start_c
+ 118 | 0x000210b0: 0xa09dc002 { allocframe(R29,#0x10):raw }
+ ... | ...
+ 137 | 0x000210fc: 0x5a00c4aa { call PC+2388 }
+ 138 |
+ 139 | General Purpose Registers = {
+ 140 | r0 = 0x4100fa70
+ 141 | r1 = 0x00042108
+ 142 | r2 = 0x00021084
+ 143 | r3 = 0x00000000
+
+Importantly, we see some Hexagon assembly followed by a dump of the CPU state,
+now the CPU state is actually dumped before the input assembly above is ran.
+As such, we are actually interested in the instructions ran before this.
+
+Scrolling up a bit, we find
+
+::
+
+ 54 | ----------------
+ 55 | IN: _start
+ 56 | 0x00021088: 0x6a09c002 { R2 = C9/pc }
+ 57 | 0x0002108c: 0xbfe2ff82 { R2 = add(R2,#0xfffffffc) }
+ 58 | 0x00021090: 0x9182c001 { R1 = memw(R2+#0x0) }
+ 59 | 0x00021094: 0xf302c101 { R1 = add(R2,R1) }
+ 60 | 0x00021098: 0x7800c01e { R30 = #0x0 }
+ 61 | 0x0002109c: 0x707dc000 { R0 = R29 }
+ 62 | 0x000210a0: 0x763dfe1d { R29 = and(R29,#0xfffffff0) }
+ 63 | 0x000210a4: 0xa79dfdfe { memw(R29+#0xfffffff8) = R29 }
+ 64 | 0x000210a8: 0xbffdff1d { R29 = add(R29,#0xfffffff8) }
+ 65 | 0x000210ac: 0x5a00c002 { call PC+4 }
+ 66 |
+ 67 | General Purpose Registers = {
+ 68 | r0 = 0x00000000
+ 69 | r1 = 0x00000000
+ 70 | r2 = 0x00000000
+ 71 | r3 = 0x00000000
+
+Remember, the instructions on lines 56-65 are ran on the CPU state shown below
+instructions, and as the CPU state has not diverged at this point, we know the
+starting state is accurate. The bug must then lie within the instructions shown
+here. Next we may notice that ``R1`` is only touched by lines 57 and 58, that is
+by
+
+::
+
+ 58 | 0x00021090: 0x9182c001 { R1 = memw(R2+#0x0) }
+ 59 | 0x00021094: 0xf302c101 { R1 = add(R2,R1) }
+
+Therefore, we are either dealing with an correct load instruction
+``R1 = memw(R2+#0x0)`` or with an incorrect add ``R1 = add(R2,R1)``. At this
+point it might be easy enough to go directly to the emitted code for the
+instructions mentioned and look for bugs, but we could also run
+``./qemu-heaxgon -d op,in_asm float_conv`` where we find for the following
+tinycode for the Hexagon ``add`` instruction
+
+::
+
+ ---- 00021094
+ mov_i32 pkt_has_store_s1,$0x0
+ add_i32 tmp0,r2,r2
+ mov_i32 loc2,tmp0
+ mov_i32 new_r1,loc2
+ mov_i32 r1,new_r1
+
+Here we have finally located our bug ``add_i32 tmp0,r2,r2``.
+
+Limitations and Future Development
+----------------------------------
+
+The main limitation of the current parser is given by the syntax-driven nature
+of the Bison-generated parsers. This has the severe implication of only being
+able to generate code in the order of evaluation of the various rules, without,
+in any case, being able to backtrack and alter the generated code.
+
+An example limitation is highlighted by this statement of the input language:
+
+::
+
+ { (PsV==0xff) ? (PdV=0xff) : (PdV=0x00); }
+
+This ternary assignment, when written in this form requires us to emit some
+proper control flow statements, which emit a jump to the first or to the second
+code block, whose implementation is extremely convoluted, because when matching
+the ternary assignment, the code evaluating the two assignments will be already
+generated.
+
+Instead we pre-process that statement, making it become:
+
+::
+
+ { PdV = ((PsV==0xff)) ? 0xff : 0x00; }
+
+Which can be easily matched by the following parser rules:
+
+::
+
+ statement | rvalue ';'
+
+ rvalue : rvalue QMARK rvalue COLON rvalue
+ | rvalue EQ rvalue
+ | LPAR rvalue RPAR
+ | assign_statement
+ | IMM
+
+ assign_statement : pred ASSIGN rvalue
+
+Another example that highlight the limitation of the flex/bison parser can be
+found even in the add operation we already saw:
+
+::
+
+ TCGv_i32 tmp_0 = tcg_temp_new_i32();
+ tcg_gen_add_i32(tmp_0, RsV, RtV);
+ tcg_gen_mov_i32(RdV, tmp_0);
+
+The fact that we cannot directly use ``RdV`` as the destination of the sum is a
+consequence of the syntax-driven nature of the parser. In fact when we parse the
+assignment, the ``rvalue`` token, representing the sum has already been reduced,
+and thus its code emitted and unchangeable. We rely on the fact that QEMU will
+optimize our code reducing the useless move operations and the relative
+temporaries.
+
+A possible improvement of the parser regards the support for vectorial
+instructions and floating point instructions, which will require the extension
+of the scanner, the parser, and a partial re-design of the type system, allowing
+to build the vectorial semantics over the available vectorial tinycode generator
+primitives.
+
+A more radical improvement will use the parser, not to generate directly the
+tinycode generator code, but to generate an intermediate representation like the
+LLVM IR, which in turn could be compiled using the clang TCG backend. That code
+could be furtherly optimized, overcoming the limitations of the syntax-driven
+parsing and could lead to a more optimized generated code.
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v8 03/12] target/hexagon: make slot number an unsigned
2022-02-09 17:03 [PATCH v8 00/12] target/hexagon: introduce idef-parser Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 01/12] target/hexagon: update MAINTAINERS for idef-parser Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 02/12] target/hexagon: import README " Anton Johansson via
@ 2022-02-09 17:03 ` Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 04/12] target/hexagon: make helper functions non-static Anton Johansson via
` (8 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Anton Johansson via @ 2022-02-09 17:03 UTC (permalink / raw)
To: qemu-devel
Cc: ale, tsimpson, bcain, mlambert, babush, nizzo, richard.henderson
From: Paolo Montesel <babush@rev.ng>
Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Paolo Montesel <babush@rev.ng>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Taylor Simpson <tsimpson@quicinc.com>
---
target/hexagon/genptr.c | 24 +++++++++++++-----------
target/hexagon/macros.h | 2 +-
2 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index 4419d30e23..2f73300c90 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -30,7 +30,8 @@
#include "gen_tcg.h"
#include "gen_tcg_hvx.h"
-static inline void gen_log_predicated_reg_write(int rnum, TCGv val, int slot)
+static inline void gen_log_predicated_reg_write(int rnum, TCGv val,
+ uint32_t slot)
{
TCGv zero = tcg_constant_tl(0);
TCGv slot_mask = tcg_temp_new();
@@ -62,7 +63,8 @@ static inline void gen_log_reg_write(int rnum, TCGv val)
}
}
-static void gen_log_predicated_reg_write_pair(int rnum, TCGv_i64 val, int slot)
+static void gen_log_predicated_reg_write_pair(int rnum, TCGv_i64 val,
+ uint32_t slot)
{
TCGv val32 = tcg_temp_new();
TCGv zero = tcg_constant_tl(0);
@@ -390,7 +392,7 @@ static inline void gen_store_conditional8(DisasContext *ctx,
tcg_gen_movi_tl(hex_llsc_addr, ~0);
}
-static inline void gen_store32(TCGv vaddr, TCGv src, int width, int slot)
+static inline void gen_store32(TCGv vaddr, TCGv src, int width, uint32_t slot)
{
tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
tcg_gen_movi_tl(hex_store_width[slot], width);
@@ -398,49 +400,49 @@ static inline void gen_store32(TCGv vaddr, TCGv src, int width, int slot)
}
static inline void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src,
- DisasContext *ctx, int slot)
+ DisasContext *ctx, uint32_t slot)
{
gen_store32(vaddr, src, 1, slot);
ctx->store_width[slot] = 1;
}
static inline void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
- DisasContext *ctx, int slot)
+ DisasContext *ctx, uint32_t slot)
{
TCGv tmp = tcg_constant_tl(src);
gen_store1(cpu_env, vaddr, tmp, ctx, slot);
}
static inline void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src,
- DisasContext *ctx, int slot)
+ DisasContext *ctx, uint32_t slot)
{
gen_store32(vaddr, src, 2, slot);
ctx->store_width[slot] = 2;
}
static inline void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
- DisasContext *ctx, int slot)
+ DisasContext *ctx, uint32_t slot)
{
TCGv tmp = tcg_constant_tl(src);
gen_store2(cpu_env, vaddr, tmp, ctx, slot);
}
static inline void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src,
- DisasContext *ctx, int slot)
+ DisasContext *ctx, uint32_t slot)
{
gen_store32(vaddr, src, 4, slot);
ctx->store_width[slot] = 4;
}
static inline void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
- DisasContext *ctx, int slot)
+ DisasContext *ctx, uint32_t slot)
{
TCGv tmp = tcg_constant_tl(src);
gen_store4(cpu_env, vaddr, tmp, ctx, slot);
}
static inline void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src,
- DisasContext *ctx, int slot)
+ DisasContext *ctx, uint32_t slot)
{
tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
tcg_gen_movi_tl(hex_store_width[slot], 8);
@@ -449,7 +451,7 @@ static inline void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src,
}
static inline void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src,
- DisasContext *ctx, int slot)
+ DisasContext *ctx, uint32_t slot)
{
TCGv_i64 tmp = tcg_constant_i64(src);
gen_store8(cpu_env, vaddr, tmp, ctx, slot);
diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h
index 19d103cad5..3a64357090 100644
--- a/target/hexagon/macros.h
+++ b/target/hexagon/macros.h
@@ -185,7 +185,7 @@
#define LOAD_CANCEL(EA) do { CANCEL; } while (0)
#ifdef QEMU_GENERATE
-static inline void gen_pred_cancel(TCGv pred, int slot_num)
+static inline void gen_pred_cancel(TCGv pred, uint32_t slot_num)
{
TCGv slot_mask = tcg_temp_new();
TCGv tmp = tcg_temp_new();
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v8 04/12] target/hexagon: make helper functions non-static
2022-02-09 17:03 [PATCH v8 00/12] target/hexagon: introduce idef-parser Anton Johansson via
` (2 preceding siblings ...)
2022-02-09 17:03 ` [PATCH v8 03/12] target/hexagon: make slot number an unsigned Anton Johansson via
@ 2022-02-09 17:03 ` Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 05/12] target/hexagon: introduce new helper functions Anton Johansson via
` (7 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Anton Johansson via @ 2022-02-09 17:03 UTC (permalink / raw)
To: qemu-devel
Cc: ale, tsimpson, bcain, mlambert, babush, nizzo, richard.henderson
From: Paolo Montesel <babush@rev.ng>
Make certain helper functions non-static, making them available outside
genptr.c. These functions are required by code generated by the
idef-parser.
This commit also makes some op_helper.c non-static in order to avoid
having them marked as unused when using the idef-parser generated code.
Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Paolo Montesel <babush@rev.ng>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Taylor Simpson <tsimpson@quicinc.com>
---
target/hexagon/genptr.c | 59 +++++++++++++++++++++-----------------
target/hexagon/genptr.h | 30 +++++++++++++++++++
target/hexagon/op_helper.c | 29 +++++++++----------
target/hexagon/op_helper.h | 37 ++++++++++++++++++++++++
4 files changed, 113 insertions(+), 42 deletions(-)
create mode 100644 target/hexagon/op_helper.h
diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index 2f73300c90..ae798e921e 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -29,6 +29,13 @@
#undef QEMU_GENERATE
#include "gen_tcg.h"
#include "gen_tcg_hvx.h"
+#include "genptr.h"
+
+TCGv gen_read_preg(TCGv pred, uint8_t num)
+{
+ tcg_gen_mov_tl(pred, hex_pred[num]);
+ return pred;
+}
static inline void gen_log_predicated_reg_write(int rnum, TCGv val,
uint32_t slot)
@@ -54,7 +61,7 @@ static inline void gen_log_predicated_reg_write(int rnum, TCGv val,
tcg_temp_free(slot_mask);
}
-static inline void gen_log_reg_write(int rnum, TCGv val)
+void gen_log_reg_write(int rnum, TCGv val)
{
tcg_gen_mov_tl(hex_new_value[rnum], val);
if (HEX_DEBUG) {
@@ -116,7 +123,7 @@ static void gen_log_reg_write_pair(int rnum, TCGv_i64 val)
}
}
-static inline void gen_log_pred_write(DisasContext *ctx, int pnum, TCGv val)
+void gen_log_pred_write(DisasContext *ctx, int pnum, TCGv val)
{
TCGv base_val = tcg_temp_new();
@@ -270,7 +277,7 @@ static inline void gen_write_ctrl_reg_pair(DisasContext *ctx, int reg_num,
}
}
-static TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign)
+TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign)
{
if (sign) {
tcg_gen_sextract_tl(result, src, N * 8, 8);
@@ -280,7 +287,7 @@ static TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign)
return result;
}
-static TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign)
+TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign)
{
TCGv_i64 res64 = tcg_temp_new_i64();
if (sign) {
@@ -294,7 +301,7 @@ static TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign)
return result;
}
-static inline TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign)
+TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign)
{
if (sign) {
tcg_gen_sextract_tl(result, src, N * 16, 16);
@@ -304,12 +311,12 @@ static inline TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign)
return result;
}
-static inline void gen_set_half(int N, TCGv result, TCGv src)
+void gen_set_half(int N, TCGv result, TCGv src)
{
tcg_gen_deposit_tl(result, result, src, N * 16, 16);
}
-static inline void gen_set_half_i64(int N, TCGv_i64 result, TCGv src)
+void gen_set_half_i64(int N, TCGv_i64 result, TCGv src)
{
TCGv_i64 src64 = tcg_temp_new_i64();
tcg_gen_extu_i32_i64(src64, src);
@@ -317,7 +324,7 @@ static inline void gen_set_half_i64(int N, TCGv_i64 result, TCGv src)
tcg_temp_free_i64(src64);
}
-static void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src)
+void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src)
{
TCGv_i64 src64 = tcg_temp_new_i64();
tcg_gen_extu_i32_i64(src64, src);
@@ -392,57 +399,57 @@ static inline void gen_store_conditional8(DisasContext *ctx,
tcg_gen_movi_tl(hex_llsc_addr, ~0);
}
-static inline void gen_store32(TCGv vaddr, TCGv src, int width, uint32_t slot)
+void gen_store32(TCGv vaddr, TCGv src, int width, uint32_t slot)
{
tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
tcg_gen_movi_tl(hex_store_width[slot], width);
tcg_gen_mov_tl(hex_store_val32[slot], src);
}
-static inline void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src,
- DisasContext *ctx, uint32_t slot)
+void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
+ uint32_t slot)
{
gen_store32(vaddr, src, 1, slot);
ctx->store_width[slot] = 1;
}
-static inline void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
- DisasContext *ctx, uint32_t slot)
+void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src, DisasContext *ctx,
+ uint32_t slot)
{
TCGv tmp = tcg_constant_tl(src);
gen_store1(cpu_env, vaddr, tmp, ctx, slot);
}
-static inline void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src,
- DisasContext *ctx, uint32_t slot)
+void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
+ uint32_t slot)
{
gen_store32(vaddr, src, 2, slot);
ctx->store_width[slot] = 2;
}
-static inline void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
- DisasContext *ctx, uint32_t slot)
+void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src, DisasContext *ctx,
+ uint32_t slot)
{
TCGv tmp = tcg_constant_tl(src);
gen_store2(cpu_env, vaddr, tmp, ctx, slot);
}
-static inline void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src,
- DisasContext *ctx, uint32_t slot)
+void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
+ uint32_t slot)
{
gen_store32(vaddr, src, 4, slot);
ctx->store_width[slot] = 4;
}
-static inline void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
- DisasContext *ctx, uint32_t slot)
+void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src, DisasContext *ctx,
+ uint32_t slot)
{
TCGv tmp = tcg_constant_tl(src);
gen_store4(cpu_env, vaddr, tmp, ctx, slot);
}
-static inline void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src,
- DisasContext *ctx, uint32_t slot)
+void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src, DisasContext *ctx,
+ uint32_t slot)
{
tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
tcg_gen_movi_tl(hex_store_width[slot], 8);
@@ -450,14 +457,14 @@ static inline void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src,
ctx->store_width[slot] = 8;
}
-static inline void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src,
- DisasContext *ctx, uint32_t slot)
+void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src, DisasContext *ctx,
+ uint32_t slot)
{
TCGv_i64 tmp = tcg_constant_i64(src);
gen_store8(cpu_env, vaddr, tmp, ctx, slot);
}
-static TCGv gen_8bitsof(TCGv result, TCGv value)
+TCGv gen_8bitsof(TCGv result, TCGv value)
{
TCGv zero = tcg_constant_tl(0);
TCGv ones = tcg_constant_tl(0xff);
diff --git a/target/hexagon/genptr.h b/target/hexagon/genptr.h
index c158005d2a..d71dd7e1ce 100644
--- a/target/hexagon/genptr.h
+++ b/target/hexagon/genptr.h
@@ -19,7 +19,37 @@
#define HEXAGON_GENPTR_H
#include "insn.h"
+#include "tcg/tcg.h"
+#include "translate.h"
extern const SemanticInsn opcode_genptr[];
+void gen_store32(TCGv vaddr, TCGv src, int width, uint32_t slot);
+void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
+ uint32_t slot);
+void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
+ uint32_t slot);
+void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
+ uint32_t slot);
+void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src, DisasContext *ctx,
+ uint32_t slot);
+void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src, DisasContext *ctx,
+ uint32_t slot);
+void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src, DisasContext *ctx,
+ uint32_t slot);
+void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src, DisasContext *ctx,
+ uint32_t slot);
+void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src, DisasContext *ctx,
+ uint32_t slot);
+TCGv gen_read_preg(TCGv pred, uint8_t num);
+void gen_log_reg_write(int rnum, TCGv val);
+void gen_log_pred_write(DisasContext *ctx, int pnum, TCGv val);
+TCGv gen_8bitsof(TCGv result, TCGv value);
+void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src);
+TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign);
+TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign);
+TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign);
+void gen_set_half(int N, TCGv result, TCGv src);
+void gen_set_half_i64(int N, TCGv_i64 result, TCGv src);
+
#endif
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 057baf9a48..722a115007 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -29,6 +29,7 @@
#include "fma_emu.h"
#include "mmvec/mmvec.h"
#include "mmvec/macros.h"
+#include "op_helper.h"
#define SF_BIAS 127
#define SF_MANTBITS 23
@@ -49,8 +50,8 @@ void QEMU_NORETURN HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp)
do_raise_exception_err(env, excp, 0);
}
-static void log_reg_write(CPUHexagonState *env, int rnum,
- target_ulong val, uint32_t slot)
+void log_reg_write(CPUHexagonState *env, int rnum, target_ulong val,
+ uint32_t slot)
{
HEX_DEBUG_LOG("log_reg_write[%d] = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")",
rnum, val, val);
@@ -81,8 +82,8 @@ static void log_pred_write(CPUHexagonState *env, int pnum, target_ulong val)
}
}
-static void log_store32(CPUHexagonState *env, target_ulong addr,
- target_ulong val, int width, int slot)
+void log_store32(CPUHexagonState *env, target_ulong addr, target_ulong val,
+ int width, int slot)
{
HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
", %" PRId32 " [0x08%" PRIx32 "])\n",
@@ -92,8 +93,8 @@ static void log_store32(CPUHexagonState *env, target_ulong addr,
env->mem_log_stores[slot].data32 = val;
}
-static void log_store64(CPUHexagonState *env, target_ulong addr,
- int64_t val, int width, int slot)
+void log_store64(CPUHexagonState *env, target_ulong addr, int64_t val,
+ int width, int slot)
{
HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
", %" PRId64 " [0x016%" PRIx64 "])\n",
@@ -103,7 +104,7 @@ static void log_store64(CPUHexagonState *env, target_ulong addr,
env->mem_log_stores[slot].data64 = val;
}
-static void write_new_pc(CPUHexagonState *env, target_ulong addr)
+void write_new_pc(CPUHexagonState *env, target_ulong addr)
{
HEX_DEBUG_LOG("write_new_pc(0x" TARGET_FMT_lx ")\n", addr);
@@ -521,32 +522,28 @@ static void check_noshuf(CPUHexagonState *env, uint32_t slot)
}
}
-static uint8_t mem_load1(CPUHexagonState *env, uint32_t slot,
- target_ulong vaddr)
+uint8_t mem_load1(CPUHexagonState *env, uint32_t slot, target_ulong vaddr)
{
uintptr_t ra = GETPC();
check_noshuf(env, slot);
return cpu_ldub_data_ra(env, vaddr, ra);
}
-static uint16_t mem_load2(CPUHexagonState *env, uint32_t slot,
- target_ulong vaddr)
+uint16_t mem_load2(CPUHexagonState *env, uint32_t slot, target_ulong vaddr)
{
uintptr_t ra = GETPC();
check_noshuf(env, slot);
return cpu_lduw_data_ra(env, vaddr, ra);
}
-static uint32_t mem_load4(CPUHexagonState *env, uint32_t slot,
- target_ulong vaddr)
+uint32_t mem_load4(CPUHexagonState *env, uint32_t slot, target_ulong vaddr)
{
uintptr_t ra = GETPC();
check_noshuf(env, slot);
return cpu_ldl_data_ra(env, vaddr, ra);
}
-static uint64_t mem_load8(CPUHexagonState *env, uint32_t slot,
- target_ulong vaddr)
+uint64_t mem_load8(CPUHexagonState *env, uint32_t slot, target_ulong vaddr)
{
uintptr_t ra = GETPC();
check_noshuf(env, slot);
@@ -1459,7 +1456,7 @@ void HELPER(vwhist128qm)(CPUHexagonState *env, int32_t uiV)
}
}
-static void cancel_slot(CPUHexagonState *env, uint32_t slot)
+void cancel_slot(CPUHexagonState *env, uint32_t slot)
{
HEX_DEBUG_LOG("Slot %d cancelled\n", slot);
env->slot_cancelled |= (1 << slot);
diff --git a/target/hexagon/op_helper.h b/target/hexagon/op_helper.h
new file mode 100644
index 0000000000..2d39637b8f
--- /dev/null
+++ b/target/hexagon/op_helper.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HEXAGON_OP_HELPER_H
+#define HEXAGON_OP_HELPER_H
+
+/* Misc functions */
+void cancel_slot(CPUHexagonState *env, uint32_t slot);
+void write_new_pc(CPUHexagonState *env, target_ulong addr);
+
+uint8_t mem_load1(CPUHexagonState *env, uint32_t slot, target_ulong vaddr);
+uint16_t mem_load2(CPUHexagonState *env, uint32_t slot, target_ulong vaddr);
+uint32_t mem_load4(CPUHexagonState *env, uint32_t slot, target_ulong vaddr);
+uint64_t mem_load8(CPUHexagonState *env, uint32_t slot, target_ulong vaddr);
+
+void log_reg_write(CPUHexagonState *env, int rnum, target_ulong val,
+ uint32_t slot);
+void log_store64(CPUHexagonState *env, target_ulong addr, int64_t val,
+ int width, int slot);
+void log_store32(CPUHexagonState *env, target_ulong addr, target_ulong val,
+ int width, int slot);
+
+#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v8 05/12] target/hexagon: introduce new helper functions
2022-02-09 17:03 [PATCH v8 00/12] target/hexagon: introduce idef-parser Anton Johansson via
` (3 preceding siblings ...)
2022-02-09 17:03 ` [PATCH v8 04/12] target/hexagon: make helper functions non-static Anton Johansson via
@ 2022-02-09 17:03 ` Anton Johansson via
2022-03-21 18:28 ` Taylor Simpson
2022-02-09 17:03 ` [PATCH v8 06/12] target/hexagon: expose next PC in DisasContext Anton Johansson via
` (6 subsequent siblings)
11 siblings, 1 reply; 23+ messages in thread
From: Anton Johansson via @ 2022-02-09 17:03 UTC (permalink / raw)
To: qemu-devel
Cc: ale, tsimpson, bcain, mlambert, babush, nizzo, richard.henderson
From: Niccolò Izzo <nizzo@rev.ng>
These helpers will be employed by the idef-parser generated code, to
correctly implement instruction semantics. "Helper" functions, in the
context of this patch, refers to functions which provide a manual TCG
implementation of certain features.
Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Niccolò Izzo <nizzo@rev.ng>
Signed-off-by: Anton Johansson <anjo@rev.ng>
---
target/hexagon/genptr.c | 167 ++++++++++++++++++++++++++++++++++++++--
target/hexagon/genptr.h | 16 +++-
target/hexagon/macros.h | 9 +++
3 files changed, 184 insertions(+), 8 deletions(-)
diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index ae798e921e..9d0c1fe2df 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -31,6 +31,12 @@
#include "gen_tcg_hvx.h"
#include "genptr.h"
+TCGv gen_read_reg(TCGv result, int num)
+{
+ tcg_gen_mov_tl(result, hex_gpr[num]);
+ return result;
+}
+
TCGv gen_read_preg(TCGv pred, uint8_t num)
{
tcg_gen_mov_tl(pred, hex_pred[num]);
@@ -399,18 +405,19 @@ static inline void gen_store_conditional8(DisasContext *ctx,
tcg_gen_movi_tl(hex_llsc_addr, ~0);
}
-void gen_store32(TCGv vaddr, TCGv src, int width, uint32_t slot)
+void gen_store32(DisasContext *ctx, TCGv vaddr, TCGv src, tcg_target_long width,
+ uint32_t slot)
{
tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
tcg_gen_movi_tl(hex_store_width[slot], width);
tcg_gen_mov_tl(hex_store_val32[slot], src);
+ ctx->store_width[slot] = width;
}
void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
uint32_t slot)
{
- gen_store32(vaddr, src, 1, slot);
- ctx->store_width[slot] = 1;
+ gen_store32(ctx, vaddr, src, 1, slot);
}
void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src, DisasContext *ctx,
@@ -423,8 +430,7 @@ void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src, DisasContext *ctx,
void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
uint32_t slot)
{
- gen_store32(vaddr, src, 2, slot);
- ctx->store_width[slot] = 2;
+ gen_store32(ctx, vaddr, src, 2, slot);
}
void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src, DisasContext *ctx,
@@ -437,8 +443,7 @@ void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src, DisasContext *ctx,
void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
uint32_t slot)
{
- gen_store32(vaddr, src, 4, slot);
- ctx->store_width[slot] = 4;
+ gen_store32(ctx, vaddr, src, 4, slot);
}
void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src, DisasContext *ctx,
@@ -643,5 +648,153 @@ static void vec_to_qvec(size_t size, intptr_t dstoff, intptr_t srcoff)
tcg_temp_free_i64(mask);
}
+void gen_set_usr_field(int field, TCGv val)
+{
+ /*
+ * Apparently tcg_gen_deposit_i32/64 doesn't OR the input value
+ * with the previously present one, as deposit32/64 in bitops.h
+ * does. We therefore copy the old value to `old_usr` to later
+ * OR with it to replicate this behavior.
+ */
+ TCGv_i32 old_usr = tcg_temp_new_i32();
+ tcg_gen_mov_i32(old_usr, hex_new_value[HEX_REG_USR]);
+ tcg_gen_deposit_tl(hex_new_value[HEX_REG_USR], hex_new_value[HEX_REG_USR],
+ val,
+ reg_field_info[field].offset,
+ reg_field_info[field].width);
+ tcg_gen_or_i32(hex_new_value[HEX_REG_USR],
+ old_usr,
+ hex_new_value[HEX_REG_USR]);
+ tcg_temp_free(old_usr);
+}
+
+void gen_set_usr_fieldi(int field, int x)
+{
+ TCGv val = tcg_constant_tl(x);
+ gen_set_usr_field(field, val);
+}
+
+void gen_write_new_pc(TCGv addr)
+{
+ /* If there are multiple branches in a packet, ignore the second one */
+ TCGv zero = tcg_constant_tl(0);
+ tcg_gen_movcond_tl(TCG_COND_NE, hex_next_PC, hex_branch_taken, zero,
+ hex_next_PC, addr);
+ tcg_gen_movi_tl(hex_branch_taken, 1);
+}
+
+void gen_sat_i32(TCGv dest, TCGv source, int width)
+{
+ TCGv max_val = tcg_constant_tl((1 << (width - 1)) - 1);
+ TCGv min_val = tcg_constant_tl(-(1 << (width - 1)));
+ tcg_gen_smin_tl(dest, source, max_val);
+ tcg_gen_smax_tl(dest, dest, min_val);
+}
+
+void gen_sat_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width)
+{
+ gen_sat_i32(dest, source, width);
+ tcg_gen_setcond_tl(TCG_COND_NE, ovfl, source, dest);
+}
+
+void gen_satu_i32(TCGv dest, TCGv source, int width)
+{
+ TCGv max_val = tcg_constant_tl((1 << width) - 1);
+ TCGv zero = tcg_constant_tl(0);
+ tcg_gen_movcond_tl(TCG_COND_GTU, dest, source, max_val, max_val, source);
+ tcg_gen_movcond_tl(TCG_COND_LT, dest, source, zero, zero, dest);
+}
+
+void gen_satu_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width)
+{
+ gen_satu_i32(dest, source, width);
+ tcg_gen_setcond_tl(TCG_COND_NE, ovfl, source, dest);
+}
+
+void gen_sat_i64(TCGv_i64 dest, TCGv_i64 source, int width)
+{
+ TCGv_i64 max_val = tcg_constant_i64((1LL << (width - 1)) - 1LL);
+ TCGv_i64 min_val = tcg_constant_i64(-(1LL << (width - 1)));
+ tcg_gen_smin_i64(dest, source, max_val);
+ tcg_gen_smax_i64(dest, dest, min_val);
+}
+
+void gen_sat_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width)
+{
+ TCGv_i64 ovfl_64;
+ gen_sat_i64(dest, source, width);
+ ovfl_64 = tcg_temp_new_i64();
+ tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, dest, source);
+ tcg_gen_trunc_i64_tl(ovfl, ovfl_64);
+ tcg_temp_free_i64(ovfl_64);
+}
+
+void gen_satu_i64(TCGv_i64 dest, TCGv_i64 source, int width)
+{
+ TCGv_i64 max_val = tcg_constant_i64((1LL << width) - 1LL);
+ TCGv_i64 zero = tcg_constant_i64(0);
+ tcg_gen_movcond_i64(TCG_COND_GTU, dest, source, max_val, max_val, source);
+ tcg_gen_movcond_i64(TCG_COND_LT, dest, source, zero, zero, dest);
+}
+
+void gen_satu_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width)
+{
+ TCGv_i64 ovfl_64;
+ gen_satu_i64(dest, source, width);
+ ovfl_64 = tcg_temp_new_i64();
+ tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, dest, source);
+ tcg_gen_trunc_i64_tl(ovfl, ovfl_64);
+ tcg_temp_free_i64(ovfl_64);
+}
+
+/* Implements the fADDSAT64 macro in TCG */
+void gen_add_sat_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b)
+{
+ TCGv_i64 sum = tcg_temp_local_new_i64();
+ TCGv_i64 xor = tcg_temp_new_i64();
+ TCGv_i64 cond1 = tcg_temp_new_i64();
+ TCGv_i64 cond2 = tcg_temp_local_new_i64();
+ TCGv_i64 cond3 = tcg_temp_new_i64();
+ TCGv_i64 mask = tcg_constant_i64(0x8000000000000000ULL);
+ TCGv_i64 max_pos = tcg_constant_i64(0x7FFFFFFFFFFFFFFFLL);
+ TCGv_i64 max_neg = tcg_constant_i64(0x8000000000000000LL);
+ TCGv_i64 zero = tcg_constant_i64(0);
+ TCGLabel *no_ovfl_label = gen_new_label();
+ TCGLabel *ovfl_label = gen_new_label();
+ TCGLabel *ret_label = gen_new_label();
+
+ tcg_gen_add_i64(sum, a, b);
+ tcg_gen_xor_i64(xor, a, b);
+
+ /* if (xor & mask) */
+ tcg_gen_and_i64(cond1, xor, mask);
+ tcg_temp_free_i64(xor);
+ tcg_gen_brcondi_i64(TCG_COND_NE, cond1, 0, no_ovfl_label);
+ tcg_temp_free_i64(cond1);
+
+ /* else if ((a ^ sum) & mask) */
+ tcg_gen_xor_i64(cond2, a, sum);
+ tcg_gen_and_i64(cond2, cond2, mask);
+ tcg_gen_brcondi_i64(TCG_COND_NE, cond2, 0, ovfl_label);
+ tcg_temp_free_i64(cond2);
+ /* fallthrough to no_ovfl_label branch */
+
+ /* if branch */
+ gen_set_label(no_ovfl_label);
+ tcg_gen_mov_i64(ret, sum);
+ tcg_gen_br(ret_label);
+
+ /* else if branch */
+ gen_set_label(ovfl_label);
+ tcg_gen_and_i64(cond3, sum, mask);
+ tcg_temp_free_i64(mask);
+ tcg_temp_free_i64(sum);
+ tcg_gen_movcond_i64(TCG_COND_NE, ret, cond3, zero, max_pos, max_neg);
+ tcg_temp_free_i64(cond3);
+ SET_USR_FIELD(USR_OVF, 1);
+
+ gen_set_label(ret_label);
+}
+
#include "tcg_funcs_generated.c.inc"
#include "tcg_func_table_generated.c.inc"
diff --git a/target/hexagon/genptr.h b/target/hexagon/genptr.h
index d71dd7e1ce..e4e248d6f4 100644
--- a/target/hexagon/genptr.h
+++ b/target/hexagon/genptr.h
@@ -24,7 +24,8 @@
extern const SemanticInsn opcode_genptr[];
-void gen_store32(TCGv vaddr, TCGv src, int width, uint32_t slot);
+void gen_store32(DisasContext *ctx, TCGv vaddr, TCGv src, tcg_target_long width,
+ uint32_t slot);
void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
uint32_t slot);
void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src, DisasContext *ctx,
@@ -44,6 +45,18 @@ void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src, DisasContext *ctx,
TCGv gen_read_preg(TCGv pred, uint8_t num);
void gen_log_reg_write(int rnum, TCGv val);
void gen_log_pred_write(DisasContext *ctx, int pnum, TCGv val);
+void gen_write_new_pc(TCGv addr);
+void gen_set_usr_field(int field, TCGv val);
+void gen_set_usr_fieldi(int field, int x);
+void gen_sat_i32(TCGv dest, TCGv source, int width);
+void gen_sat_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width);
+void gen_satu_i32(TCGv dest, TCGv source, int width);
+void gen_satu_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width);
+void gen_sat_i64(TCGv_i64 dest, TCGv_i64 source, int width);
+void gen_sat_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width);
+void gen_satu_i64(TCGv_i64 dest, TCGv_i64 source, int width);
+void gen_satu_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width);
+void gen_add_sat_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b);
TCGv gen_8bitsof(TCGv result, TCGv value);
void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src);
TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign);
@@ -51,5 +64,6 @@ TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign);
TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign);
void gen_set_half(int N, TCGv result, TCGv src);
void gen_set_half_i64(int N, TCGv_i64 result, TCGv src);
+TCGv gen_read_reg(TCGv result, int num);
#endif
diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h
index 3a64357090..2e2764ddc8 100644
--- a/target/hexagon/macros.h
+++ b/target/hexagon/macros.h
@@ -180,7 +180,16 @@
#define MEM_STORE8(VA, DATA, SLOT) log_store64(env, VA, DATA, 8, SLOT)
#endif
+#ifdef QEMU_GENERATE
+static inline void gen_cancel(uint32_t slot)
+{
+ tcg_gen_ori_tl(hex_slot_cancelled, hex_slot_cancelled, 1 << slot);
+}
+
+#define CANCEL gen_cancel(slot);
+#else
#define CANCEL cancel_slot(env, slot)
+#endif
#define LOAD_CANCEL(EA) do { CANCEL; } while (0)
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v8 06/12] target/hexagon: expose next PC in DisasContext
2022-02-09 17:03 [PATCH v8 00/12] target/hexagon: introduce idef-parser Anton Johansson via
` (4 preceding siblings ...)
2022-02-09 17:03 ` [PATCH v8 05/12] target/hexagon: introduce new helper functions Anton Johansson via
@ 2022-02-09 17:03 ` Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 07/12] target/hexagon: prepare input for the idef-parser Anton Johansson via
` (5 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Anton Johansson via @ 2022-02-09 17:03 UTC (permalink / raw)
To: qemu-devel
Cc: ale, tsimpson, bcain, mlambert, babush, nizzo, richard.henderson
From: Paolo Montesel <babush@rev.ng>
Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Paolo Montesel <babush@rev.ng>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Taylor Simpson <tsimpson@quicinc.com>
---
target/hexagon/translate.c | 3 ++-
target/hexagon/translate.h | 1 +
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index b6f541ecb2..d4d4bcf3b2 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -741,11 +741,12 @@ static void decode_and_translate_packet(CPUHexagonState *env, DisasContext *ctx)
if (decode_packet(nwords, words, &pkt, false) > 0) {
HEX_DEBUG_PRINT_PKT(&pkt);
gen_start_packet(ctx, &pkt);
+ ctx->npc = ctx->base.pc_next + pkt.encod_pkt_size_in_bytes;
for (i = 0; i < pkt.num_insns; i++) {
gen_insn(env, ctx, &pkt.insn[i], &pkt);
}
gen_commit_packet(env, ctx, &pkt);
- ctx->base.pc_next += pkt.encod_pkt_size_in_bytes;
+ ctx->base.pc_next = ctx->npc;
} else {
gen_exception_end_tb(ctx, HEX_EXCP_INVALID_PACKET);
}
diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h
index fccfb94340..0eb96b9621 100644
--- a/target/hexagon/translate.h
+++ b/target/hexagon/translate.h
@@ -52,6 +52,7 @@ typedef struct DisasContext {
bool qreg_is_predicated[NUM_QREGS];
int qreg_log_idx;
bool pre_commit;
+ uint32_t npc;
} DisasContext;
static inline void ctx_log_reg_write(DisasContext *ctx, int rnum)
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v8 07/12] target/hexagon: prepare input for the idef-parser
2022-02-09 17:03 [PATCH v8 00/12] target/hexagon: introduce idef-parser Anton Johansson via
` (5 preceding siblings ...)
2022-02-09 17:03 ` [PATCH v8 06/12] target/hexagon: expose next PC in DisasContext Anton Johansson via
@ 2022-02-09 17:03 ` Anton Johansson via
2022-03-21 18:33 ` Taylor Simpson
2022-02-09 17:03 ` [PATCH v8 08/12] target/hexagon: import flex/bison to docker files Anton Johansson via
` (4 subsequent siblings)
11 siblings, 1 reply; 23+ messages in thread
From: Anton Johansson via @ 2022-02-09 17:03 UTC (permalink / raw)
To: qemu-devel
Cc: ale, tsimpson, bcain, mlambert, babush, nizzo, richard.henderson
From: Alessandro Di Federico <ale@rev.ng>
Introduce infrastructure necessary to produce a file suitable for being
parsed by the idef-parser.
Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Anton Johansson <anjo@rev.ng>
---
target/hexagon/gen_idef_parser_funcs.py | 125 +++++++++++++++++++++
target/hexagon/idef-parser/macros.inc | 140 ++++++++++++++++++++++++
target/hexagon/idef-parser/prepare | 24 ++++
target/hexagon/meson.build | 17 +++
4 files changed, 306 insertions(+)
create mode 100644 target/hexagon/gen_idef_parser_funcs.py
create mode 100644 target/hexagon/idef-parser/macros.inc
create mode 100755 target/hexagon/idef-parser/prepare
diff --git a/target/hexagon/gen_idef_parser_funcs.py b/target/hexagon/gen_idef_parser_funcs.py
new file mode 100644
index 0000000000..5a802d08aa
--- /dev/null
+++ b/target/hexagon/gen_idef_parser_funcs.py
@@ -0,0 +1,125 @@
+#!/usr/bin/env python3
+
+##
+## Copyright(c) 2019-2021 rev.ng Labs Srl. All Rights Reserved.
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+##
+
+import sys
+import re
+import string
+from io import StringIO
+
+import hex_common
+
+##
+## Generate code to be fed to the idef_parser
+##
+## Consider A2_add:
+##
+## Rd32=add(Rs32,Rt32), { RdV=RsV+RtV;}
+##
+## We produce:
+##
+## A2_add(RdV, in RsV, in RtV) {
+## { RdV=RsV+RtV;}
+## }
+##
+## A2_add represents the instruction tag. Then we have a list of TCGv
+## that the code generated by the parser can expect in input. Some of
+## them are inputs ("in" prefix), while some others are outputs.
+##
+def main():
+ hex_common.read_semantics_file(sys.argv[1])
+ hex_common.read_attribs_file(sys.argv[2])
+ hex_common.calculate_attribs()
+ tagregs = hex_common.get_tagregs()
+ tagimms = hex_common.get_tagimms()
+
+ with open(sys.argv[3], 'w') as f:
+ f.write('#include "macros.inc"\n\n')
+
+ for tag in hex_common.tags:
+ ## Skip the priv instructions
+ if ( "A_PRIV" in hex_common.attribdict[tag] ) :
+ continue
+ ## Skip the guest instructions
+ if ( "A_GUEST" in hex_common.attribdict[tag] ) :
+ continue
+ ## Skip instructions using switch
+ if ( tag in {'S4_vrcrotate_acc', 'S4_vrcrotate'} ) :
+ continue
+ ## Skip trap instructions
+ if ( tag in {'J2_trap0', 'J2_trap1'} ) :
+ continue
+ ## Skip 128-bit instructions
+ if ( tag in {'A7_croundd_ri', 'A7_croundd_rr'} ) :
+ continue
+ if ( tag in {'M7_wcmpyrw', 'M7_wcmpyrwc',
+ 'M7_wcmpyiw', 'M7_wcmpyiwc',
+ 'M7_wcmpyrw_rnd', 'M7_wcmpyrwc_rnd',
+ 'M7_wcmpyiw_rnd', 'M7_wcmpyiwc_rnd'} ) :
+ continue
+ ## Skip interleave/deinterleave instructions
+ if ( tag in {'S2_interleave', 'S2_deinterleave'} ) :
+ continue
+ ## Skip instructions using bit reverse
+ if ( tag in {'S2_brev', 'S2_brevp', 'S2_ct0', 'S2_ct1',
+ 'S2_ct0p', 'S2_ct1p', 'A4_tlbmatch'} ) :
+ continue
+ ## Skip other unsupported instructions
+ if ( tag == 'S2_cabacdecbin' or tag == 'A5_ACS' ) :
+ continue
+ if ( tag.startswith('Y') ) :
+ continue
+ if ( tag.startswith('V6_') ) :
+ continue
+ if ( tag.startswith('F') ) :
+ continue
+ if ( tag.endswith('_locked') ) :
+ continue
+
+ regs = tagregs[tag]
+ imms = tagimms[tag]
+
+ arguments = []
+ for regtype,regid,toss,numregs in regs:
+ prefix = "in " if hex_common.is_read(regid) else ""
+
+ is_pair = hex_common.is_pair(regid)
+ is_single_old = (hex_common.is_single(regid)
+ and hex_common.is_old_val(regtype, regid, tag))
+ is_single_new = (hex_common.is_single(regid)
+ and hex_common.is_new_val(regtype, regid, tag))
+
+ if is_pair or is_single_old:
+ arguments.append("%s%s%sV" % (prefix, regtype, regid))
+ elif is_single_new:
+ arguments.append("%s%s%sN" % (prefix, regtype, regid))
+ else:
+ print("Bad register parse: ",regtype,regid,toss,numregs)
+
+ for immlett,bits,immshift in imms:
+ arguments.append(hex_common.imm_name(immlett))
+
+ f.write("%s(%s) {\n" % (tag, ", ".join(arguments)))
+ f.write(" ");
+ if hex_common.need_ea(tag):
+ f.write("size4u_t EA; ");
+ f.write("%s\n" % hex_common.semdict[tag])
+ f.write("}\n\n")
+
+if __name__ == "__main__":
+ main()
diff --git a/target/hexagon/idef-parser/macros.inc b/target/hexagon/idef-parser/macros.inc
new file mode 100644
index 0000000000..b74a8f6f22
--- /dev/null
+++ b/target/hexagon/idef-parser/macros.inc
@@ -0,0 +1,140 @@
+/*
+ * Copyright(c) 2019-2021 rev.ng Labs Srl. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Copy rules */
+#define fLSBOLD(VAL) (fGETBIT(0, VAL))
+#define fSATH(VAL) fSATN(16, VAL)
+#define fSATUH(VAL) fSATUN(16, VAL)
+#define fVSATH(VAL) fVSATN(16, VAL)
+#define fVSATUH(VAL) fVSATUN(16, VAL)
+#define fSATUB(VAL) fSATUN(8, VAL)
+#define fSATB(VAL) fSATN(8, VAL)
+#define fVSATUB(VAL) fVSATUN(8, VAL)
+#define fVSATB(VAL) fVSATN(8, VAL)
+#define fCALL(A) fWRITE_LR(fREAD_NPC()); fWRITE_NPC(A);
+#define fCALLR(A) fWRITE_LR(fREAD_NPC()); fWRITE_NPC(A);
+#define fCAST2_8s(A) fSXTN(16, 64, A)
+#define fCAST2_8u(A) fZXTN(16, 64, A)
+#define fVSATW(A) fVSATN(32, fCAST8_8s(A))
+#define fSATW(A) fSATN(32, fCAST8_8s(A))
+#define fVSAT(A) fVSATN(32, A)
+#define fSAT(A) fSATN(32, A)
+
+/* Ease parsing */
+#define f8BITSOF(VAL) ((VAL) ? 0xff : 0x00)
+#define fREAD_GP() (Constant_extended ? (0) : GP)
+#define fCLIP(DST, SRC, U) (DST = fMIN((1 << U) - 1, fMAX(SRC, -(1 << U))))
+#define fBIDIR_ASHIFTL(SRC, SHAMT, REGSTYPE) \
+ ((SHAMT > 0) ? \
+ (fCAST##REGSTYPE##s(SRC) << SHAMT) : \
+ (fCAST##REGSTYPE##s(SRC) >> -SHAMT))
+
+#define fBIDIR_LSHIFTL(SRC, SHAMT, REGSTYPE) \
+ ((SHAMT > 0) ? \
+ (fCAST##REGSTYPE##u(SRC) << SHAMT) : \
+ (fCAST##REGSTYPE##u(SRC) >>> -SHAMT))
+
+#define fBIDIR_ASHIFTR(SRC, SHAMT, REGSTYPE) \
+ ((SHAMT > 0) ? \
+ (fCAST##REGSTYPE##s(SRC) >> SHAMT) : \
+ (fCAST##REGSTYPE##s(SRC) << -SHAMT))
+
+#define fBIDIR_SHIFTR(SRC, SHAMT, REGSTYPE) \
+ (((SHAMT) < 0) ? ((fCAST##REGSTYPE(SRC) << ((-(SHAMT)) - 1)) << 1) \
+ : (fCAST##REGSTYPE(SRC) >> (SHAMT)))
+
+#define fBIDIR_LSHIFTR(SRC, SHAMT, REGSTYPE) \
+ fBIDIR_SHIFTR(SRC, SHAMT, REGSTYPE##u)
+
+#define fSATVALN(N, VAL) \
+ fSET_OVERFLOW( \
+ ((VAL) < 0) ? (-(1LL << ((N) - 1))) : ((1LL << ((N) - 1)) - 1) \
+ )
+
+#define fSAT_ORIG_SHL(A, ORIG_REG) \
+ (((fCAST4s((fSAT(A)) ^ (fCAST4s(ORIG_REG)))) < 0) \
+ ? fSATVALN(32, (fCAST4s(ORIG_REG))) \
+ : ((((ORIG_REG) > 0) && ((A) == 0)) ? fSATVALN(32, (ORIG_REG)) \
+ : fSAT(A)))
+
+#define fBIDIR_ASHIFTR_SAT(SRC, SHAMT, REGSTYPE) \
+ (((SHAMT) < 0) ? fSAT_ORIG_SHL((fCAST##REGSTYPE##s(SRC) \
+ << ((-(SHAMT)) - 1)) << 1, (SRC)) \
+ : (fCAST##REGSTYPE##s(SRC) >> (SHAMT)))
+
+#define fBIDIR_ASHIFTL_SAT(SRC, SHAMT, REGSTYPE) \
+ (((SHAMT) < 0) \
+ ? ((fCAST##REGSTYPE##s(SRC) >> ((-(SHAMT)) - 1)) >> 1) \
+ : fSAT_ORIG_SHL(fCAST##REGSTYPE##s(SRC) << (SHAMT), (SRC)))
+
+#define fEXTRACTU_BIDIR(INREG, WIDTH, OFFSET) \
+ (fZXTN(WIDTH, 32, fBIDIR_LSHIFTR((INREG), (OFFSET), 4_8)))
+
+/* Least significant bit operations */
+#define fLSBNEW0 fLSBNEW(P0N)
+#define fLSBNEW1 fLSBNEW(P1N)
+#define fLSBOLDNOT(VAL) fGETBIT(0, ~VAL)
+#define fLSBNEWNOT(PRED) (fLSBNEW(~PRED))
+#define fLSBNEW0NOT fLSBNEW(~P0N)
+#define fLSBNEW1NOT fLSBNEW(~P1N)
+
+/* Assignments */
+#define fPCALIGN(IMM) (IMM = IMM & ~3)
+#define fWRITE_LR(A) (LR = A)
+#define fWRITE_FP(A) (FP = A)
+#define fWRITE_SP(A) (SP = A)
+/*
+ * Note: There is a rule in the parser that matches `PC = ...` and emits
+ * a call to `gen_write_new_pc`. We need to call `gen_write_new_pc` to
+ * get the correct semantics when there are multiple stores in a packet.
+ */
+#define fBRANCH(LOC, TYPE) (PC = LOC)
+#define fJUMPR(REGNO, TARGET, TYPE) (PC = TARGET)
+#define fWRITE_LOOP_REGS0(START, COUNT) SA0 = START; (LC0 = COUNT)
+#define fWRITE_LOOP_REGS1(START, COUNT) SA1 = START; (LC1 = COUNT)
+#define fWRITE_LC0(VAL) (LC0 = VAL)
+#define fWRITE_LC1(VAL) (LC1 = VAL)
+#define fSET_LPCFG(VAL) (USR.LPCFG = VAL)
+#define fWRITE_P0(VAL) P0 = VAL;
+#define fWRITE_P1(VAL) P1 = VAL;
+#define fWRITE_P3(VAL) P3 = VAL;
+#define fEA_RI(REG, IMM) (EA = REG + IMM)
+#define fEA_RRs(REG, REG2, SCALE) (EA = REG + (REG2 << SCALE))
+#define fEA_IRs(IMM, REG, SCALE) (EA = IMM + (REG << SCALE))
+#define fEA_IMM(IMM) (EA = IMM)
+#define fEA_REG(REG) (EA = REG)
+#define fEA_BREVR(REG) (EA = fbrev(REG))
+#define fEA_GPI(IMM) (EA = fREAD_GP() + IMM)
+#define fPM_I(REG, IMM) (REG = REG + IMM)
+#define fPM_M(REG, MVAL) (REG = REG + MVAL)
+#define fWRITE_NPC(VAL) (PC = VAL)
+
+/* Unary operators */
+#define fROUND(A) (A + 0x8000)
+
+/* Binary operators */
+#define fSCALE(N, A) (A << N)
+#define fASHIFTR(SRC, SHAMT, REGSTYPE) (fCAST##REGSTYPE##s(SRC) >> SHAMT)
+#define fLSHIFTR(SRC, SHAMT, REGSTYPE) (SRC >>> SHAMT)
+#define fROTL(SRC, SHAMT, REGSTYPE) fROTL(SRC, SHAMT)
+#define fASHIFTL(SRC, SHAMT, REGSTYPE) (fCAST##REGSTYPE##s(SRC) << SHAMT)
+
+/* Include fHIDE macros which hide type declarations */
+#define fHIDE(A) A
+
+/* Purge non-relavant parts */
+#define fBRANCH_SPECULATE_STALL(A, B, C, D, E)
diff --git a/target/hexagon/idef-parser/prepare b/target/hexagon/idef-parser/prepare
new file mode 100755
index 0000000000..72d6fcbd21
--- /dev/null
+++ b/target/hexagon/idef-parser/prepare
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+#
+# Copyright(c) 2019-2021 rev.ng Labs Srl. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+
+set -e
+set -o pipefail
+
+# Run the preprocessor and drop comments
+cpp "$@"
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index b61243103f..5945098cc4 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -21,6 +21,7 @@ hex_common_py = 'hex_common.py'
attribs_def = meson.current_source_dir() / 'attribs_def.h.inc'
gen_tcg_h = meson.current_source_dir() / 'gen_tcg.h'
gen_tcg_hvx_h = meson.current_source_dir() / 'gen_tcg_hvx.h'
+idef_parser_dir = meson.current_source_dir() / 'idef-parser'
#
# Step 1
@@ -179,4 +180,20 @@ hexagon_ss.add(files(
'mmvec/system_ext_mmvec.c',
))
+idef_parser_input_generated = custom_target(
+ 'idef_parser_input.h.inc',
+ output: 'idef_parser_input.h.inc',
+ depends: [semantics_generated],
+ depend_files: [hex_common_py],
+ command: [python, files('gen_idef_parser_funcs.py'), semantics_generated, attribs_def, '@OUTPUT@'],
+)
+
+preprocessed_idef_parser_input_generated = custom_target(
+ 'idef_parser_input.preprocessed.h.inc',
+ output: 'idef_parser_input.preprocessed.h.inc',
+ input: idef_parser_input_generated,
+ depend_files: [idef_parser_dir / 'macros.inc'],
+ command: [idef_parser_dir / 'prepare', '@INPUT@', '-I' + idef_parser_dir, '-o', '@OUTPUT@'],
+)
+
target_arch += {'hexagon': hexagon_ss}
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v8 08/12] target/hexagon: import flex/bison to docker files
2022-02-09 17:03 [PATCH v8 00/12] target/hexagon: introduce idef-parser Anton Johansson via
` (6 preceding siblings ...)
2022-02-09 17:03 ` [PATCH v8 07/12] target/hexagon: prepare input for the idef-parser Anton Johansson via
@ 2022-02-09 17:03 ` Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 09/12] target/hexagon: import lexer for idef-parser Anton Johansson via
` (3 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Anton Johansson via @ 2022-02-09 17:03 UTC (permalink / raw)
To: qemu-devel
Cc: ale, tsimpson, bcain, mlambert, babush, nizzo, richard.henderson
Note: In this version of the patchset `tests/lcitool/libvirt-ci` points
to a fork of libvirt-ci that includes flex/bison. This fork has not been
merged upstream yet, and can be found at
https://gitlab.com/AntonJohansson/libvirt-ci/-/tree/mapping-flex-bison
This patch will have to be modified to point to the upstreamed version
before pulling.
Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Paolo Montesel <babush@rev.ng>
Signed-off-by: Anton Johansson <anjo@rev.ng>
---
.gitlab-ci.d/cirrus/freebsd-12.vars | 2 +-
.gitlab-ci.d/cirrus/freebsd-13.vars | 2 +-
.gitlab-ci.d/windows.yml | 2 ++
.gitmodules | 3 ++-
tests/docker/dockerfiles/alpine.docker | 5 ++++-
tests/docker/dockerfiles/centos8.docker | 7 ++++---
tests/docker/dockerfiles/debian-amd64.docker | 2 ++
tests/docker/dockerfiles/debian-native.docker | 3 +++
tests/docker/dockerfiles/debian-riscv64-cross.docker | 3 +++
tests/docker/dockerfiles/debian-tricore-cross.docker | 1 +
tests/docker/dockerfiles/debian10.docker | 3 +++
tests/docker/dockerfiles/fedora-i386-cross.docker | 3 +++
tests/docker/dockerfiles/fedora-win32-cross.docker | 3 +++
tests/docker/dockerfiles/fedora-win64-cross.docker | 3 +++
tests/docker/dockerfiles/fedora.docker | 5 +++--
tests/docker/dockerfiles/opensuse-leap.docker | 7 ++++---
tests/docker/dockerfiles/ubuntu1804.docker | 7 ++++---
tests/docker/dockerfiles/ubuntu2004.docker | 7 ++++---
tests/lcitool/libvirt-ci | 2 +-
tests/lcitool/projects/qemu.yml | 2 ++
tests/lcitool/refresh | 2 +-
21 files changed, 54 insertions(+), 20 deletions(-)
diff --git a/.gitlab-ci.d/cirrus/freebsd-12.vars b/.gitlab-ci.d/cirrus/freebsd-12.vars
index 9c52266811..f2385c1b4a 100644
--- a/.gitlab-ci.d/cirrus/freebsd-12.vars
+++ b/.gitlab-ci.d/cirrus/freebsd-12.vars
@@ -11,6 +11,6 @@ MAKE='/usr/local/bin/gmake'
NINJA='/usr/local/bin/ninja'
PACKAGING_COMMAND='pkg'
PIP3='/usr/local/bin/pip-3.8'
-PKGS='alsa-lib bash bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage ctags curl cyrus-sasl dbus diffutils dtc gettext git glib gmake gnutls gsed gtk3 libepoxy libffi libgcrypt libjpeg-turbo libnfs libspice-server libssh libtasn1 libxml2 llvm lttng-ust lzo2 meson ncurses nettle ninja opencv p5-Test-Harness perl5 pixman pkgconf png py38-numpy py38-pillow py38-pip py38-sphinx py38-sphinx_rtd_theme py38-virtualenv py38-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd'
+PKGS='alsa-lib bash bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage ctags curl cyrus-sasl dbus diffutils dtc gettext git glib gmake gnutls gsed gtk3 libepoxy libffi libgcrypt libjpeg-turbo libnfs libspice-server libssh libtasn1 libxml2 llvm lzo2 meson ncurses nettle ninja opencv p5-Test-Harness perl5 pixman pkgconf png py38-numpy py38-pillow py38-pip py38-sphinx py38-sphinx_rtd_theme py38-virtualenv py38-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd'
PYPI_PKGS=''
PYTHON='/usr/local/bin/python3'
diff --git a/.gitlab-ci.d/cirrus/freebsd-13.vars b/.gitlab-ci.d/cirrus/freebsd-13.vars
index 7b44dba324..43904b65fa 100644
--- a/.gitlab-ci.d/cirrus/freebsd-13.vars
+++ b/.gitlab-ci.d/cirrus/freebsd-13.vars
@@ -11,6 +11,6 @@ MAKE='/usr/local/bin/gmake'
NINJA='/usr/local/bin/ninja'
PACKAGING_COMMAND='pkg'
PIP3='/usr/local/bin/pip-3.8'
-PKGS='alsa-lib bash bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage ctags curl cyrus-sasl dbus diffutils dtc gettext git glib gmake gnutls gsed gtk3 libepoxy libffi libgcrypt libjpeg-turbo libnfs libspice-server libssh libtasn1 libxml2 llvm lttng-ust lzo2 meson ncurses nettle ninja opencv p5-Test-Harness perl5 pixman pkgconf png py38-numpy py38-pillow py38-pip py38-sphinx py38-sphinx_rtd_theme py38-virtualenv py38-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd'
+PKGS='alsa-lib bash bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage ctags curl cyrus-sasl dbus diffutils dtc gettext git glib gmake gnutls gsed gtk3 libepoxy libffi libgcrypt libjpeg-turbo libnfs libspice-server libssh libtasn1 libxml2 llvm lzo2 meson ncurses nettle ninja opencv p5-Test-Harness perl5 pixman pkgconf png py38-numpy py38-pillow py38-pip py38-sphinx py38-sphinx_rtd_theme py38-virtualenv py38-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd'
PYPI_PKGS=''
PYTHON='/usr/local/bin/python3'
diff --git a/.gitlab-ci.d/windows.yml b/.gitlab-ci.d/windows.yml
index 62dd9ed832..4ae49376cf 100644
--- a/.gitlab-ci.d/windows.yml
+++ b/.gitlab-ci.d/windows.yml
@@ -33,6 +33,7 @@ msys2-64bit:
script:
- .\msys64\usr\bin\bash -lc "pacman -Sy --noconfirm --needed
diffutils git grep make sed
+ flex bison
mingw-w64-x86_64-capstone
mingw-w64-x86_64-curl
mingw-w64-x86_64-cyrus-sasl
@@ -68,6 +69,7 @@ msys2-32bit:
script:
- .\msys64\usr\bin\bash -lc "pacman -Sy --noconfirm --needed
diffutils git grep make sed
+ flex bison
mingw-w64-i686-capstone
mingw-w64-i686-curl
mingw-w64-i686-cyrus-sasl
diff --git a/.gitmodules b/.gitmodules
index 84425d87e2..666e17907f 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -66,4 +66,5 @@
url = https://gitlab.com/qemu-project/vbootrom.git
[submodule "tests/lcitool/libvirt-ci"]
path = tests/lcitool/libvirt-ci
- url = http://gitlab.com/libvirt/libvirt-ci
+ url = http://gitlab.com/AntonJohansson/libvirt-ci
+ branch = mapping-flex-bison
diff --git a/tests/docker/dockerfiles/alpine.docker b/tests/docker/dockerfiles/alpine.docker
index eb2251c81c..d4f0279318 100644
--- a/tests/docker/dockerfiles/alpine.docker
+++ b/tests/docker/dockerfiles/alpine.docker
@@ -1,6 +1,6 @@
# THIS FILE WAS AUTO-GENERATED
#
-# $ lcitool dockerfile alpine-edge qemu
+# $ lcitool dockerfile --layers all alpine-edge qemu
#
# https://gitlab.com/libvirt/libvirt-ci
@@ -13,6 +13,7 @@ RUN apk update && \
attr-dev \
bash \
bc \
+ bison \
bzip2 \
bzip2-dev \
ca-certificates \
@@ -29,6 +30,7 @@ RUN apk update && \
dtc-dev \
eudev-dev \
findutils \
+ flex \
fuse3-dev \
g++ \
gcc \
@@ -109,6 +111,7 @@ RUN apk update && \
zlib-dev \
zlib-static \
zstd-dev && \
+ apk list | sort > /packages.txt && \
mkdir -p /usr/libexec/ccache-wrappers && \
ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/c++ && \
ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \
diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker
index cbb909d02b..66d1f09a86 100644
--- a/tests/docker/dockerfiles/centos8.docker
+++ b/tests/docker/dockerfiles/centos8.docker
@@ -1,10 +1,10 @@
# THIS FILE WAS AUTO-GENERATED
#
-# $ lcitool dockerfile centos-8 qemu
+# $ lcitool dockerfile --layers all almalinux-8 qemu
#
# https://gitlab.com/libvirt/libvirt-ci
-FROM docker.io/library/centos:8
+FROM docker.io/library/almalinux:8
RUN dnf update -y && \
dnf install 'dnf-command(config-manager)' -y && \
@@ -16,6 +16,7 @@ RUN dnf update -y && \
alsa-lib-devel \
bash \
bc \
+ bison \
brlapi-devel \
bzip2 \
bzip2-devel \
@@ -30,6 +31,7 @@ RUN dnf update -y && \
device-mapper-multipath-devel \
diffutils \
findutils \
+ flex \
fuse3-devel \
gcc \
gcc-c++ \
@@ -69,7 +71,6 @@ RUN dnf update -y && \
libssh-devel \
libtasn1-devel \
libubsan \
- libudev-devel \
liburing-devel \
libusbx-devel \
libxml2-devel \
diff --git a/tests/docker/dockerfiles/debian-amd64.docker b/tests/docker/dockerfiles/debian-amd64.docker
index ed546edcd6..805fd6f981 100644
--- a/tests/docker/dockerfiles/debian-amd64.docker
+++ b/tests/docker/dockerfiles/debian-amd64.docker
@@ -14,9 +14,11 @@ RUN apt update && \
RUN apt update && \
DEBIAN_FRONTEND=noninteractive eatmydata \
apt install -y --no-install-recommends \
+ bison \
cscope \
genisoimage \
exuberant-ctags \
+ flex \
global \
libbz2-dev \
liblzo2-dev \
diff --git a/tests/docker/dockerfiles/debian-native.docker b/tests/docker/dockerfiles/debian-native.docker
index efd55cb6e0..02ccaf98fd 100644
--- a/tests/docker/dockerfiles/debian-native.docker
+++ b/tests/docker/dockerfiles/debian-native.docker
@@ -26,13 +26,16 @@ RUN apt update && \
RUN apt update && \
DEBIAN_FRONTEND=noninteractive eatmydata \
apt install -y --no-install-recommends \
+ bison \
cscope \
genisoimage \
exuberant-ctags \
+ flex \
global \
libbz2-dev \
liblzo2-dev \
libgcrypt20-dev \
+ libglib2.0-dev \
libfdt-dev \
librdmacm-dev \
libsasl2-dev \
diff --git a/tests/docker/dockerfiles/debian-riscv64-cross.docker b/tests/docker/dockerfiles/debian-riscv64-cross.docker
index 594d97982c..f5553afc2e 100644
--- a/tests/docker/dockerfiles/debian-riscv64-cross.docker
+++ b/tests/docker/dockerfiles/debian-riscv64-cross.docker
@@ -17,12 +17,15 @@ RUN apt update && \
# Install common build utilities
RUN DEBIAN_FRONTEND=noninteractive eatmydata apt install -yy \
bc \
+ bison \
build-essential \
ca-certificates \
debian-ports-archive-keyring \
dpkg-dev \
+ flex \
gettext \
git \
+ libglib2.0-dev \
ninja-build \
pkg-config \
python3
diff --git a/tests/docker/dockerfiles/debian-tricore-cross.docker b/tests/docker/dockerfiles/debian-tricore-cross.docker
index 3f6b55562c..9191aafc7f 100644
--- a/tests/docker/dockerfiles/debian-tricore-cross.docker
+++ b/tests/docker/dockerfiles/debian-tricore-cross.docker
@@ -20,6 +20,7 @@ RUN apt update && \
bzip2 \
ca-certificates \
ccache \
+ flex \
g++ \
gcc \
git \
diff --git a/tests/docker/dockerfiles/debian10.docker b/tests/docker/dockerfiles/debian10.docker
index b414af1b9f..23285e7aa4 100644
--- a/tests/docker/dockerfiles/debian10.docker
+++ b/tests/docker/dockerfiles/debian10.docker
@@ -18,15 +18,18 @@ RUN apt update && \
DEBIAN_FRONTEND=noninteractive eatmydata \
apt install -y --no-install-recommends \
bc \
+ bison \
build-essential \
ca-certificates \
ccache \
clang \
dbus \
+ flex \
gdb-multiarch \
gettext \
git \
libffi-dev \
+ libglib2.0-dev \
libncurses5-dev \
ninja-build \
pkg-config \
diff --git a/tests/docker/dockerfiles/fedora-i386-cross.docker b/tests/docker/dockerfiles/fedora-i386-cross.docker
index 13328e6081..ae009a203f 100644
--- a/tests/docker/dockerfiles/fedora-i386-cross.docker
+++ b/tests/docker/dockerfiles/fedora-i386-cross.docker
@@ -1,12 +1,15 @@
FROM registry.fedoraproject.org/fedora:34
ENV PACKAGES \
+ bison \
bzip2 \
ccache \
diffutils \
findutils \
+ flex \
gcc \
git \
+ glib2-devel \
libffi-devel.i686 \
libselinux-devel.i686 \
libtasn1-devel.i686 \
diff --git a/tests/docker/dockerfiles/fedora-win32-cross.docker b/tests/docker/dockerfiles/fedora-win32-cross.docker
index d80e66c651..ed08392657 100644
--- a/tests/docker/dockerfiles/fedora-win32-cross.docker
+++ b/tests/docker/dockerfiles/fedora-win32-cross.docker
@@ -3,13 +3,16 @@ FROM registry.fedoraproject.org/fedora:33
# Please keep this list sorted alphabetically
ENV PACKAGES \
bc \
+ bison \
bzip2 \
ccache \
diffutils \
findutils \
+ flex \
gcc \
gettext \
git \
+ glib2-devel \
hostname \
make \
meson \
diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker
index 2b12b94ccf..bc31c66aef 100644
--- a/tests/docker/dockerfiles/fedora-win64-cross.docker
+++ b/tests/docker/dockerfiles/fedora-win64-cross.docker
@@ -3,12 +3,15 @@ FROM registry.fedoraproject.org/fedora:33
# Please keep this list sorted alphabetically
ENV PACKAGES \
bc \
+ bison \
bzip2 \
ccache \
diffutils \
findutils \
+ flex \
gcc \
gettext \
+ glib2-devel \
git \
hostname \
make \
diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker
index 60207f3da3..e2ba993e6b 100644
--- a/tests/docker/dockerfiles/fedora.docker
+++ b/tests/docker/dockerfiles/fedora.docker
@@ -1,6 +1,6 @@
# THIS FILE WAS AUTO-GENERATED
#
-# $ lcitool dockerfile fedora-35 qemu
+# $ lcitool dockerfile --layers all fedora-35 qemu
#
# https://gitlab.com/libvirt/libvirt-ci
@@ -23,6 +23,7 @@ exec "$@"' > /usr/bin/nosync && \
alsa-lib-devel \
bash \
bc \
+ bison \
brlapi-devel \
bzip2 \
bzip2-devel \
@@ -37,6 +38,7 @@ exec "$@"' > /usr/bin/nosync && \
device-mapper-multipath-devel \
diffutils \
findutils \
+ flex \
fuse3-devel \
gcc \
gcc-c++ \
@@ -77,7 +79,6 @@ exec "$@"' > /usr/bin/nosync && \
libssh-devel \
libtasn1-devel \
libubsan \
- libudev-devel \
liburing-devel \
libusbx-devel \
libxml2-devel \
diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker
index f57d8cfb29..146cd9f3e3 100644
--- a/tests/docker/dockerfiles/opensuse-leap.docker
+++ b/tests/docker/dockerfiles/opensuse-leap.docker
@@ -1,6 +1,6 @@
# THIS FILE WAS AUTO-GENERATED
#
-# $ lcitool dockerfile opensuse-leap-152 qemu
+# $ lcitool dockerfile --layers all opensuse-leap-152 qemu
#
# https://gitlab.com/libvirt/libvirt-ci
@@ -12,6 +12,7 @@ RUN zypper update -y && \
alsa-lib-devel \
bash \
bc \
+ bison \
brlapi-devel \
bzip2 \
ca-certificates \
@@ -22,6 +23,7 @@ RUN zypper update -y && \
dbus-1 \
diffutils \
findutils \
+ flex \
fuse3-devel \
gcc \
gcc-c++ \
@@ -128,8 +130,7 @@ RUN zypper update -y && \
ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++ && \
ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc
-RUN pip3 install \
- meson==0.56.0
+RUN pip3 install meson==0.56.0
ENV LANG "en_US.UTF-8"
ENV MAKE "/usr/bin/make"
diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker
index 0ffa3c4d4b..0a5900f203 100644
--- a/tests/docker/dockerfiles/ubuntu1804.docker
+++ b/tests/docker/dockerfiles/ubuntu1804.docker
@@ -1,6 +1,6 @@
# THIS FILE WAS AUTO-GENERATED
#
-# $ lcitool dockerfile ubuntu-1804 qemu
+# $ lcitool dockerfile --layers all ubuntu-1804 qemu
#
# https://gitlab.com/libvirt/libvirt-ci
@@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
eatmydata apt-get install --no-install-recommends -y \
bash \
bc \
+ bison \
bsdmainutils \
bzip2 \
ca-certificates \
@@ -23,6 +24,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
diffutils \
exuberant-ctags \
findutils \
+ flex \
g++ \
gcc \
gcovr \
@@ -134,8 +136,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++ && \
ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc
-RUN pip3 install \
- meson==0.56.0
+RUN pip3 install meson==0.56.0
ENV LANG "en_US.UTF-8"
ENV MAKE "/usr/bin/make"
diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker
index 4e562dfdcd..75b5eee895 100644
--- a/tests/docker/dockerfiles/ubuntu2004.docker
+++ b/tests/docker/dockerfiles/ubuntu2004.docker
@@ -1,6 +1,6 @@
# THIS FILE WAS AUTO-GENERATED
#
-# $ lcitool dockerfile ubuntu-2004 qemu
+# $ lcitool dockerfile --layers all ubuntu-2004 qemu
#
# https://gitlab.com/libvirt/libvirt-ci
@@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
eatmydata apt-get install --no-install-recommends -y \
bash \
bc \
+ bison \
bsdmainutils \
bzip2 \
ca-certificates \
@@ -23,6 +24,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
diffutils \
exuberant-ctags \
findutils \
+ flex \
g++ \
gcc \
gcovr \
@@ -136,8 +138,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++ && \
ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc
-RUN pip3 install \
- meson==0.56.0
+RUN pip3 install meson==0.56.0
ENV LANG "en_US.UTF-8"
ENV MAKE "/usr/bin/make"
diff --git a/tests/lcitool/libvirt-ci b/tests/lcitool/libvirt-ci
index 29cec2153b..22a88ac731 160000
--- a/tests/lcitool/libvirt-ci
+++ b/tests/lcitool/libvirt-ci
@@ -1 +1 @@
-Subproject commit 29cec2153b9a4dbb2e66f1cbc9866a4eff519cfd
+Subproject commit 22a88ac73197e6c6b8a319eb92cdbd2ac06eb44a
diff --git a/tests/lcitool/projects/qemu.yml b/tests/lcitool/projects/qemu.yml
index ed5ab1407a..f464665990 100644
--- a/tests/lcitool/projects/qemu.yml
+++ b/tests/lcitool/projects/qemu.yml
@@ -3,6 +3,7 @@ packages:
- alsa
- bash
- bc
+ - bison
- brlapi
- bzip2
- bzip2-libs
@@ -18,6 +19,7 @@ packages:
- diffutils
- dtrace
- findutils
+ - flex
- fuse3
- g++
- gcc
diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh
index 033120e223..4d7e6e8383 100755
--- a/tests/lcitool/refresh
+++ b/tests/lcitool/refresh
@@ -77,7 +77,7 @@ ubuntu2004_tsanhack = [
]
try:
- generate_dockerfile("centos8", "centos-8")
+ generate_dockerfile("centos8", "almalinux-8")
generate_dockerfile("fedora", "fedora-35")
generate_dockerfile("ubuntu1804", "ubuntu-1804",
trailer="".join(ubuntu1804_skipssh))
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v8 09/12] target/hexagon: import lexer for idef-parser
2022-02-09 17:03 [PATCH v8 00/12] target/hexagon: introduce idef-parser Anton Johansson via
` (7 preceding siblings ...)
2022-02-09 17:03 ` [PATCH v8 08/12] target/hexagon: import flex/bison to docker files Anton Johansson via
@ 2022-02-09 17:03 ` Anton Johansson via
2022-03-21 18:40 ` Taylor Simpson
2022-02-09 17:03 ` [PATCH v8 10/12] target/hexagon: import parser " Anton Johansson via
` (2 subsequent siblings)
11 siblings, 1 reply; 23+ messages in thread
From: Anton Johansson via @ 2022-02-09 17:03 UTC (permalink / raw)
To: qemu-devel
Cc: ale, tsimpson, bcain, mlambert, babush, nizzo, richard.henderson
From: Paolo Montesel <babush@rev.ng>
Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Paolo Montesel <babush@rev.ng>
Signed-off-by: Anton Johansson <anjo@rev.ng>
---
target/hexagon/idef-parser/idef-parser.h | 254 +++++++++
target/hexagon/idef-parser/idef-parser.lex | 566 +++++++++++++++++++++
target/hexagon/meson.build | 4 +
3 files changed, 824 insertions(+)
create mode 100644 target/hexagon/idef-parser/idef-parser.h
create mode 100644 target/hexagon/idef-parser/idef-parser.lex
diff --git a/target/hexagon/idef-parser/idef-parser.h b/target/hexagon/idef-parser/idef-parser.h
new file mode 100644
index 0000000000..106eb3ec98
--- /dev/null
+++ b/target/hexagon/idef-parser/idef-parser.h
@@ -0,0 +1,254 @@
+/*
+ * Copyright(c) 2019-2021 rev.ng Labs Srl. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef IDEF_PARSER_H
+#define IDEF_PARSER_H
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <glib.h>
+
+#define TCGV_NAME_SIZE 7
+#define MAX_WRITTEN_REGS 32
+#define OFFSET_STR_LEN 32
+#define ALLOC_LIST_LEN 32
+#define ALLOC_NAME_SIZE 32
+#define INIT_LIST_LEN 32
+#define OUT_BUF_LEN (1024 * 1024)
+#define SIGNATURE_BUF_LEN (128 * 1024)
+#define HEADER_BUF_LEN (128 * 1024)
+
+/* Variadic macros to wrap the buffer printing functions */
+#define EMIT(c, ...) \
+ do { \
+ g_string_append_printf((c)->out_str, __VA_ARGS__); \
+ } while (0)
+
+#define EMIT_SIG(c, ...) \
+ do { \
+ g_string_append_printf((c)->signature_str, __VA_ARGS__); \
+ } while (0)
+
+#define EMIT_HEAD(c, ...) \
+ do { \
+ g_string_append_printf((c)->header_str, __VA_ARGS__); \
+ } while (0)
+
+/**
+ * Type of register, assigned to the HexReg.type field
+ */
+typedef enum { GENERAL_PURPOSE, CONTROL, MODIFIER, DOTNEW } HexRegType;
+
+typedef enum { UNKNOWN_SIGNEDNESS, SIGNED, UNSIGNED } HexSignedness;
+
+/**
+ * Semantic record of the REG tokens, identifying registers
+ */
+typedef struct HexReg {
+ uint8_t id; /**< Identifier of the register */
+ HexRegType type; /**< Type of the register */
+ unsigned bit_width; /**< Bit width of the reg, 32 or 64 bits */
+} HexReg;
+
+/**
+ * Data structure, identifying a TCGv temporary value
+ */
+typedef struct HexTmp {
+ unsigned index; /**< Index of the TCGv temporary value */
+} HexTmp;
+
+/**
+ * Enum of the possible immediated, an immediate is a value which is known
+ * at tinycode generation time, e.g. an integer value, not a TCGv
+ */
+enum ImmUnionTag {
+ I,
+ VARIABLE,
+ VALUE,
+ QEMU_TMP,
+ IMM_PC,
+ IMM_NPC,
+ IMM_CONSTEXT,
+};
+
+/**
+ * Semantic record of the IMM token, identifying an immediate constant
+ */
+typedef struct HexImm {
+ union {
+ char id; /**< Identifier, used when type is VARIABLE */
+ uint64_t value; /**< Immediate value, used when type is VALUE */
+ uint64_t index; /**< Index, used when type is QEMU_TMP */
+ };
+ enum ImmUnionTag type; /**< Type of the immediate */
+} HexImm;
+
+/**
+ * Semantic record of the PRED token, identifying a predicate
+ */
+typedef struct HexPred {
+ char id; /**< Identifier of the predicate */
+} HexPred;
+
+/**
+ * Semantic record of the SAT token, identifying the saturate operator
+ */
+typedef struct HexSat {
+ bool set_overflow; /**< Should the sat. op. set overflow? */
+ HexSignedness signedness; /**< Signedness of the sat. op. */
+} HexSat;
+
+/**
+ * Semantic record of the CAST token, identifying the cast operator
+ */
+typedef struct HexCast {
+ unsigned bit_width; /**< Bit width of the cast operator */
+ HexSignedness signedness; /**< Unsigned flag for the cast operator */
+} HexCast;
+
+/**
+ * Semantic record of the EXTRACT token, identifying the cast operator
+ */
+typedef struct HexExtract {
+ unsigned bit_width; /**< Bit width of the extract operator */
+ unsigned storage_bit_width; /**< Actual bit width of the extract operator */
+ HexSignedness signedness; /**< Unsigned flag for the extract operator */
+} HexExtract;
+
+/**
+ * Semantic record of the MPY token, identifying the fMPY multiplication
+ * operator
+ */
+typedef struct HexMpy {
+ unsigned first_bit_width; /**< Bit width of 1st operand of fMPY */
+ unsigned second_bit_width; /**< Bit width of 2nd operand of fMPY */
+ HexSignedness first_signedness; /**< Signedness of 1st operand of fMPY */
+ HexSignedness second_signedness; /**< Signedness of 2nd operand of fMPY */
+} HexMpy;
+
+/**
+ * Semantic record of the VARID token, identifying declared variables
+ * of the input language
+ */
+typedef struct HexVar {
+ GString *name; /**< Name of the VARID variable */
+} HexVar;
+
+/**
+ * Data structure uniquely identifying a declared VARID variable, used for
+ * keeping track of declared variable, so that any variable is declared only
+ * once, and its properties are propagated through all the subsequent instances
+ * of that variable
+ */
+typedef struct Var {
+ GString *name; /**< Name of the VARID variable */
+ uint8_t bit_width; /**< Bit width of the VARID variable */
+ HexSignedness signedness; /**< Unsigned flag for the VARID var */
+} Var;
+
+/**
+ * Enum of the possible rvalue types, used in the HexValue.type field
+ */
+typedef enum RvalueUnionTag {
+ REGISTER, REGISTER_ARG, TEMP, IMMEDIATE, PREDICATE, VARID
+} RvalueUnionTag;
+
+/**
+ * Semantic record of the rvalue token, identifying any numeric value,
+ * immediate or register based. The rvalue tokens are combined together
+ * through the use of several operators, to encode expressions
+ */
+typedef struct HexValue {
+ union {
+ HexReg reg; /**< rvalue of register type */
+ HexTmp tmp; /**< rvalue of temporary type */
+ HexImm imm; /**< rvalue of immediate type */
+ HexPred pred; /**< rvalue of predicate type */
+ HexVar var; /**< rvalue of declared variable type */
+ };
+ RvalueUnionTag type; /**< Type of the rvalue */
+ unsigned bit_width; /**< Bit width of the rvalue */
+ HexSignedness signedness; /**< Unsigned flag for the rvalue */
+ bool is_dotnew; /**< rvalue of predicate type is dotnew? */
+ bool is_manual; /**< Opt out of automatic freeing of params */
+} HexValue;
+
+/**
+ * State of ternary operator
+ */
+typedef enum TernaryState { IN_LEFT, IN_RIGHT } TernaryState;
+
+/**
+ * Data structure used to handle side effects inside ternary operators
+ */
+typedef struct Ternary {
+ TernaryState state;
+ HexValue cond;
+} Ternary;
+
+/**
+ * Operator type, used for referencing the correct operator when calling the
+ * gen_bin_op() function, which in turn will generate the correct code to
+ * execute the operation between the two rvalues
+ */
+typedef enum OpType {
+ ADD_OP, SUB_OP, MUL_OP, ASL_OP, ASR_OP, LSR_OP, ANDB_OP, ORB_OP,
+ XORB_OP, ANDL_OP, MINI_OP, MAXI_OP, MOD_OP
+} OpType;
+
+/**
+ * Data structure including instruction specific information, to be cleared
+ * out after the compilation of each instruction
+ */
+typedef struct Inst {
+ GString *name; /**< Name of the compiled instruction */
+ char *code_begin; /**< Beginning of instruction input code */
+ char *code_end; /**< End of instruction input code */
+ unsigned tmp_count; /**< Index of the last declared TCGv temp */
+ unsigned qemu_tmp_count; /**< Index of the last declared int temp */
+ unsigned if_count; /**< Index of the last declared if label */
+ unsigned error_count; /**< Number of generated errors */
+ GArray *allocated; /**< Allocated declaredVARID vars */
+ GArray *init_list; /**< List of initialized registers */
+ GArray *strings; /**< Strings allocated by the instruction */
+} Inst;
+
+/**
+ * Data structure representing the whole translation context, which in a
+ * reentrant flex/bison parser just like ours is passed between the scanner
+ * and the parser, holding all the necessary information to perform the
+ * parsing, this data structure survives between the compilation of different
+ * instructions
+ *
+ */
+typedef struct Context {
+ void *scanner; /**< Reentrant parser state pointer */
+ char *input_buffer; /**< Buffer containing the input code */
+ GString *out_str; /**< String containing the output code */
+ GString *signature_str; /**< String containing the signatures code */
+ GString *header_str; /**< String containing the header code */
+ FILE *defines_file; /**< FILE * of the generated header */
+ FILE *output_file; /**< FILE * of the C output file */
+ FILE *enabled_file; /**< FILE * of the list of enabled inst */
+ GArray *ternary; /**< Array to track nesting of ternary ops */
+ unsigned total_insn; /**< Number of instructions in input file */
+ unsigned implemented_insn; /**< Instruction compiled without errors */
+ Inst inst; /**< Parsing data of the current inst */
+} Context;
+
+#endif /* IDEF_PARSER_H */
diff --git a/target/hexagon/idef-parser/idef-parser.lex b/target/hexagon/idef-parser/idef-parser.lex
new file mode 100644
index 0000000000..7cdfb22d80
--- /dev/null
+++ b/target/hexagon/idef-parser/idef-parser.lex
@@ -0,0 +1,566 @@
+%option noyywrap noinput nounput
+%option 8bit reentrant bison-bridge
+%option warn nodefault
+%option bison-locations
+
+%{
+/*
+ * Copyright(c) 2019-2021 rev.ng Labs Srl. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <stdbool.h>
+
+#include "hex_regs.h"
+
+#include "idef-parser.h"
+#include "idef-parser.tab.h"
+
+/* Keep track of scanner position for error message printout */
+#define YY_USER_ACTION yylloc->first_column = yylloc->last_column; \
+ for (int i = 0; yytext[i] != '\0'; i++) { \
+ yylloc->last_column++; \
+ }
+
+/* Global Error Counter */
+int error_count;
+
+%}
+
+/* Definitions */
+DIGIT [0-9]
+LOWER_ID [a-z]
+UPPER_ID [A-Z]
+ID LOWER_ID|UPPER_ID
+INST_NAME [A-Z]+[0-9]_([A-Za-z]|[0-9]|_)+
+HEX_DIGIT [0-9a-fA-F]
+REG_ID_32 e|s|d|t|u|v|x|y
+REG_ID_64 ee|ss|dd|tt|uu|vv|xx|yy
+SYS_ID_32 s|d
+SYS_ID_64 ss|dd
+PRED_ID d|s|t|u|v|e|x|x
+IMM_ID r|s|S|u|U
+VAR_ID [a-zA-Z_][a-zA-Z0-9_]*
+SIGN_ID s|u
+STRING_LIT \"(\\.|[^"\\])*\"
+
+/* Tokens */
+%%
+
+[ \t\f\v]+ { /* Ignore whitespaces. */ }
+[\n\r]+ { /* Ignore newlines. */ }
+^#.*$ { /* Ignore linemarkers. */ }
+
+{INST_NAME} { yylval->string = g_string_new(yytext);
+ return INAME; }
+"fFLOAT" |
+"fUNFLOAT" |
+"fDOUBLE" |
+"fUNDOUBLE" |
+"0.0" |
+"0x1.0p52" |
+"0x1.0p-52" { return FAIL; }
+"in" { return IN; }
+"R"{REG_ID_32}"V" {
+ yylval->rvalue.type = REGISTER_ARG;
+ yylval->rvalue.reg.type = GENERAL_PURPOSE;
+ yylval->rvalue.reg.id = yytext[1];
+ yylval->rvalue.reg.bit_width = 32;
+ yylval->rvalue.bit_width = 32;
+ yylval->rvalue.is_dotnew = false;
+ yylval->rvalue.signedness = SIGNED;
+ return REG; }
+"R"{REG_ID_32}"N" {
+ yylval->rvalue.type = REGISTER_ARG;
+ yylval->rvalue.reg.type = DOTNEW;
+ yylval->rvalue.reg.id = yytext[1];
+ yylval->rvalue.reg.bit_width = 32;
+ yylval->rvalue.bit_width = 32;
+ yylval->rvalue.is_dotnew = true;
+ yylval->rvalue.signedness = SIGNED;
+ return REG; }
+"R"{REG_ID_64}"V" {
+ yylval->rvalue.type = REGISTER_ARG;
+ yylval->rvalue.reg.type = GENERAL_PURPOSE;
+ yylval->rvalue.reg.id = yytext[1];
+ yylval->rvalue.reg.bit_width = 64;
+ yylval->rvalue.bit_width = 64;
+ yylval->rvalue.is_dotnew = false;
+ yylval->rvalue.signedness = SIGNED;
+ return REG; }
+"R"{REG_ID_64}"N" {
+ yylval->rvalue.type = REGISTER_ARG;
+ yylval->rvalue.reg.type = DOTNEW;
+ yylval->rvalue.reg.id = yytext[1];
+ yylval->rvalue.reg.bit_width = 64;
+ yylval->rvalue.bit_width = 64;
+ yylval->rvalue.is_dotnew = true;
+ yylval->rvalue.signedness = SIGNED;
+ return REG; }
+"MuV" {
+ yylval->rvalue.type = REGISTER_ARG;
+ yylval->rvalue.reg.type = MODIFIER;
+ yylval->rvalue.reg.id = 'u';
+ yylval->rvalue.reg.bit_width = 32;
+ yylval->rvalue.bit_width = 32;
+ yylval->rvalue.signedness = SIGNED;
+ return REG; }
+"C"{REG_ID_32}"V" {
+ yylval->rvalue.type = REGISTER_ARG;
+ yylval->rvalue.reg.type = CONTROL;
+ yylval->rvalue.reg.id = yytext[1];
+ yylval->rvalue.reg.bit_width = 32;
+ yylval->rvalue.bit_width = 32;
+ yylval->rvalue.is_dotnew = false;
+ yylval->rvalue.signedness = SIGNED;
+ return REG; }
+"C"{REG_ID_64}"V" {
+ yylval->rvalue.type = REGISTER_ARG;
+ yylval->rvalue.reg.type = CONTROL;
+ yylval->rvalue.reg.id = yytext[1];
+ yylval->rvalue.reg.bit_width = 64;
+ yylval->rvalue.bit_width = 64;
+ yylval->rvalue.is_dotnew = false;
+ yylval->rvalue.signedness = SIGNED;
+ return REG; }
+{IMM_ID}"iV" {
+ yylval->rvalue.type = IMMEDIATE;
+ yylval->rvalue.signedness = SIGNED;
+ yylval->rvalue.imm.type = VARIABLE;
+ yylval->rvalue.imm.id = yytext[0];
+ yylval->rvalue.bit_width = 32;
+ yylval->rvalue.is_dotnew = false;
+ return IMM; }
+"P"{PRED_ID}"V" {
+ yylval->rvalue.type = PREDICATE;
+ yylval->rvalue.pred.id = yytext[1];
+ yylval->rvalue.bit_width = 32;
+ yylval->rvalue.is_dotnew = false;
+ yylval->rvalue.signedness = SIGNED;
+ return PRED; }
+"P"{PRED_ID}"N" {
+ yylval->rvalue.type = PREDICATE;
+ yylval->rvalue.pred.id = yytext[1];
+ yylval->rvalue.bit_width = 32;
+ yylval->rvalue.is_dotnew = true;
+ yylval->rvalue.signedness = SIGNED;
+ return PRED; }
+"IV1DEAD()" |
+"fPAUSE(uiV);" { return ';'; }
+"+=" { return INC; }
+"-=" { return DEC; }
+"++" { return PLUSPLUS; }
+"&=" { return ANDA; }
+"|=" { return ORA; }
+"^=" { return XORA; }
+"<<" { return ASL; }
+">>" { return ASR; }
+">>>" { return LSR; }
+"==" { return EQ; }
+"!=" { return NEQ; }
+"<=" { return LTE; }
+">=" { return GTE; }
+"&&" { return ANDL; }
+"else" { return ELSE; }
+"for" { return FOR; }
+"fREAD_IREG" { return ICIRC; }
+"fPART1" { return PART1; }
+"if" { return IF; }
+"fFRAME_SCRAMBLE" { return FSCR; }
+"fFRAME_UNSCRAMBLE" { return FSCR; }
+"fFRAMECHECK" { return FCHK; }
+"Constant_extended" { return CONSTEXT; }
+"fCL1_"{DIGIT} { return LOCNT; }
+"fbrev" { return BREV; }
+"fSXTN" { return SXT; }
+"fZXTN" { return ZXT; }
+"fDF_MAX" |
+"fSF_MAX" |
+"fMAX" { return MAX; }
+"fDF_MIN" |
+"fSF_MIN" |
+"fMIN" { return MIN; }
+"fABS" { return ABS; }
+"fRNDN" { return ROUND; }
+"fCRND" { return CROUND; }
+"fCRNDN" { return CROUND; }
+"fPM_CIRI" { return CIRCADD; }
+"fPM_CIRR" { return CIRCADD; }
+"fCOUNTONES_"{DIGIT} { return COUNTONES; }
+"fSATN" { yylval->sat.set_overflow = true;
+ yylval->sat.signedness = SIGNED;
+ return SAT; }
+"fVSATN" { yylval->sat.set_overflow = false;
+ yylval->sat.signedness = SIGNED;
+ return SAT; }
+"fSATUN" { yylval->sat.set_overflow = true;
+ yylval->sat.signedness = UNSIGNED;
+ return SAT; }
+"fCONSTLL" { yylval->cast.bit_width = 64;
+ yylval->cast.signedness = SIGNED;
+ return CAST; }
+"fCONSTULL" { yylval->cast.bit_width = 64;
+ yylval->cast.signedness = UNSIGNED;
+ return CAST; }
+"fSE32_64" { yylval->cast.bit_width = 64;
+ yylval->cast.signedness = SIGNED;
+ return CAST; }
+"fCAST4_4u" { yylval->cast.bit_width = 32;
+ yylval->cast.signedness = UNSIGNED;
+ return CAST; }
+"fCAST4_8s" { yylval->cast.bit_width = 64;
+ yylval->cast.signedness = SIGNED;
+ return CAST; }
+"fCAST4_8u" { return CAST4_8U; }
+"fCAST4u" { yylval->cast.bit_width = 32;
+ yylval->cast.signedness = UNSIGNED;
+ return CAST; }
+"fNEWREG" |
+"fCAST4_4s" |
+"fCAST4s" { yylval->cast.bit_width = 32;
+ yylval->cast.signedness = SIGNED;
+ return CAST; }
+"fCAST8_8u" { yylval->cast.bit_width = 64;
+ yylval->cast.signedness = UNSIGNED;
+ return CAST; }
+"fCAST8u" { yylval->cast.bit_width = 64;
+ yylval->cast.signedness = UNSIGNED;
+ return CAST; }
+"fCAST8_8s" |
+"fCAST8s" { yylval->cast.bit_width = 64;
+ yylval->cast.signedness = SIGNED;
+ return CAST; }
+"fGETBIT" { yylval->extract.bit_width = 1;
+ yylval->extract.storage_bit_width = 1;
+ yylval->extract.signedness = UNSIGNED;
+ return EXTRACT; }
+"fGETBYTE" { yylval->extract.bit_width = 8;
+ yylval->extract.storage_bit_width = 8;
+ yylval->extract.signedness = SIGNED;
+ return EXTRACT; }
+"fGETUBYTE" { yylval->extract.bit_width = 8;
+ yylval->extract.storage_bit_width = 8;
+ yylval->extract.signedness = UNSIGNED;
+ return EXTRACT; }
+"fGETHALF" { yylval->extract.bit_width = 16;
+ yylval->extract.storage_bit_width = 16;
+ yylval->extract.signedness = SIGNED;
+ return EXTRACT; }
+"fGETUHALF" { yylval->extract.bit_width = 16;
+ yylval->extract.storage_bit_width = 16;
+ yylval->extract.signedness = UNSIGNED;
+ return EXTRACT; }
+"fGETWORD" { yylval->extract.bit_width = 32;
+ yylval->extract.storage_bit_width = 64;
+ yylval->extract.signedness = SIGNED;
+ return EXTRACT; }
+"fGETUWORD" { yylval->extract.bit_width = 32;
+ yylval->extract.storage_bit_width = 64;
+ yylval->extract.signedness = UNSIGNED;
+ return EXTRACT; }
+"fEXTRACTU_BITS" { return EXTBITS; }
+"fEXTRACTU_RANGE" { return EXTRANGE; }
+"fSETBIT" { yylval->cast.bit_width = 1;
+ yylval->cast.signedness = SIGNED;
+ return DEPOSIT; }
+"fSETBYTE" { yylval->cast.bit_width = 8;
+ yylval->cast.signedness = SIGNED;
+ return DEPOSIT; }
+"fSETHALF" { yylval->cast.bit_width = 16;
+ yylval->cast.signedness = SIGNED;
+ return SETHALF; }
+"fSETWORD" { yylval->cast.bit_width = 32;
+ yylval->cast.signedness = SIGNED;
+ return DEPOSIT; }
+"fINSERT_BITS" { return INSBITS; }
+"fSETBITS" { return SETBITS; }
+"fMPY8UU" { yylval->mpy.first_bit_width = 8;
+ yylval->mpy.second_bit_width = 8;
+ yylval->mpy.first_signedness = UNSIGNED;
+ yylval->mpy.second_signedness = UNSIGNED;
+ return MPY; }
+"fMPY8US" { yylval->mpy.first_bit_width = 8;
+ yylval->mpy.second_bit_width = 8;
+ yylval->mpy.first_signedness = UNSIGNED;
+ yylval->mpy.second_signedness = SIGNED;
+ return MPY; }
+"fMPY8SU" { yylval->mpy.first_bit_width = 8;
+ yylval->mpy.second_bit_width = 8;
+ yylval->mpy.first_signedness = SIGNED;
+ yylval->mpy.second_signedness = UNSIGNED;
+ return MPY; }
+"fMPY8SS" { yylval->mpy.first_bit_width = 8;
+ yylval->mpy.second_bit_width = 8;
+ yylval->mpy.first_signedness = SIGNED;
+ yylval->mpy.second_signedness = SIGNED;
+ return MPY; }
+"fMPY16UU" { yylval->mpy.first_bit_width = 16;
+ yylval->mpy.second_bit_width = 16;
+ yylval->mpy.first_signedness = UNSIGNED;
+ yylval->mpy.second_signedness = UNSIGNED;
+ return MPY; }
+"fMPY16US" { yylval->mpy.first_bit_width = 16;
+ yylval->mpy.second_bit_width = 16;
+ yylval->mpy.first_signedness = UNSIGNED;
+ yylval->mpy.second_signedness = SIGNED;
+ return MPY; }
+"fMPY16SU" { yylval->mpy.first_bit_width = 16;
+ yylval->mpy.second_bit_width = 16;
+ yylval->mpy.first_signedness = SIGNED;
+ yylval->mpy.second_signedness = UNSIGNED;
+ return MPY; }
+"fMPY16SS" { yylval->mpy.first_bit_width = 16;
+ yylval->mpy.second_bit_width = 16;
+ yylval->mpy.first_signedness = SIGNED;
+ yylval->mpy.second_signedness = SIGNED;
+ return MPY; }
+"fMPY32UU" { yylval->mpy.first_bit_width = 32;
+ yylval->mpy.second_bit_width = 32;
+ yylval->mpy.first_signedness = UNSIGNED;
+ yylval->mpy.second_signedness = UNSIGNED;
+ return MPY; }
+"fMPY32US" { yylval->mpy.first_bit_width = 32;
+ yylval->mpy.second_bit_width = 32;
+ yylval->mpy.first_signedness = UNSIGNED;
+ yylval->mpy.second_signedness = SIGNED;
+ return MPY; }
+"fMPY32SU" { yylval->mpy.first_bit_width = 32;
+ yylval->mpy.second_bit_width = 32;
+ yylval->mpy.first_signedness = SIGNED;
+ yylval->mpy.second_signedness = UNSIGNED;
+ return MPY; }
+"fSFMPY" |
+"fMPY32SS" { yylval->mpy.first_bit_width = 32;
+ yylval->mpy.second_bit_width = 32;
+ yylval->mpy.first_signedness = SIGNED;
+ yylval->mpy.second_signedness = SIGNED;
+ return MPY; }
+"fMPY3216SS" { yylval->mpy.first_bit_width = 32;
+ yylval->mpy.second_bit_width = 16;
+ yylval->mpy.first_signedness = SIGNED;
+ yylval->mpy.second_signedness = SIGNED;
+ return MPY; }
+"fMPY3216SU" { yylval->mpy.first_bit_width = 32;
+ yylval->mpy.second_bit_width = 16;
+ yylval->mpy.first_signedness = SIGNED;
+ yylval->mpy.second_signedness = UNSIGNED;
+ return MPY; }
+"fNEWREG_ST" |
+"fIMMEXT" |
+"fMUST_IMMEXT" |
+"fPASS" |
+"fECHO" { return IDENTITY; }
+"(size8"[us]"_t)" { yylval->cast.bit_width = 64;
+ if (yytext[6] == 'u') {
+ yylval->cast.signedness = UNSIGNED;
+ } else {
+ yylval->cast.signedness = SIGNED;
+ }
+ return CAST; }
+"(int)" { yylval->cast.bit_width = 32;
+ yylval->cast.signedness = SIGNED;
+ return CAST; }
+"(unsigned int)" { yylval->cast.bit_width = 32;
+ yylval->cast.signedness = UNSIGNED;
+ return CAST; }
+"fREAD_PC()" |
+"PC" { return PC; }
+"fREAD_NPC()" |
+"NPC" { return NPC; }
+"fGET_LPCFG" |
+"USR.LPCFG" { return LPCFG; }
+"LOAD_CANCEL(EA)" |
+"STORE_CANCEL(EA)" |
+"CANCEL" { return CANCEL; }
+"N"{LOWER_ID} { yylval->rvalue.type = REGISTER_ARG;
+ yylval->rvalue.reg.type = GENERAL_PURPOSE;
+ yylval->rvalue.reg.id = yytext[1];
+ yylval->rvalue.reg.bit_width = 32;
+ yylval->rvalue.bit_width = 32;
+ yylval->rvalue.signedness = UNSIGNED;
+ return REG; }
+"N"{LOWER_ID}"N" { yylval->rvalue.type = REGISTER_ARG;
+ yylval->rvalue.reg.type = DOTNEW;
+ yylval->rvalue.reg.id = yytext[1];
+ yylval->rvalue.reg.bit_width = 32;
+ yylval->rvalue.bit_width = 32;
+ yylval->rvalue.signedness = UNSIGNED;
+ return REG; }
+"fREAD_SP()" |
+"SP" { yylval->rvalue.type = REGISTER;
+ yylval->rvalue.reg.type = GENERAL_PURPOSE;
+ yylval->rvalue.reg.id = HEX_REG_SP;
+ yylval->rvalue.reg.bit_width = 32;
+ yylval->rvalue.bit_width = 32;
+ yylval->rvalue.signedness = UNSIGNED;
+ return REG; }
+"fREAD_FP()" |
+"FP" { yylval->rvalue.type = REGISTER;
+ yylval->rvalue.reg.type = GENERAL_PURPOSE;
+ yylval->rvalue.reg.id = HEX_REG_FP;
+ yylval->rvalue.reg.bit_width = 32;
+ yylval->rvalue.bit_width = 32;
+ yylval->rvalue.signedness = UNSIGNED;
+ return REG; }
+"fREAD_LR()" |
+"LR" { yylval->rvalue.type = REGISTER;
+ yylval->rvalue.reg.type = GENERAL_PURPOSE;
+ yylval->rvalue.reg.id = HEX_REG_LR;
+ yylval->rvalue.reg.bit_width = 32;
+ yylval->rvalue.bit_width = 32;
+ yylval->rvalue.signedness = UNSIGNED;
+ return REG; }
+"fREAD_GP()" |
+"GP" { yylval->rvalue.type = REGISTER;
+ yylval->rvalue.reg.type = CONTROL;
+ yylval->rvalue.reg.id = HEX_REG_GP;
+ yylval->rvalue.reg.bit_width = 32;
+ yylval->rvalue.bit_width = 32;
+ yylval->rvalue.signedness = UNSIGNED;
+ return REG; }
+"fREAD_LC"[01] { yylval->rvalue.type = REGISTER;
+ yylval->rvalue.reg.type = CONTROL;
+ yylval->rvalue.reg.id = HEX_REG_LC0
+ + (yytext[8] - '0') * 2;
+ yylval->rvalue.reg.bit_width = 32;
+ yylval->rvalue.bit_width = 32;
+ yylval->rvalue.signedness = UNSIGNED;
+ return REG; }
+"LC"[01] { yylval->rvalue.type = REGISTER;
+ yylval->rvalue.reg.type = CONTROL;
+ yylval->rvalue.reg.id = HEX_REG_LC0
+ + (yytext[2] - '0') * 2;
+ yylval->rvalue.reg.bit_width = 32;
+ yylval->rvalue.bit_width = 32;
+ yylval->rvalue.signedness = UNSIGNED;
+ return REG; }
+"fREAD_SA"[01] { yylval->rvalue.type = REGISTER;
+ yylval->rvalue.reg.type = CONTROL;
+ yylval->rvalue.reg.id = HEX_REG_SA0
+ + (yytext[8] - '0') * 2;
+ yylval->rvalue.reg.bit_width = 32;
+ yylval->rvalue.bit_width = 32;
+ yylval->rvalue.signedness = UNSIGNED;
+ return REG; }
+"SA"[01] { yylval->rvalue.type = REGISTER;
+ yylval->rvalue.reg.type = CONTROL;
+ yylval->rvalue.reg.id = HEX_REG_SA0
+ + (yytext[2] - '0') * 2;
+ yylval->rvalue.reg.bit_width = 32;
+ yylval->rvalue.bit_width = 32;
+ yylval->rvalue.signedness = UNSIGNED;
+ return REG; }
+"MuN" { return MUN; }
+"fREAD_P0()" { yylval->rvalue.type = PREDICATE;
+ yylval->rvalue.pred.id = '0';
+ yylval->rvalue.bit_width = 32;
+ return PRED; }
+[pP]{DIGIT} { yylval->rvalue.type = PREDICATE;
+ yylval->rvalue.pred.id = yytext[1];
+ yylval->rvalue.bit_width = 32;
+ yylval->rvalue.is_dotnew = false;
+ return PRED; }
+[pP]{DIGIT}[nN] { yylval->rvalue.type = PREDICATE;
+ yylval->rvalue.pred.id = yytext[1];
+ yylval->rvalue.bit_width = 32;
+ yylval->rvalue.is_dotnew = true;
+ return PRED; }
+"fLSBNEW" { return LSBNEW; }
+"N" { yylval->rvalue.type = IMMEDIATE;
+ yylval->rvalue.bit_width = 32;
+ yylval->rvalue.imm.type = VARIABLE;
+ yylval->rvalue.imm.id = 'N';
+ return IMM; }
+"i" { yylval->rvalue.type = IMMEDIATE;
+ yylval->rvalue.bit_width = 32;
+ yylval->rvalue.signedness = SIGNED;
+ yylval->rvalue.imm.type = I;
+ return IMM; }
+{SIGN_ID} { if (yytext[0] == 'u') {
+ yylval->signedness = UNSIGNED;
+ } else {
+ yylval->signedness = SIGNED;
+ }
+ return SIGN;
+ }
+"fSF_BIAS()" { yylval->rvalue.type = IMMEDIATE;
+ yylval->rvalue.bit_width = 32;
+ yylval->rvalue.signedness = SIGNED;
+ yylval->rvalue.imm.type = VALUE;
+ yylval->rvalue.imm.value = 127;
+ return IMM; }
+"0x"{HEX_DIGIT}+ |
+{DIGIT}+ { yylval->rvalue.type = IMMEDIATE;
+ yylval->rvalue.bit_width = 32;
+ yylval->rvalue.signedness = SIGNED;
+ yylval->rvalue.imm.type = VALUE;
+ yylval->rvalue.imm.value = strtoull(yytext, NULL, 0);
+ return IMM; }
+"0x"{HEX_DIGIT}+"LL" |
+{DIGIT}+"LL" { yylval->rvalue.type = IMMEDIATE;
+ yylval->rvalue.bit_width = 64;
+ yylval->rvalue.signedness = SIGNED;
+ yylval->rvalue.imm.type = VALUE;
+ yylval->rvalue.imm.value = strtoull(yytext, NULL, 0);
+ return IMM; }
+"0x"{HEX_DIGIT}+"ULL" |
+{DIGIT}+"ULL" { yylval->rvalue.type = IMMEDIATE;
+ yylval->rvalue.bit_width = 64;
+ yylval->rvalue.signedness = UNSIGNED;
+ yylval->rvalue.imm.type = VALUE;
+ yylval->rvalue.imm.value = strtoull(yytext, NULL, 0);
+ return IMM; }
+"fLOAD" { return LOAD; }
+"fSTORE" { return STORE; }
+"fROTL" { return ROTL; }
+"fSET_OVERFLOW" { return SETOVF; }
+"fCARRY_FROM_ADD" { return CARRY_FROM_ADD; }
+"fADDSAT64" { return ADDSAT64; }
+"size"[1248][us]"_t" { /* Handles "size_t" variants of int types */
+ const unsigned int bits_per_byte = 8;
+ const unsigned int bytes = yytext[4] - '0';
+ yylval->rvalue.bit_width = bits_per_byte * bytes;
+ if (yytext[5] == 'u') {
+ yylval->rvalue.signedness = UNSIGNED;
+ } else {
+ yylval->rvalue.signedness = SIGNED;
+ }
+ return TYPE_SIZE_T; }
+"size16"[us]"_t" { /* Handles "size_t" variants of int types */
+ yylval->rvalue.bit_width = 128;
+ if (yytext[6] == 'u') {
+ yylval->rvalue.signedness = UNSIGNED;
+ } else {
+ yylval->rvalue.signedness = SIGNED;
+ }
+ return TYPE_SIZE_T; }
+"signed" { return TYPE_SIGNED; }
+"unsigned" { return TYPE_UNSIGNED; }
+"long" { return TYPE_LONG; }
+"int" { return TYPE_INT; }
+"const" { /* Emit no token */ }
+{VAR_ID} { /* Variable name, we adopt the C names convention */
+ yylval->rvalue.type = VARID;
+ yylval->rvalue.var.name = g_string_new(yytext);
+ /* Default to an unknown signedness and 0 width. */
+ yylval->rvalue.bit_width = 0;
+ yylval->rvalue.signedness = UNKNOWN_SIGNEDNESS;
+ return VAR; }
+"fatal("{STRING_LIT}")" { /* Emit no token */ }
+"fHINTJR(RsV)" { /* Emit no token */ }
+. { return yytext[0]; }
+
+%%
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index 5945098cc4..63f13e1d21 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -196,4 +196,8 @@ preprocessed_idef_parser_input_generated = custom_target(
command: [idef_parser_dir / 'prepare', '@INPUT@', '-I' + idef_parser_dir, '-o', '@OUTPUT@'],
)
+flex = generator(find_program('flex'),
+ output: ['@BASENAME@.yy.c', '@BASENAME@.yy.h'],
+ arguments: ['-o', '@OUTPUT0@', '--header-file=@OUTPUT1@', '@INPUT@'])
+
target_arch += {'hexagon': hexagon_ss}
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v8 10/12] target/hexagon: import parser for idef-parser
2022-02-09 17:03 [PATCH v8 00/12] target/hexagon: introduce idef-parser Anton Johansson via
` (8 preceding siblings ...)
2022-02-09 17:03 ` [PATCH v8 09/12] target/hexagon: import lexer for idef-parser Anton Johansson via
@ 2022-02-09 17:03 ` Anton Johansson via
2022-04-11 15:20 ` Taylor Simpson
2022-02-09 17:03 ` [PATCH v8 11/12] target/hexagon: call idef-parser functions Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 12/12] target/hexagon: import additional tests Anton Johansson via
11 siblings, 1 reply; 23+ messages in thread
From: Anton Johansson via @ 2022-02-09 17:03 UTC (permalink / raw)
To: qemu-devel
Cc: ale, tsimpson, bcain, mlambert, babush, nizzo, richard.henderson
Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Paolo Montesel <babush@rev.ng>
Signed-off-by: Anton Johansson <anjo@rev.ng>
---
target/hexagon/idef-parser/idef-parser.y | 1039 ++++++++
target/hexagon/idef-parser/parser-helpers.c | 2551 +++++++++++++++++++
target/hexagon/idef-parser/parser-helpers.h | 375 +++
target/hexagon/meson.build | 25 +
4 files changed, 3990 insertions(+)
create mode 100644 target/hexagon/idef-parser/idef-parser.y
create mode 100644 target/hexagon/idef-parser/parser-helpers.c
create mode 100644 target/hexagon/idef-parser/parser-helpers.h
diff --git a/target/hexagon/idef-parser/idef-parser.y b/target/hexagon/idef-parser/idef-parser.y
new file mode 100644
index 0000000000..b6489be9fb
--- /dev/null
+++ b/target/hexagon/idef-parser/idef-parser.y
@@ -0,0 +1,1039 @@
+%{
+/*
+ * Copyright(c) 2019-2021 rev.ng Labs Srl. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "idef-parser.h"
+#include "parser-helpers.h"
+#include "idef-parser.tab.h"
+#include "idef-parser.yy.h"
+
+/* Uncomment this to disable yyasserts */
+/* #define NDEBUG */
+
+#define ERR_LINE_CONTEXT 40
+
+%}
+
+%lex-param {void *scanner}
+%parse-param {void *scanner}
+%parse-param {Context *c}
+
+%define parse.error verbose
+%define parse.lac full
+%define api.pure full
+
+%locations
+
+%union {
+ GString *string;
+ HexValue rvalue;
+ HexSat sat;
+ HexCast cast;
+ HexExtract extract;
+ HexMpy mpy;
+ HexSignedness signedness;
+ int index;
+}
+
+/* Tokens */
+%start input
+
+%expect 1
+
+%token IN INAME VAR
+%token ABS CROUND ROUND CIRCADD COUNTONES INC DEC ANDA ORA XORA PLUSPLUS ASL
+%token ASR LSR EQ NEQ LTE GTE MIN MAX ANDL FOR ICIRC IF MUN FSCR FCHK SXT
+%token ZXT CONSTEXT LOCNT BREV SIGN LOAD STORE PC NPC LPCFG
+%token CANCEL IDENTITY PART1 ROTL INSBITS SETBITS EXTBITS EXTRANGE
+%token CAST4_8U SETOVF FAIL CARRY_FROM_ADD ADDSAT64 LSBNEW
+%token TYPE_SIZE_T TYPE_INT TYPE_SIGNED TYPE_UNSIGNED TYPE_LONG
+
+%token <rvalue> REG IMM PRED
+%token <index> ELSE
+%token <mpy> MPY
+%token <sat> SAT
+%token <cast> CAST DEPOSIT SETHALF
+%token <extract> EXTRACT
+%type <string> INAME
+%type <rvalue> rvalue lvalue VAR assign_statement var var_decl var_type
+%type <rvalue> FAIL
+%type <rvalue> TYPE_SIGNED TYPE_UNSIGNED TYPE_INT TYPE_LONG TYPE_SIZE_T
+%type <index> if_stmt IF
+%type <signedness> SIGN
+
+/* Operator Precedences */
+%left MIN MAX
+%left '('
+%left ','
+%left '='
+%right CIRCADD
+%right INC DEC ANDA ORA XORA
+%left '?' ':'
+%left ANDL
+%left '|'
+%left '^' ANDOR
+%left '&'
+%left EQ NEQ
+%left '<' '>' LTE GTE
+%left ASL ASR LSR
+%right ABS
+%left '-' '+'
+%left '*' '/' '%' MPY
+%right '~' '!'
+%left '['
+%right CAST
+%right LOCNT BREV
+
+/* Bison Grammar */
+%%
+
+/* Input file containing the description of each hexagon instruction */
+input : instructions
+ {
+ YYACCEPT;
+ }
+ ;
+
+instructions : instruction instructions
+ | %empty
+ ;
+
+instruction : INAME
+ {
+ gen_inst(c, $1);
+ }
+ arguments
+ {
+ EMIT_SIG(c, ")");
+ EMIT_HEAD(c, "{\n");
+ }
+ code
+ {
+ gen_inst_code(c, &@1);
+ }
+ | error /* Recover gracefully after instruction compilation error */
+ {
+ free_instruction(c);
+ }
+ ;
+
+arguments : '(' ')'
+ | '(' argument_list ')';
+
+argument_list : argument_decl ',' argument_list
+ | argument_decl
+ ;
+
+var : VAR
+ {
+ track_string(c, $1.var.name);
+ $$ = $1;
+ }
+ ;
+
+/*
+ * Here the integer types are defined from valid combinations of
+ * "signed", "unsigned", "int", and "long" tokens. The "signed"
+ * and "unsigned" tokens are here assumed to always be placed
+ * first in the type declaration, which is not the case in
+ * normal C. Similarly, "int" is assumed to be placed in the type.
+ */
+type_int : TYPE_INT
+ | TYPE_SIGNED
+ | TYPE_SIGNED TYPE_INT;
+type_uint : TYPE_UNSIGNED
+ | TYPE_UNSIGNED TYPE_INT;
+type_long : TYPE_LONG
+ | TYPE_LONG TYPE_INT
+ | TYPE_SIGNED TYPE_LONG
+ | TYPE_SIGNED TYPE_LONG TYPE_INT;
+type_ulong : TYPE_UNSIGNED TYPE_LONG
+ | TYPE_UNSIGNED TYPE_LONG TYPE_INT;
+type_longlong : TYPE_LONG TYPE_LONG
+ | TYPE_LONG TYPE_LONG TYPE_INT
+ | TYPE_SIGNED TYPE_LONG TYPE_LONG
+ | TYPE_SIGNED TYPE_LONG TYPE_LONG TYPE_INT;
+type_ulonglong : TYPE_UNSIGNED TYPE_LONG TYPE_LONG
+ | TYPE_UNSIGNED TYPE_LONG TYPE_LONG TYPE_INT;
+
+/*
+ * Here the various valid int types defined above specify
+ * their `signedness` and `bit_width`. The LP64 convention
+ * is assumed where longs are 64-bit, long longs are then
+ * assumed to also be 64-bit.abvove
+ */
+var_type : TYPE_SIZE_T
+ {
+ yyassert(c, &@1, $1.bit_width <= 64,
+ "Variables with size > 64-bit are not supported!");
+ $$ = $1;
+ }
+ | type_int
+ {
+ $$.signedness = SIGNED;
+ $$.bit_width = 32;
+ }
+ | type_uint
+ {
+ $$.signedness = UNSIGNED;
+ $$.bit_width = 32;
+ }
+ | type_long
+ {
+ $$.signedness = SIGNED;
+ $$.bit_width = 64;
+ }
+ | type_ulong
+ {
+ $$.signedness = UNSIGNED;
+ $$.bit_width = 64;
+ }
+ | type_longlong
+ {
+ $$.signedness = SIGNED;
+ $$.bit_width = 64;
+ }
+ | type_ulonglong
+ {
+ $$.signedness = UNSIGNED;
+ $$.bit_width = 64;
+ }
+ ;
+
+/* Rule to capture declarations of VARs */
+var_decl : var_type IMM
+ {
+ /*
+ * Rule to capture "int i;" declarations since "i" is special
+ * and assumed to be always be IMM. Moreover, "i" is only
+ * assumed to be used in for-loops.
+ *
+ * Therefore we want to NOP these declarations.
+ */
+ yyassert(c, &@2, $2.imm.type == I,
+ "Variable declaration with immedaties only allowed"
+ " for the loop induction variable \"i\"");
+ $$ = $2;
+ }
+ | var_type var
+ {
+ /*
+ * Allocate new variable, this checks that it hasn't aldready
+ * been declared.
+ */
+ gen_varid_allocate(c, &@1, &$2, $1.bit_width, $1.signedness);
+ /* Copy var for variable name */
+ $$ = $2;
+ /* Copy type info from var_type */
+ $$.signedness = $1.signedness;
+ $$.bit_width = $1.bit_width;
+ }
+ ;
+
+/* Return the modified registers list */
+code : '{' statements '}'
+ {
+ c->inst.code_begin = c->input_buffer + @2.first_column - 1;
+ c->inst.code_end = c->input_buffer + @2.last_column - 1;
+ }
+ | '{'
+ {
+ /* Nop */
+ }
+ '}'
+ ;
+
+argument_decl : REG
+ {
+ emit_arg(c, &@1, &$1);
+ /* Enqueue register into initialization list */
+ g_array_append_val(c->inst.init_list, $1);
+ }
+ | PRED
+ {
+ emit_arg(c, &@1, &$1);
+ /* Enqueue predicate into initialization list */
+ g_array_append_val(c->inst.init_list, $1);
+ }
+ | IN REG
+ {
+ emit_arg(c, &@2, &$2);
+ }
+ | IN PRED
+ {
+ emit_arg(c, &@2, &$2);
+ }
+ | IMM
+ {
+ EMIT_SIG(c, ", int %ciV", $1.imm.id);
+ }
+ ;
+
+code_block : '{' statements '}'
+ | '{' '}'
+ ;
+
+/* A list of one or more statements */
+statements : statements statement
+ | statement
+ ;
+
+/* Statements can be assignment (rvalue ';'), control or memory statements */
+statement : control_statement
+ | var_decl ';'
+ | rvalue ';'
+ {
+ gen_rvalue_free(c, &@1, &$1);
+ }
+ | code_block
+ | ';'
+ ;
+
+assign_statement : lvalue '=' rvalue
+ {
+ @1.last_column = @3.last_column;
+ gen_assign(c, &@1, &$1, &$3);
+ $$ = $1;
+ }
+ | var_decl '=' rvalue
+ {
+ @1.last_column = @3.last_column;
+ gen_assign(c, &@1, &$1, &$3);
+ $$ = $1;
+ }
+ | lvalue INC rvalue
+ {
+ @1.last_column = @3.last_column;
+ HexValue tmp = gen_bin_op(c, &@1, ADD_OP, &$1, &$3);
+ gen_assign(c, &@1, &$1, &tmp);
+ $$ = $1;
+ }
+ | lvalue DEC rvalue
+ {
+ @1.last_column = @3.last_column;
+ HexValue tmp = gen_bin_op(c, &@1, SUB_OP, &$1, &$3);
+ gen_assign(c, &@1, &$1, &tmp);
+ $$ = $1;
+ }
+ | lvalue ANDA rvalue
+ {
+ @1.last_column = @3.last_column;
+ HexValue tmp = gen_bin_op(c, &@1, ANDB_OP, &$1, &$3);
+ gen_assign(c, &@1, &$1, &tmp);
+ $$ = $1;
+ }
+ | lvalue ORA rvalue
+ {
+ @1.last_column = @3.last_column;
+ HexValue tmp = gen_bin_op(c, &@1, ORB_OP, &$1, &$3);
+ gen_assign(c, &@1, &$1, &tmp);
+ $$ = $1;
+ }
+ | lvalue XORA rvalue
+ {
+ @1.last_column = @3.last_column;
+ HexValue tmp = gen_bin_op(c, &@1, XORB_OP, &$1, &$3);
+ gen_assign(c, &@1, &$1, &tmp);
+ $$ = $1;
+ }
+ | PRED '=' rvalue
+ {
+ @1.last_column = @3.last_column;
+ gen_pred_assign(c, &@1, &$1, &$3);
+ }
+ | IMM '=' rvalue
+ {
+ @1.last_column = @3.last_column;
+ yyassert(c, &@1, $3.type == IMMEDIATE,
+ "Cannot assign non-immediate to immediate!");
+ yyassert(c, &@1, $1.imm.type == VARIABLE,
+ "Cannot assign to non-variable!");
+ /* Assign to the function argument */
+ OUT(c, &@1, &$1, " = ", &$3, ";\n");
+ $$ = $1;
+ }
+ | PC '=' rvalue
+ {
+ @1.last_column = @3.last_column;
+ yyassert(c, &@1, c->ternary->len == 0,
+ "Assignment side-effect not modeled!");
+ $3 = gen_rvalue_truncate(c, &@1, &$3);
+ $3 = rvalue_materialize(c, &@1, &$3);
+ OUT(c, &@1, "gen_write_new_pc(", &$3, ");\n");
+ gen_rvalue_free(c, &@1, &$3); /* Free temporary value */
+ }
+ | LOAD '(' IMM ',' IMM ',' SIGN ',' var ',' lvalue ')'
+ {
+ @1.last_column = @12.last_column;
+ yyassert(c, &@1, c->ternary->len == 0,
+ "Assignment side-effect not modeled!");
+ yyassert(c, &@1, $3.imm.value == 1,
+ "LOAD of arrays not supported!");
+ gen_load(c, &@1, &$5, $7, &$9, &$11);
+ }
+ | STORE '(' IMM ',' IMM ',' var ',' rvalue ')'
+ /* Store primitive */
+ {
+ @1.last_column = @10.last_column;
+ yyassert(c, &@1, c->ternary->len == 0,
+ "Assignment side-effect not modeled!");
+ yyassert(c, &@1, $3.imm.value == 1,
+ "STORE of arrays not supported!");
+ gen_store(c, &@1, &$5, &$7, &$9);
+ }
+ | LPCFG '=' rvalue
+ {
+ @1.last_column = @3.last_column;
+ yyassert(c, &@1, c->ternary->len == 0,
+ "Assignment side-effect not modeled!");
+ $3 = gen_rvalue_truncate(c, &@1, &$3);
+ $3 = rvalue_materialize(c, &@1, &$3);
+ OUT(c, &@1, "SET_USR_FIELD(USR_LPCFG, ", &$3, ");\n");
+ gen_rvalue_free(c, &@1, &$3);
+ }
+ | DEPOSIT '(' rvalue ',' rvalue ',' rvalue ')'
+ {
+ @1.last_column = @8.last_column;
+ yyassert(c, &@1, c->ternary->len == 0,
+ "Assignment side-effect not modeled!");
+ gen_deposit_op(c, &@1, &$5, &$7, &$3, &$1);
+ }
+ | SETHALF '(' rvalue ',' lvalue ',' rvalue ')'
+ {
+ @1.last_column = @8.last_column;
+ yyassert(c, &@1, c->ternary->len == 0,
+ "Assignment side-effect not modeled!");
+ gen_sethalf(c, &@1, &$1, &$3, &$5, &$7);
+ }
+ | SETBITS '(' rvalue ',' rvalue ',' rvalue ',' rvalue ')'
+ {
+ @1.last_column = @10.last_column;
+ yyassert(c, &@1, c->ternary->len == 0,
+ "Assignment side-effect not modeled!");
+ gen_setbits(c, &@1, &$3, &$5, &$7, &$9);
+ }
+ | INSBITS '(' lvalue ',' rvalue ',' rvalue ',' rvalue ')'
+ {
+ @1.last_column = @10.last_column;
+ yyassert(c, &@1, c->ternary->len == 0,
+ "Assignment side-effect not modeled!");
+ gen_rdeposit_op(c, &@1, &$3, &$9, &$7, &$5);
+ }
+ | IDENTITY '(' rvalue ')'
+ {
+ @1.last_column = @4.last_column;
+ $$ = $3;
+ }
+ ;
+
+control_statement : frame_check
+ | cancel_statement
+ | if_statement
+ | for_statement
+ | fpart1_statement
+ ;
+
+frame_check : FCHK '(' rvalue ',' rvalue ')' ';'
+ {
+ gen_rvalue_free(c, &@1, &$3);
+ gen_rvalue_free(c, &@1, &$5);
+ }
+ ;
+
+cancel_statement : CANCEL
+ {
+ OUT(c, &@1, "gen_cancel(insn->slot);\n");
+ }
+ ;
+
+if_statement : if_stmt
+ {
+ /* Fix else label */
+ OUT(c, &@1, "gen_set_label(if_label_", &$1, ");\n");
+ }
+ | if_stmt ELSE
+ {
+ @1.last_column = @2.last_column;
+ $2 = gen_if_else(c, &@1, $1);
+ }
+ statement
+ {
+ OUT(c, &@1, "gen_set_label(if_label_", &$2, ");\n");
+ }
+ ;
+
+for_statement : FOR '(' IMM '=' IMM ';' IMM '<' IMM ';' IMM PLUSPLUS ')'
+ {
+ yyassert(c, &@3,
+ $3.imm.type == I &&
+ $7.imm.type == I &&
+ $11.imm.type == I,
+ "Loop induction variable must be \"i\"");
+ @1.last_column = @13.last_column;
+ OUT(c, &@1, "for (int ", &$3, " = ", &$5, "; ",
+ &$7, " < ", &$9);
+ OUT(c, &@1, "; ", &$11, "++) {\n");
+ }
+ code_block
+ {
+ OUT(c, &@1, "}\n");
+ }
+ | FOR '(' IMM '=' IMM ';' IMM '<' IMM ';' IMM INC IMM ')'
+ {
+ yyassert(c, &@3,
+ $3.imm.type == I &&
+ $7.imm.type == I &&
+ $11.imm.type == I,
+ "Loop induction variable must be \"i\"");
+ @1.last_column = @14.last_column;
+ OUT(c, &@1, "for (int ", &$3, " = ", &$5, "; ",
+ &$7, " < ", &$9);
+ OUT(c, &@1, "; ", &$11, " += ", &$13, ") {\n");
+ }
+ code_block
+ {
+ OUT(c, &@1, "}\n");
+ }
+ ;
+
+fpart1_statement : PART1
+ {
+ OUT(c, &@1, "if (insn->part1) {\n");
+ }
+ '(' statements ')'
+ {
+ @1.last_column = @3.last_column;
+ OUT(c, &@1, "return; }\n");
+ }
+ ;
+
+if_stmt : IF '(' rvalue ')'
+ {
+ @1.last_column = @3.last_column;
+ $1 = gen_if_cond(c, &@1, &$3);
+ }
+ statement
+ {
+ $$ = $1;
+ }
+ ;
+
+rvalue : FAIL
+ {
+ yyassert(c, &@1, false, "Encountered a FAIL token as rvalue.\n");
+ }
+ | assign_statement
+ | REG
+ {
+ if ($1.type == REGISTER_ARG) {
+ $$ = gen_read_reg(c, &@1, &$1);
+ } else {
+ $$ = $1;
+ }
+ }
+ | IMM
+ {
+ $$ = $1;
+ }
+ | PRED
+ {
+ $$ = gen_rvalue_pred(c, &@1, &$1);
+ }
+ | PC
+ {
+ /* Read PC from the CR */
+ HexValue rvalue;
+ memset(&rvalue, 0, sizeof(HexValue));
+ rvalue.type = IMMEDIATE;
+ rvalue.imm.type = IMM_PC;
+ rvalue.bit_width = 32;
+ rvalue.signedness = UNSIGNED;
+ $$ = rvalue;
+ }
+ | NPC
+ {
+ /*
+ * NPC is only read from CALLs, so we can hardcode it
+ * at translation time
+ */
+ HexValue rvalue;
+ memset(&rvalue, 0, sizeof(HexValue));
+ rvalue.type = IMMEDIATE;
+ rvalue.imm.type = IMM_NPC;
+ rvalue.bit_width = 32;
+ rvalue.signedness = UNSIGNED;
+ $$ = rvalue;
+ }
+ | CONSTEXT
+ {
+ HexValue rvalue;
+ memset(&rvalue, 0, sizeof(HexValue));
+ rvalue.type = IMMEDIATE;
+ rvalue.imm.type = IMM_CONSTEXT;
+ rvalue.signedness = UNSIGNED;
+ rvalue.is_dotnew = false;
+ rvalue.is_manual = false;
+ $$ = rvalue;
+ }
+ | var
+ {
+ $$ = gen_rvalue_var(c, &@1, &$1);
+ }
+ | MPY '(' rvalue ',' rvalue ')'
+ {
+ @1.last_column = @6.last_column;
+ $$ = gen_rvalue_mpy(c, &@1, &$1, &$3, &$5);
+ }
+ | rvalue '+' rvalue
+ {
+ @1.last_column = @3.last_column;
+ $$ = gen_bin_op(c, &@1, ADD_OP, &$1, &$3);
+ }
+ | rvalue '-' rvalue
+ {
+ @1.last_column = @3.last_column;
+ $$ = gen_bin_op(c, &@1, SUB_OP, &$1, &$3);
+ }
+ | rvalue '*' rvalue
+ {
+ @1.last_column = @3.last_column;
+ $$ = gen_bin_op(c, &@1, MUL_OP, &$1, &$3);
+ }
+ | rvalue '%' rvalue
+ {
+ @1.last_column = @3.last_column;
+ $$ = gen_bin_op(c, &@1, MOD_OP, &$1, &$3);
+ }
+ | rvalue ASL rvalue
+ {
+ @1.last_column = @3.last_column;
+ $$ = gen_bin_op(c, &@1, ASL_OP, &$1, &$3);
+ }
+ | rvalue ASR rvalue
+ {
+ @1.last_column = @3.last_column;
+ assert_signedness(c, &@1, $1.signedness);
+ if ($1.signedness == UNSIGNED) {
+ $$ = gen_bin_op(c, &@1, LSR_OP, &$1, &$3);
+ } else if ($1.signedness == SIGNED) {
+ $$ = gen_bin_op(c, &@1, ASR_OP, &$1, &$3);
+ }
+ }
+ | rvalue LSR rvalue
+ {
+ @1.last_column = @3.last_column;
+ $$ = gen_bin_op(c, &@1, LSR_OP, &$1, &$3);
+ }
+ | rvalue '&' rvalue
+ {
+ @1.last_column = @3.last_column;
+ $$ = gen_bin_op(c, &@1, ANDB_OP, &$1, &$3);
+ }
+ | rvalue '|' rvalue
+ {
+ @1.last_column = @3.last_column;
+ $$ = gen_bin_op(c, &@1, ORB_OP, &$1, &$3);
+ }
+ | rvalue '^' rvalue
+ {
+ @1.last_column = @3.last_column;
+ $$ = gen_bin_op(c, &@1, XORB_OP, &$1, &$3);
+ }
+ | rvalue ANDL rvalue
+ {
+ @1.last_column = @3.last_column;
+ $$ = gen_bin_op(c, &@1, ANDL_OP, &$1, &$3);
+ }
+ | MIN '(' rvalue ',' rvalue ')'
+ {
+ @1.last_column = @3.last_column;
+ $$ = gen_bin_op(c, &@1, MINI_OP, &$3, &$5);
+ }
+ | MAX '(' rvalue ',' rvalue ')'
+ {
+ @1.last_column = @3.last_column;
+ $$ = gen_bin_op(c, &@1, MAXI_OP, &$3, &$5);
+ }
+ | '~' rvalue
+ {
+ @1.last_column = @2.last_column;
+ $$ = gen_rvalue_not(c, &@1, &$2);
+ }
+ | '!' rvalue
+ {
+ @1.last_column = @2.last_column;
+ $$ = gen_rvalue_notl(c, &@1, &$2);
+ }
+ | SAT '(' IMM ',' rvalue ')'
+ {
+ @1.last_column = @6.last_column;
+ $$ = gen_rvalue_sat(c, &@1, &$1, &$3, &$5);
+ }
+ | CAST rvalue
+ {
+ @1.last_column = @2.last_column;
+ /* Assign target signedness */
+ $2.signedness = $1.signedness;
+ $$ = gen_cast_op(c, &@1, &$2, $1.bit_width, $1.signedness);
+ }
+ | rvalue EQ rvalue
+ {
+ @1.last_column = @3.last_column;
+ $$ = gen_bin_cmp(c, &@1, TCG_COND_EQ, &$1, &$3);
+ }
+ | rvalue NEQ rvalue
+ {
+ @1.last_column = @3.last_column;
+ $$ = gen_bin_cmp(c, &@1, TCG_COND_NE, &$1, &$3);
+ }
+ | rvalue '<' rvalue
+ {
+ @1.last_column = @3.last_column;
+
+ assert_signedness(c, &@1, $1.signedness);
+ assert_signedness(c, &@1, $3.signedness);
+ if ($1.signedness == UNSIGNED || $3.signedness == UNSIGNED) {
+ $$ = gen_bin_cmp(c, &@1, TCG_COND_LTU, &$1, &$3);
+ } else {
+ $$ = gen_bin_cmp(c, &@1, TCG_COND_LT, &$1, &$3);
+ }
+ }
+ | rvalue '>' rvalue
+ {
+ @1.last_column = @3.last_column;
+
+ assert_signedness(c, &@1, $1.signedness);
+ assert_signedness(c, &@1, $3.signedness);
+ if ($1.signedness == UNSIGNED || $3.signedness == UNSIGNED) {
+ $$ = gen_bin_cmp(c, &@1, TCG_COND_GTU, &$1, &$3);
+ } else {
+ $$ = gen_bin_cmp(c, &@1, TCG_COND_GT, &$1, &$3);
+ }
+ }
+ | rvalue LTE rvalue
+ {
+ @1.last_column = @3.last_column;
+
+ assert_signedness(c, &@1, $1.signedness);
+ assert_signedness(c, &@1, $3.signedness);
+ if ($1.signedness == UNSIGNED || $3.signedness == UNSIGNED) {
+ $$ = gen_bin_cmp(c, &@1, TCG_COND_LEU, &$1, &$3);
+ } else {
+ $$ = gen_bin_cmp(c, &@1, TCG_COND_LE, &$1, &$3);
+ }
+ }
+ | rvalue GTE rvalue
+ {
+ @1.last_column = @3.last_column;
+
+ assert_signedness(c, &@1, $1.signedness);
+ assert_signedness(c, &@1, $3.signedness);
+ if ($1.signedness == UNSIGNED || $3.signedness == UNSIGNED) {
+ $$ = gen_bin_cmp(c, &@1, TCG_COND_GEU, &$1, &$3);
+ } else {
+ $$ = gen_bin_cmp(c, &@1, TCG_COND_GE, &$1, &$3);
+ }
+ }
+ | rvalue '?'
+ {
+ $1.is_manual = true;
+ Ternary t = { 0 };
+ t.state = IN_LEFT;
+ t.cond = $1;
+ g_array_append_val(c->ternary, t);
+ }
+ rvalue ':'
+ {
+ Ternary *t = &g_array_index(c->ternary, Ternary,
+ c->ternary->len - 1);
+ t->state = IN_RIGHT;
+ }
+ rvalue
+ {
+ @1.last_column = @5.last_column;
+ $$ = gen_rvalue_ternary(c, &@1, &$1, &$4, &$7);
+ }
+ | FSCR '(' rvalue ')'
+ {
+ @1.last_column = @4.last_column;
+ $$ = gen_rvalue_fscr(c, &@1, &$3);
+ }
+ | SXT '(' rvalue ',' IMM ',' rvalue ')'
+ {
+ @1.last_column = @8.last_column;
+ yyassert(c, &@1, $5.type == IMMEDIATE &&
+ $5.imm.type == VALUE,
+ "SXT expects immediate values\n");
+ $$ = gen_extend_op(c, &@1, &$3, $5.imm.value, &$7, SIGNED);
+ }
+ | ZXT '(' rvalue ',' IMM ',' rvalue ')'
+ {
+ @1.last_column = @8.last_column;
+ yyassert(c, &@1, $5.type == IMMEDIATE &&
+ $5.imm.type == VALUE,
+ "ZXT expects immediate values\n");
+ $$ = gen_extend_op(c, &@1, &$3, $5.imm.value, &$7, UNSIGNED);
+ }
+ | '(' rvalue ')'
+ {
+ $$ = $2;
+ }
+ | ABS rvalue
+ {
+ @1.last_column = @2.last_column;
+ $$ = gen_rvalue_abs(c, &@1, &$2);
+ }
+ | CROUND '(' rvalue ',' rvalue ')'
+ {
+ @1.last_column = @6.last_column;
+ $$ = gen_convround_n(c, &@1, &$3, &$5);
+ }
+ | CROUND '(' rvalue ')'
+ {
+ @1.last_column = @4.last_column;
+ $$ = gen_convround(c, &@1, &$3);
+ }
+ | ROUND '(' rvalue ',' rvalue ')'
+ {
+ @1.last_column = @6.last_column;
+ $$ = gen_round(c, &@1, &$3, &$5);
+ }
+ | '-' rvalue
+ {
+ @1.last_column = @2.last_column;
+ $$ = gen_rvalue_neg(c, &@1, &$2);
+ }
+ | ICIRC '(' rvalue ')' ASL IMM
+ {
+ @1.last_column = @6.last_column;
+ $$ = gen_tmp(c, &@1, 32, UNSIGNED);
+ OUT(c, &@1, "gen_read_ireg(", &$$, ", ", &$3, ", ", &$6, ");\n");
+ gen_rvalue_free(c, &@1, &$3);
+ }
+ | CIRCADD '(' rvalue ',' rvalue ',' rvalue ')'
+ {
+ @1.last_column = @8.last_column;
+ gen_circ_op(c, &@1, &$3, &$5, &$7);
+ }
+ | LOCNT '(' rvalue ')'
+ {
+ @1.last_column = @4.last_column;
+ /* Leading ones count */
+ $$ = gen_locnt_op(c, &@1, &$3);
+ }
+ | COUNTONES '(' rvalue ')'
+ {
+ @1.last_column = @4.last_column;
+ /* Ones count */
+ $$ = gen_ctpop_op(c, &@1, &$3);
+ }
+ | LPCFG
+ {
+ $$ = gen_tmp_value(c, &@1, "0", 32, UNSIGNED);
+ OUT(c, &@1, "GET_USR_FIELD(USR_LPCFG, ", &$$, ");\n");
+ }
+ | EXTRACT '(' rvalue ',' rvalue ')'
+ {
+ @1.last_column = @6.last_column;
+ $$ = gen_extract_op(c, &@1, &$5, &$3, &$1);
+ }
+ | EXTBITS '(' rvalue ',' rvalue ',' rvalue ')'
+ {
+ @1.last_column = @8.last_column;
+ yyassert(c, &@1, $5.type == IMMEDIATE &&
+ $5.imm.type == VALUE &&
+ $7.type == IMMEDIATE &&
+ $7.imm.type == VALUE,
+ "Range extract needs immediate values!\n");
+ $$ = gen_rextract_op(c, &@1, &$3, $7.imm.value, $5.imm.value);
+ }
+ | EXTRANGE '(' rvalue ',' rvalue ',' rvalue ')'
+ {
+ @1.last_column = @8.last_column;
+ yyassert(c, &@1, $5.type == IMMEDIATE &&
+ $5.imm.type == VALUE &&
+ $7.type == IMMEDIATE &&
+ $7.imm.type == VALUE,
+ "Range extract needs immediate values!\n");
+ $$ = gen_rextract_op(c,
+ &@1,
+ &$3,
+ $7.imm.value,
+ $5.imm.value - $7.imm.value + 1);
+ }
+ | CAST4_8U '(' rvalue ')'
+ {
+ @1.last_column = @4.last_column;
+ $$ = gen_rvalue_truncate(c, &@1, &$3);
+ $$.signedness = UNSIGNED;
+ $$ = rvalue_materialize(c, &@1, &$$);
+ $$ = gen_rvalue_extend(c, &@1, &$$);
+ }
+ | BREV '(' rvalue ')'
+ {
+ @1.last_column = @4.last_column;
+ $$ = gen_rvalue_brev(c, &@1, &$3);
+ }
+ | ROTL '(' rvalue ',' rvalue ')'
+ {
+ @1.last_column = @6.last_column;
+ $$ = gen_rotl(c, &@1, &$3, &$5);
+ }
+ | SETOVF '(' ')'
+ {
+ @1.last_column = @3.last_column;
+ HexValue ovfl = gen_imm_value(c, &@1, 1, 32, UNSIGNED);
+ gen_set_overflow(c, &@1, &ovfl);
+ }
+ | SETOVF '(' rvalue ')'
+ {
+ /* Convenience fSET_OVERFLOW with pass-through */
+ @1.last_column = @3.last_column;
+ HexValue ovfl = gen_imm_value(c, &@1, 1, 32, UNSIGNED);
+ gen_set_overflow(c, &@1, &ovfl);
+ $$ = $3;
+ }
+ | ADDSAT64 '(' rvalue ',' rvalue ',' rvalue ')'
+ {
+ @1.last_column = @8.last_column;
+ gen_addsat64(c, &@1, &$3, &$5, &$7);
+ }
+ | CARRY_FROM_ADD '(' rvalue ',' rvalue ',' rvalue ')'
+ {
+ @1.last_column = @8.last_column;
+ $$ = gen_carry_from_add(c, &@1, &$3, &$5, &$7);
+ }
+ | LSBNEW '(' rvalue ')'
+ {
+ @1.last_column = @4.last_column;
+ HexValue one = gen_imm_value(c, &@1, 1, 32, UNSIGNED);
+ $$ = gen_bin_op(c, &@1, ANDB_OP, &$3, &one);
+ }
+ ;
+
+lvalue : FAIL
+ {
+ @1.last_column = @1.last_column;
+ yyassert(c, &@1, false, "Encountered a FAIL token as lvalue.\n");
+ }
+ | REG
+ {
+ $$ = $1;
+ }
+ | var
+ {
+ $$ = $1;
+ }
+ ;
+
+%%
+
+int main(int argc, char **argv)
+{
+ if (argc != 5) {
+ fprintf(stderr,
+ "Semantics: Hexagon ISA to tinycode generator compiler\n\n");
+ fprintf(stderr,
+ "Usage: ./semantics IDEFS EMITTER_C EMITTER_H "
+ "ENABLED_INSTRUCTIONS_LIST\n");
+ return 1;
+ }
+
+ enum {
+ ARG_INDEX_ARGV0 = 0,
+ ARG_INDEX_IDEFS,
+ ARG_INDEX_EMITTER_C,
+ ARG_INDEX_EMITTER_H,
+ ARG_INDEX_ENABLED_INSTRUCTIONS_LIST
+ };
+
+ FILE *enabled_file = fopen(argv[ARG_INDEX_ENABLED_INSTRUCTIONS_LIST], "w");
+
+ FILE *output_file = fopen(argv[ARG_INDEX_EMITTER_C], "w");
+ fputs("#include \"qemu/osdep.h\"\n", output_file);
+ fputs("#include \"qemu/log.h\"\n", output_file);
+ fputs("#include \"cpu.h\"\n", output_file);
+ fputs("#include \"internal.h\"\n", output_file);
+ fputs("#include \"tcg/tcg-op.h\"\n", output_file);
+ fputs("#include \"insn.h\"\n", output_file);
+ fputs("#include \"opcodes.h\"\n", output_file);
+ fputs("#include \"translate.h\"\n", output_file);
+ fputs("#define QEMU_GENERATE\n", output_file);
+ fputs("#include \"genptr.h\"\n", output_file);
+ fputs("#include \"tcg/tcg.h\"\n", output_file);
+ fputs("#include \"macros.h\"\n", output_file);
+ fprintf(output_file, "#include \"%s\"\n", argv[ARG_INDEX_EMITTER_H]);
+
+ FILE *defines_file = fopen(argv[ARG_INDEX_EMITTER_H], "w");
+ assert(defines_file != NULL);
+ fputs("#ifndef HEX_EMITTER_H\n", defines_file);
+ fputs("#define HEX_EMITTER_H\n", defines_file);
+ fputs("\n", defines_file);
+ fputs("#include \"insn.h\"\n\n", defines_file);
+
+ /* Parser input file */
+ Context context = { 0 };
+ context.defines_file = defines_file;
+ context.output_file = output_file;
+ context.enabled_file = enabled_file;
+ /* Initialize buffers */
+ context.out_str = g_string_new(NULL);
+ context.signature_str = g_string_new(NULL);
+ context.header_str = g_string_new(NULL);
+ context.ternary = g_array_new(FALSE, TRUE, sizeof(Ternary));
+ /* Read input file */
+ FILE *input_file = fopen(argv[ARG_INDEX_IDEFS], "r");
+ fseek(input_file, 0L, SEEK_END);
+ long input_size = ftell(input_file);
+ context.input_buffer = (char *) calloc(input_size + 1, sizeof(char));
+ fseek(input_file, 0L, SEEK_SET);
+ size_t read_chars = fread(context.input_buffer,
+ sizeof(char),
+ input_size,
+ input_file);
+ if (read_chars != (size_t) input_size) {
+ fprintf(stderr, "Error: an error occurred while reading input file!\n");
+ return -1;
+ }
+ yylex_init(&context.scanner);
+ YY_BUFFER_STATE buffer;
+ buffer = yy_scan_string(context.input_buffer, context.scanner);
+ /* Start the parsing procedure */
+ yyparse(context.scanner, &context);
+ if (context.implemented_insn != context.total_insn) {
+ fprintf(stderr,
+ "Warning: %d/%d meta instructions have been implemented!\n",
+ context.implemented_insn,
+ context.total_insn);
+ }
+ fputs("#endif " START_COMMENT " HEX_EMITTER_h " END_COMMENT "\n",
+ defines_file);
+ /* Cleanup */
+ yy_delete_buffer(buffer, context.scanner);
+ yylex_destroy(context.scanner);
+ free(context.input_buffer);
+ g_string_free(context.out_str, TRUE);
+ g_string_free(context.signature_str, TRUE);
+ g_string_free(context.header_str, TRUE);
+ g_array_free(context.ternary, TRUE);
+ fclose(output_file);
+ fclose(input_file);
+ fclose(defines_file);
+ fclose(enabled_file);
+
+ return 0;
+}
diff --git a/target/hexagon/idef-parser/parser-helpers.c b/target/hexagon/idef-parser/parser-helpers.c
new file mode 100644
index 0000000000..0ac18ca150
--- /dev/null
+++ b/target/hexagon/idef-parser/parser-helpers.c
@@ -0,0 +1,2551 @@
+/*
+ * Copyright(c) 2019-2021 rev.ng Labs Srl. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "idef-parser.h"
+#include "parser-helpers.h"
+#include "idef-parser.tab.h"
+#include "idef-parser.yy.h"
+
+void yyerror(YYLTYPE *locp,
+ yyscan_t scanner __attribute__((unused)),
+ Context *c,
+ const char *s)
+{
+ const char *code_ptr = c->input_buffer;
+
+ fprintf(stderr, "WARNING (%s): '%s'\n", c->inst.name->str, s);
+
+ fprintf(stderr, "Problematic range: ");
+ for (int i = locp->first_column; i < locp->last_column; i++) {
+ if (code_ptr[i] != '\n') {
+ fprintf(stderr, "%c", code_ptr[i]);
+ }
+ }
+ fprintf(stderr, "\n");
+
+ for (unsigned i = 0;
+ i < 80 &&
+ code_ptr[locp->first_column - 10 + i] != '\0' &&
+ code_ptr[locp->first_column - 10 + i] != '\n';
+ i++) {
+ fprintf(stderr, "%c", code_ptr[locp->first_column - 10 + i]);
+ }
+ fprintf(stderr, "\n");
+ for (unsigned i = 0; i < 9; i++) {
+ fprintf(stderr, " ");
+ }
+ fprintf(stderr, "^");
+ for (int i = 0; i < (locp->last_column - locp->first_column) - 1; i++) {
+ fprintf(stderr, "~");
+ }
+ fprintf(stderr, "\n");
+ c->inst.error_count++;
+}
+
+bool is_direct_predicate(HexValue *value)
+{
+ return value->pred.id >= '0' && value->pred.id <= '3';
+}
+
+bool is_inside_ternary(Context *c)
+{
+ return c->ternary->len > 0;
+}
+
+/* Print functions */
+void str_print(Context *c, YYLTYPE *locp, const char *string)
+{
+ (void) locp;
+ EMIT(c, "%s", string);
+}
+
+void uint8_print(Context *c, YYLTYPE *locp, uint8_t *num)
+{
+ (void) locp;
+ EMIT(c, "%u", *num);
+}
+
+void uint64_print(Context *c, YYLTYPE *locp, uint64_t *num)
+{
+ (void) locp;
+ EMIT(c, "%" PRIu64, *num);
+}
+
+void int_print(Context *c, YYLTYPE *locp, int *num)
+{
+ (void) locp;
+ EMIT(c, "%d", *num);
+}
+
+void uint_print(Context *c, YYLTYPE *locp, unsigned *num)
+{
+ (void) locp;
+ EMIT(c, "%u", *num);
+}
+
+void tmp_print(Context *c, YYLTYPE *locp, HexTmp *tmp)
+{
+ (void) locp;
+ EMIT(c, "tmp_%d", tmp->index);
+}
+
+void pred_print(Context *c, YYLTYPE *locp, HexPred *pred, bool is_dotnew)
+{
+ (void) locp;
+ char suffix = is_dotnew ? 'N' : 'V';
+ EMIT(c, "P%c%c", pred->id, suffix);
+}
+
+void reg_compose(Context *c, YYLTYPE *locp, HexReg *reg, char reg_id[5])
+{
+ memset(reg_id, 0, 5 * sizeof(char));
+ switch (reg->type) {
+ case GENERAL_PURPOSE:
+ reg_id[0] = 'R';
+ break;
+ case CONTROL:
+ reg_id[0] = 'C';
+ break;
+ case MODIFIER:
+ reg_id[0] = 'M';
+ break;
+ case DOTNEW:
+ reg_id[0] = 'N';
+ reg_id[1] = reg->id;
+ reg_id[2] = 'N';
+ return;
+ }
+ switch (reg->bit_width) {
+ case 32:
+ reg_id[1] = reg->id;
+ reg_id[2] = 'V';
+ break;
+ case 64:
+ reg_id[1] = reg->id;
+ reg_id[2] = reg->id;
+ reg_id[3] = 'V';
+ break;
+ default:
+ yyassert(c, locp, false, "Unhandled register bit width!\n");
+ }
+}
+
+static void reg_arg_print(Context *c, YYLTYPE *locp, HexReg *reg)
+{
+ char reg_id[5];
+ reg_compose(c, locp, reg, reg_id);
+ EMIT(c, "%s", reg_id);
+}
+
+void reg_print(Context *c, YYLTYPE *locp, HexReg *reg)
+{
+ (void) locp;
+ EMIT(c, "hex_gpr[%u]", reg->id);
+}
+
+void imm_print(Context *c, YYLTYPE *locp, HexImm *imm)
+{
+ switch (imm->type) {
+ case I:
+ EMIT(c, "i");
+ break;
+ case VARIABLE:
+ EMIT(c, "%ciV", imm->id);
+ break;
+ case VALUE:
+ EMIT(c, "((int64_t) %" PRIu64 "ULL)", (int64_t) imm->value);
+ break;
+ case QEMU_TMP:
+ EMIT(c, "qemu_tmp_%" PRIu64, imm->index);
+ break;
+ case IMM_PC:
+ EMIT(c, "ctx->base.pc_next");
+ break;
+ case IMM_NPC:
+ EMIT(c, "ctx->npc");
+ break;
+ case IMM_CONSTEXT:
+ EMIT(c, "insn->extension_valid");
+ break;
+ default:
+ yyassert(c, locp, false, "Cannot print this expression!");
+ }
+}
+
+void var_print(Context *c, YYLTYPE *locp, HexVar *var)
+{
+ (void) locp;
+ EMIT(c, "%s", var->name->str);
+}
+
+void rvalue_print(Context *c, YYLTYPE *locp, void *pointer)
+{
+ HexValue *rvalue = (HexValue *) pointer;
+ switch (rvalue->type) {
+ case REGISTER:
+ reg_print(c, locp, &rvalue->reg);
+ break;
+ case REGISTER_ARG:
+ reg_arg_print(c, locp, &rvalue->reg);
+ break;
+ case TEMP:
+ tmp_print(c, locp, &rvalue->tmp);
+ break;
+ case IMMEDIATE:
+ imm_print(c, locp, &rvalue->imm);
+ break;
+ case VARID:
+ var_print(c, locp, &rvalue->var);
+ break;
+ case PREDICATE:
+ pred_print(c, locp, &rvalue->pred, rvalue->is_dotnew);
+ break;
+ default:
+ yyassert(c, locp, false, "Cannot print this expression!");
+ }
+}
+
+void out_assert(Context *c, YYLTYPE *locp,
+ void *dummy __attribute__((unused)))
+{
+ abort();
+ yyassert(c, locp, false, "Unhandled print type!");
+}
+
+/* Copy output code buffer */
+void commit(Context *c)
+{
+ /* Emit instruction pseudocode */
+ EMIT_SIG(c, "\n" START_COMMENT " ");
+ for (char *x = c->inst.code_begin; x < c->inst.code_end; x++) {
+ EMIT_SIG(c, "%c", *x);
+ }
+ EMIT_SIG(c, " " END_COMMENT "\n");
+
+ /* Commit instruction code to output file */
+ fwrite(c->signature_str->str, sizeof(char), c->signature_str->len,
+ c->output_file);
+ fwrite(c->header_str->str, sizeof(char), c->header_str->len,
+ c->output_file);
+ fwrite(c->out_str->str, sizeof(char), c->out_str->len,
+ c->output_file);
+
+ fwrite(c->signature_str->str, sizeof(char), c->signature_str->len,
+ c->defines_file);
+ fprintf(c->defines_file, ";\n");
+}
+
+static HexValue get_ternary_cond(Context *c, YYLTYPE *locp)
+{
+ Ternary *ternary = NULL;
+ HexValue cond;
+
+ yyassert(c, locp, is_inside_ternary(c), "unexisting condition");
+ ternary = &g_array_index(c->ternary, Ternary, 0);
+ cond = ternary->cond;
+
+ if (ternary->state == IN_RIGHT) {
+ cond = gen_rvalue_notl(c, locp, &cond);
+ }
+ for (unsigned i = 1; i < c->ternary->len; ++i) {
+ Ternary *right = &g_array_index(c->ternary, Ternary, i);
+ HexValue other = right->cond;
+ /* Invert condition if we are on the right side */
+ if (right->state == IN_RIGHT) {
+ other = gen_rvalue_notl(c, locp, &other);
+ }
+ cond = gen_bin_op(c, locp, ANDL_OP, &cond, &other);
+ }
+ return cond;
+}
+
+static void gen_c_int_type(Context *c, YYLTYPE *locp, unsigned bit_width,
+ HexSignedness signedness)
+{
+ const char *signstr = (signedness == UNSIGNED) ? "u" : "";
+ OUT(c, locp, signstr, "int", &bit_width, "_t");
+}
+
+static HexValue gen_constant(Context *c,
+ YYLTYPE *locp,
+ const char *value,
+ unsigned bit_width,
+ HexSignedness signedness)
+{
+ HexValue rvalue;
+ assert(bit_width == 32 || bit_width == 64);
+ memset(&rvalue, 0, sizeof(HexValue));
+ rvalue.type = TEMP;
+ rvalue.bit_width = bit_width;
+ rvalue.signedness = signedness;
+ rvalue.is_dotnew = false;
+ rvalue.is_manual = true;
+ rvalue.tmp.index = c->inst.tmp_count;
+ OUT(c, locp, "TCGv_i", &bit_width, " tmp_", &c->inst.tmp_count,
+ " = tcg_constant_i", &bit_width, "(", value, ");\n");
+ c->inst.tmp_count++;
+ return rvalue;
+}
+
+/* Temporary values creation */
+HexValue gen_tmp(Context *c,
+ YYLTYPE *locp,
+ unsigned bit_width,
+ HexSignedness signedness)
+{
+ HexValue rvalue;
+ assert(bit_width == 32 || bit_width == 64);
+ memset(&rvalue, 0, sizeof(HexValue));
+ rvalue.type = TEMP;
+ rvalue.bit_width = bit_width;
+ rvalue.signedness = signedness;
+ rvalue.is_dotnew = false;
+ rvalue.is_manual = false;
+ rvalue.tmp.index = c->inst.tmp_count;
+ OUT(c, locp, "TCGv_i", &bit_width, " tmp_", &c->inst.tmp_count,
+ " = tcg_temp_new_i", &bit_width, "();\n");
+ c->inst.tmp_count++;
+ return rvalue;
+}
+
+HexValue gen_tmp_value(Context *c,
+ YYLTYPE *locp,
+ const char *value,
+ unsigned bit_width,
+ HexSignedness signedness)
+{
+ HexValue rvalue;
+ assert(bit_width == 32 || bit_width == 64);
+ memset(&rvalue, 0, sizeof(HexValue));
+ rvalue.type = TEMP;
+ rvalue.bit_width = bit_width;
+ rvalue.signedness = signedness;
+ rvalue.is_dotnew = false;
+ rvalue.is_manual = false;
+ rvalue.tmp.index = c->inst.tmp_count;
+ OUT(c, locp, "TCGv_i", &bit_width, " tmp_", &c->inst.tmp_count,
+ " = tcg_const_i", &bit_width, "(", value, ");\n");
+ c->inst.tmp_count++;
+ return rvalue;
+}
+
+static HexValue gen_tmp_value_from_imm(Context *c,
+ YYLTYPE *locp,
+ HexValue *value)
+{
+ HexValue rvalue;
+ assert(value->type == IMMEDIATE);
+ memset(&rvalue, 0, sizeof(HexValue));
+ rvalue.type = TEMP;
+ rvalue.bit_width = value->bit_width;
+ rvalue.signedness = value->signedness;
+ rvalue.is_dotnew = false;
+ rvalue.is_manual = false;
+ rvalue.tmp.index = c->inst.tmp_count;
+ /*
+ * Here we output the call to `tcg_const_i<width>` in
+ * order to create the temporary value. Note, that we
+ * add a cast
+ *
+ * `tcg_const_i<width>`((int<width>_t) ...)`
+ *
+ * This cast is required to avoid implicit integer
+ * conversion warnings since all immediates are
+ * output as `((int64_t) 123ULL)`, even if the
+ * integer is 32-bit.
+ */
+ OUT(c, locp, "TCGv_i", &rvalue.bit_width, " tmp_", &c->inst.tmp_count);
+ OUT(c, locp, " = tcg_const_i", &rvalue.bit_width,
+ "((int", &rvalue.bit_width, "_t) (", value, "));\n");
+
+ c->inst.tmp_count++;
+ return rvalue;
+}
+
+HexValue gen_imm_value(Context *c __attribute__((unused)),
+ YYLTYPE *locp,
+ int value,
+ unsigned bit_width,
+ HexSignedness signedness)
+{
+ (void) locp;
+ HexValue rvalue;
+ assert(bit_width == 32 || bit_width == 64);
+ memset(&rvalue, 0, sizeof(HexValue));
+ rvalue.type = IMMEDIATE;
+ rvalue.bit_width = bit_width;
+ rvalue.signedness = signedness;
+ rvalue.is_dotnew = false;
+ rvalue.is_manual = false;
+ rvalue.imm.type = VALUE;
+ rvalue.imm.value = value;
+ return rvalue;
+}
+
+HexValue gen_imm_qemu_tmp(Context *c, YYLTYPE *locp, unsigned bit_width,
+ HexSignedness signedness)
+{
+ (void) locp;
+ HexValue rvalue;
+ assert(bit_width == 32 || bit_width == 64);
+ memset(&rvalue, 0, sizeof(HexValue));
+ rvalue.type = IMMEDIATE;
+ rvalue.is_dotnew = false;
+ rvalue.is_manual = false;
+ rvalue.bit_width = bit_width;
+ rvalue.signedness = signedness;
+ rvalue.imm.type = QEMU_TMP;
+ rvalue.imm.index = c->inst.qemu_tmp_count++;
+ return rvalue;
+}
+
+void gen_rvalue_free(Context *c, YYLTYPE *locp, HexValue *rvalue)
+{
+ if (rvalue->type == TEMP && !rvalue->is_manual) {
+ const char *bit_suffix = (rvalue->bit_width == 64) ? "i64" : "i32";
+ OUT(c, locp, "tcg_temp_free_", bit_suffix, "(", rvalue, ");\n");
+ }
+}
+
+static void gen_rvalue_free_manual(Context *c, YYLTYPE *locp, HexValue *rvalue)
+{
+ rvalue->is_manual = false;
+ gen_rvalue_free(c, locp, rvalue);
+}
+
+HexValue rvalue_materialize(Context *c, YYLTYPE *locp, HexValue *rvalue)
+{
+ if (rvalue->type == IMMEDIATE) {
+ HexValue res = gen_tmp_value_from_imm(c, locp, rvalue);
+ gen_rvalue_free(c, locp, rvalue);
+ return res;
+ }
+ return *rvalue;
+}
+
+HexValue gen_rvalue_extend(Context *c, YYLTYPE *locp, HexValue *rvalue)
+{
+ assert_signedness(c, locp, rvalue->signedness);
+ if (rvalue->bit_width > 32) {
+ return *rvalue;
+ }
+
+ if (rvalue->type == IMMEDIATE) {
+ HexValue res = gen_imm_qemu_tmp(c, locp, 64, rvalue->signedness);
+ bool is_unsigned = (rvalue->signedness == UNSIGNED);
+ const char *sign_suffix = is_unsigned ? "u" : "";
+ gen_c_int_type(c, locp, 64, rvalue->signedness);
+ OUT(c, locp, " ", &res, " = ");
+ OUT(c, locp, "(", sign_suffix, "int64_t) ");
+ OUT(c, locp, "(", sign_suffix, "int32_t) ");
+ OUT(c, locp, rvalue, ";\n");
+ return res;
+ } else {
+ HexValue res = gen_tmp(c, locp, 64, rvalue->signedness);
+ bool is_unsigned = (rvalue->signedness == UNSIGNED);
+ const char *sign_suffix = is_unsigned ? "u" : "";
+ OUT(c, locp, "tcg_gen_ext", sign_suffix,
+ "_i32_i64(", &res, ", ", rvalue, ");\n");
+ gen_rvalue_free(c, locp, rvalue);
+ return res;
+ }
+}
+
+HexValue gen_rvalue_truncate(Context *c, YYLTYPE *locp, HexValue *rvalue)
+{
+ if (rvalue->type == IMMEDIATE) {
+ HexValue res = *rvalue;
+ res.bit_width = 32;
+ return res;
+ } else {
+ if (rvalue->bit_width == 64) {
+ HexValue res = gen_tmp(c, locp, 32, rvalue->signedness);
+ OUT(c, locp, "tcg_gen_trunc_i64_tl(", &res, ", ", rvalue, ");\n");
+ gen_rvalue_free(c, locp, rvalue);
+ return res;
+ }
+ }
+ return *rvalue;
+}
+
+/*
+ * Attempts to lookup the `Var` struct associated with the given `varid`.
+ * The `dst` argument is populated with the found name, bit_width, and
+ * signedness, given that `dst` is non-NULL. Returns true if the lookup
+ * succeeded and false otherwise.
+ */
+static bool try_find_variable(Context *c, YYLTYPE *locp,
+ HexValue *dst,
+ HexValue *varid)
+{
+ yyassert(c, locp, varid, "varid to lookup is NULL");
+ yyassert(c, locp, varid->type == VARID,
+ "Can only lookup variables by varid");
+ for (unsigned i = 0; i < c->inst.allocated->len; i++) {
+ Var *curr = &g_array_index(c->inst.allocated, Var, i);
+ if (g_string_equal(varid->var.name, curr->name)) {
+ if (dst) {
+ dst->var.name = curr->name;
+ dst->bit_width = curr->bit_width;
+ dst->signedness = curr->signedness;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Calls `try_find_variable` and asserts succcess. */
+static void find_variable(Context *c, YYLTYPE *locp,
+ HexValue *dst,
+ HexValue *varid)
+{
+ bool found = try_find_variable(c, locp, dst, varid);
+ yyassert(c, locp, found, "Use of undeclared variable!\n");
+}
+
+/* Handle signedness, if both unsigned -> result is unsigned, else signed */
+static inline HexSignedness bin_op_signedness(Context *c, YYLTYPE *locp,
+ HexSignedness sign1,
+ HexSignedness sign2)
+{
+ assert_signedness(c, locp, sign1);
+ assert_signedness(c, locp, sign2);
+ return (sign1 == UNSIGNED && sign2 == UNSIGNED) ? UNSIGNED : SIGNED;
+}
+
+void gen_varid_allocate(Context *c,
+ YYLTYPE *locp,
+ HexValue *varid,
+ unsigned bit_width,
+ HexSignedness signedness)
+{
+ const char *bit_suffix = (bit_width == 64) ? "i64" : "i32";
+ bool found = try_find_variable(c, locp, NULL, varid);
+ Var new_var;
+
+ memset(&new_var, 0, sizeof(Var));
+
+ yyassert(c, locp, !found, "Redeclaration of variables not allowed!");
+ assert_signedness(c, locp, signedness);
+
+ /* `varid` only carries name information */
+ new_var.name = varid->var.name;
+ new_var.bit_width = bit_width;
+ new_var.signedness = signedness;
+
+ EMIT_HEAD(c, "TCGv_%s %s", bit_suffix, varid->var.name->str);
+ EMIT_HEAD(c, " = tcg_temp_local_new_%s();\n", bit_suffix);
+ g_array_append_val(c->inst.allocated, new_var);
+}
+
+enum OpTypes {
+ IMM_IMM = 0,
+ IMM_REG = 1,
+ REG_IMM = 2,
+ REG_REG = 3,
+};
+
+HexValue gen_bin_cmp(Context *c,
+ YYLTYPE *locp,
+ TCGCond type,
+ HexValue *op1,
+ HexValue *op2)
+{
+ HexValue op1_m = *op1;
+ HexValue op2_m = *op2;
+ enum OpTypes op_types = (op1_m.type != IMMEDIATE) << 1
+ | (op2_m.type != IMMEDIATE);
+
+ bool op_is64bit = op1_m.bit_width == 64 || op2_m.bit_width == 64;
+ const char *bit_suffix = op_is64bit ? "i64" : "i32";
+ unsigned bit_width = (op_is64bit) ? 64 : 32;
+ HexValue res = gen_tmp(c, locp, bit_width, UNSIGNED);
+
+ /* Extend to 64-bits, if required */
+ if (op_is64bit) {
+ op1_m = gen_rvalue_extend(c, locp, &op1_m);
+ op2_m = gen_rvalue_extend(c, locp, &op2_m);
+ }
+
+ switch (op_types) {
+ case IMM_IMM:
+ OUT(c, locp, "tcg_gen_movi_", bit_suffix,
+ "(", &res, ", ", &op1_m, " == ", &op2_m, ");\n");
+ break;
+ case IMM_REG:
+ {
+ HexValue swp = op2_m;
+ op2_m = op1_m;
+ op1_m = swp;
+ /* Swap comparison direction */
+ type = tcg_swap_cond(type);
+ }
+ /* fallthrough */
+ case REG_IMM:
+ OUT(c, locp, "tcg_gen_setcondi_", bit_suffix, "(");
+ OUT(c, locp, cond_to_str(type), ", ", &res, ", ", &op1_m, ", ", &op2_m,
+ ");\n");
+ break;
+ case REG_REG:
+ OUT(c, locp, "tcg_gen_setcond_", bit_suffix, "(");
+ OUT(c, locp, cond_to_str(type), ", ", &res, ", ", &op1_m, ", ", &op2_m,
+ ");\n");
+ break;
+ default:
+ fprintf(stderr, "Error in evalutating immediateness!");
+ abort();
+ }
+
+ /* Free operands */
+ gen_rvalue_free(c, locp, &op1_m);
+ gen_rvalue_free(c, locp, &op2_m);
+
+ return res;
+}
+
+static void gen_simple_op(Context *c, YYLTYPE *locp, unsigned bit_width,
+ const char *bit_suffix, HexValue *res,
+ enum OpTypes op_types,
+ HexValue *op1,
+ HexValue *op2,
+ const char *imm_imm,
+ const char *imm_reg,
+ const char *reg_imm,
+ const char *reg_reg)
+{
+ switch (op_types) {
+ case IMM_IMM: {
+ HexSignedness signedness = bin_op_signedness(c, locp,
+ op1->signedness,
+ op2->signedness);
+ gen_c_int_type(c, locp, bit_width, signedness);
+ OUT(c, locp, " ", res,
+ " = ", op1, imm_imm, op2, ";\n");
+ } break;
+ case IMM_REG:
+ OUT(c, locp, imm_reg, bit_suffix,
+ "(", res, ", ", op2, ", ", op1, ");\n");
+ break;
+ case REG_IMM:
+ OUT(c, locp, reg_imm, bit_suffix,
+ "(", res, ", ", op1, ", ", op2, ");\n");
+ break;
+ case REG_REG:
+ OUT(c, locp, reg_reg, bit_suffix,
+ "(", res, ", ", op1, ", ", op2, ");\n");
+ break;
+ }
+ gen_rvalue_free(c, locp, op1);
+ gen_rvalue_free(c, locp, op2);
+}
+
+static void gen_sub_op(Context *c, YYLTYPE *locp, unsigned bit_width,
+ const char *bit_suffix, HexValue *res,
+ enum OpTypes op_types, HexValue *op1,
+ HexValue *op2)
+{
+ switch (op_types) {
+ case IMM_IMM: {
+ HexSignedness signedness = bin_op_signedness(c, locp,
+ op1->signedness,
+ op2->signedness);
+ gen_c_int_type(c, locp, bit_width, signedness);
+ OUT(c, locp, " ", res,
+ " = ", op1, " - ", op2, ";\n");
+ } break;
+ case IMM_REG: {
+ OUT(c, locp, "tcg_gen_subfi_", bit_suffix,
+ "(", res, ", ", op1, ", ", op2, ");\n");
+ } break;
+ case REG_IMM: {
+ OUT(c, locp, "tcg_gen_subi_", bit_suffix,
+ "(", res, ", ", op1, ", ", op2, ");\n");
+ } break;
+ case REG_REG: {
+ OUT(c, locp, "tcg_gen_sub_", bit_suffix,
+ "(", res, ", ", op1, ", ", op2, ");\n");
+ } break;
+ }
+ gen_rvalue_free(c, locp, op1);
+ gen_rvalue_free(c, locp, op2);
+}
+
+static void gen_asl_op(Context *c, YYLTYPE *locp, unsigned bit_width,
+ bool op_is64bit, const char *bit_suffix,
+ HexValue *res, enum OpTypes op_types,
+ HexValue *op1, HexValue *op2)
+{
+ HexValue op1_m = *op1;
+ HexValue op2_m = *op2;
+ switch (op_types) {
+ case IMM_IMM: {
+ HexSignedness signedness = bin_op_signedness(c, locp,
+ op1->signedness,
+ op2->signedness);
+ gen_c_int_type(c, locp, bit_width, signedness);
+ OUT(c, locp, " ", res,
+ " = ", op1, " << ", op2, ";\n");
+ } break;
+ case REG_IMM: {
+ OUT(c, locp, "if (", op2, " >= ", &bit_width, ") {\n");
+ OUT(c, locp, "tcg_gen_movi_", bit_suffix, "(", res, ", 0);\n");
+ OUT(c, locp, "} else {\n");
+ OUT(c, locp, "tcg_gen_shli_", bit_suffix,
+ "(", res, ", ", op1, ", ", op2, ");\n");
+ OUT(c, locp, "}\n");
+ } break;
+ case IMM_REG:
+ op1_m.bit_width = bit_width;
+ op1_m = rvalue_materialize(c, locp, &op1_m);
+ /* fallthrough */
+ case REG_REG: {
+ OUT(c, locp, "tcg_gen_shl_", bit_suffix,
+ "(", res, ", ", &op1_m, ", ", op2, ");\n");
+ } break;
+ }
+ if (op_types == IMM_REG || op_types == REG_REG) {
+ /*
+ * Handle left shift by 64/32 which hexagon-sim expects to clear out
+ * register
+ */
+ HexValue zero = gen_constant(c, locp, "0", bit_width, UNSIGNED);
+ HexValue edge = gen_imm_value(c, locp, bit_width, bit_width, UNSIGNED);
+ edge = rvalue_materialize(c, locp, &edge);
+ if (op_is64bit) {
+ op2_m = gen_rvalue_extend(c, locp, &op2_m);
+ }
+ op1_m = rvalue_materialize(c, locp, &op1_m);
+ op2_m = rvalue_materialize(c, locp, &op2_m);
+ OUT(c, locp, "tcg_gen_movcond_i", &bit_width);
+ OUT(c, locp, "(TCG_COND_GEU, ", res, ", ", &op2_m, ", ", &edge);
+ OUT(c, locp, ", ", &zero, ", ", res, ");\n");
+ gen_rvalue_free(c, locp, &edge);
+ }
+ gen_rvalue_free(c, locp, &op1_m);
+ gen_rvalue_free(c, locp, &op2_m);
+}
+
+static void gen_asr_op(Context *c, YYLTYPE *locp, unsigned bit_width,
+ bool op_is64bit, const char *bit_suffix,
+ HexValue *res, enum OpTypes op_types,
+ HexValue *op1, HexValue *op2)
+{
+ HexValue op1_m = *op1;
+ HexValue op2_m = *op2;
+ switch (op_types) {
+ case IMM_IMM: {
+ HexSignedness signedness = bin_op_signedness(c, locp,
+ op1->signedness,
+ op2->signedness);
+ gen_c_int_type(c, locp, bit_width, signedness);
+ OUT(c, locp, " ", res,
+ " = ", op1, " >> ", op2, ";\n");
+ } break;
+ case REG_IMM: {
+ HexSignedness signedness = bin_op_signedness(c, locp,
+ op1->signedness,
+ op2->signedness);
+ OUT(c, locp, "{\n");
+ gen_c_int_type(c, locp, bit_width, signedness);
+ OUT(c, locp, " shift = ", op2, ";\n");
+ OUT(c, locp, "if (", op2, " >= ", &bit_width, ") {\n");
+ OUT(c, locp, " shift = ", &bit_width, " - 1;\n");
+ OUT(c, locp, "}\n");
+ OUT(c, locp, "tcg_gen_sari_", bit_suffix,
+ "(", res, ", ", op1, ", shift);\n}\n");
+ } break;
+ case IMM_REG:
+ op1_m = rvalue_materialize(c, locp, &op1_m);
+ /* Fallthrough */
+ case REG_REG:
+ OUT(c, locp, "tcg_gen_sar_", bit_suffix,
+ "(", res, ", ", &op1_m, ", ", op2, ");\n");
+ break;
+ }
+ if (op_types == IMM_REG || op_types == REG_REG) {
+ /* Handle right shift by values >= bit_width */
+ const char *offset = op_is64bit ? "63" : "31";
+ HexValue tmp = gen_tmp(c, locp, bit_width, SIGNED);
+ HexValue zero = gen_constant(c, locp, "0", bit_width, SIGNED);
+ HexValue edge = gen_imm_value(c, locp, bit_width, bit_width, UNSIGNED);
+
+ edge = rvalue_materialize(c, locp, &edge);
+ if (op_is64bit) {
+ op2_m = gen_rvalue_extend(c, locp, &op2_m);
+ }
+ op1_m = rvalue_materialize(c, locp, &op1_m);
+ op2_m = rvalue_materialize(c, locp, &op2_m);
+
+ OUT(c, locp, "tcg_gen_extract_", bit_suffix, "(",
+ &tmp, ", ", &op1_m, ", ", offset, ", 1);\n");
+ OUT(c, locp, "tcg_gen_sub_", bit_suffix, "(",
+ &tmp, ", ", &zero, ", ", &tmp, ");\n");
+ OUT(c, locp, "tcg_gen_movcond_i", &bit_width);
+ OUT(c, locp, "(TCG_COND_GEU, ", res, ", ", &op2_m, ", ", &edge);
+ OUT(c, locp, ", ", &tmp, ", ", res, ");\n");
+ gen_rvalue_free(c, locp, &edge);
+ gen_rvalue_free(c, locp, &tmp);
+ }
+ gen_rvalue_free(c, locp, &op1_m);
+ gen_rvalue_free(c, locp, &op2_m);
+}
+
+static void gen_lsr_op(Context *c, YYLTYPE *locp, unsigned bit_width,
+ bool op_is64bit, const char *bit_suffix,
+ HexValue *res, enum OpTypes op_types,
+ HexValue *op1, HexValue *op2)
+{
+ HexValue op1_m = *op1;
+ HexValue op2_m = *op2;
+ switch (op_types) {
+ case IMM_IMM: {
+ HexSignedness signedness = bin_op_signedness(c, locp,
+ op1->signedness,
+ op2->signedness);
+ gen_c_int_type(c, locp, bit_width, signedness);
+ OUT(c, locp, ", ",
+ res, " = ", op1, " >> ", op2, ";\n");
+ } break;
+ case REG_IMM:
+ OUT(c, locp, "if (", op2, " >= ", &bit_width, ") {\n");
+ OUT(c, locp, "tcg_gen_movi_", bit_suffix, "(", res, ", 0);\n");
+ OUT(c, locp, "} else {\n");
+ OUT(c, locp, "tcg_gen_shri_", bit_suffix,
+ "(", res, ", ", op1, ", ", op2, ");\n");
+ OUT(c, locp, "}\n");
+ break;
+ case IMM_REG:
+ op1_m = rvalue_materialize(c, locp, &op1_m);
+ /* Fallthrough */
+ case REG_REG:
+ OUT(c, locp, "tcg_gen_shr_", bit_suffix,
+ "(", res, ", ", &op1_m, ", ", op2, ");\n");
+ break;
+ }
+ if (op_types == IMM_REG || op_types == REG_REG) {
+ /* Handle right shift by values >= bit_width */
+ HexValue zero = gen_constant(c, locp, "0", bit_width, UNSIGNED);
+ HexValue edge = gen_imm_value(c, locp, bit_width, bit_width, UNSIGNED);
+ edge = rvalue_materialize(c, locp, &edge);
+ if (op_is64bit) {
+ op2_m = gen_rvalue_extend(c, locp, &op2_m);
+ }
+ op1_m = rvalue_materialize(c, locp, &op1_m);
+ op2_m = rvalue_materialize(c, locp, &op2_m);
+ OUT(c, locp, "tcg_gen_movcond_i", &bit_width);
+ OUT(c, locp, "(TCG_COND_GEU, ", res, ", ", &op2_m, ", ", &edge);
+ OUT(c, locp, ", ", &zero, ", ", res, ");\n");
+ gen_rvalue_free(c, locp, &edge);
+ }
+ gen_rvalue_free(c, locp, &op1_m);
+ gen_rvalue_free(c, locp, &op2_m);
+}
+
+/*
+ * Note: This implementation of logical `and` does not mirror that in C.
+ * We do not short-circuit logical expressions!
+ */
+static void gen_andl_op(Context *c, YYLTYPE *locp, unsigned bit_width,
+ const char *bit_suffix, HexValue *res,
+ enum OpTypes op_types, HexValue *op1,
+ HexValue *op2)
+{
+ HexValue tmp1, tmp2;
+ HexValue zero = gen_constant(c, locp, "0", 32, UNSIGNED);
+ memset(&tmp1, 0, sizeof(HexValue));
+ memset(&tmp2, 0, sizeof(HexValue));
+ switch (op_types) {
+ case IMM_IMM: {
+ HexSignedness signedness = bin_op_signedness(c, locp,
+ op1->signedness,
+ op2->signedness);
+ gen_c_int_type(c, locp, bit_width, signedness);
+ OUT(c, locp, " ",
+ res, " = ", op1, " && ", op2, ";\n");
+ } break;
+ case IMM_REG:
+ tmp2 = gen_bin_cmp(c, locp, TCG_COND_NE, op2, &zero);
+ OUT(c, locp, "tcg_gen_andi_", bit_suffix,
+ "(", res, ", ", op1, " != 0 , ", &tmp2, ");\n");
+ gen_rvalue_free(c, locp, &tmp2);
+ break;
+ case REG_IMM:
+ tmp1 = gen_bin_cmp(c, locp, TCG_COND_NE, op1, &zero);
+ OUT(c, locp, "tcg_gen_andi_", bit_suffix,
+ "(", res, ", ", &tmp1, ", ", op2, " != 0);\n");
+ gen_rvalue_free(c, locp, &tmp1);
+ break;
+ case REG_REG:
+ tmp1 = gen_bin_cmp(c, locp, TCG_COND_NE, op1, &zero);
+ tmp2 = gen_bin_cmp(c, locp, TCG_COND_NE, op2, &zero);
+ OUT(c, locp, "tcg_gen_and_", bit_suffix,
+ "(", res, ", ", &tmp1, ", ", &tmp2, ");\n");
+ gen_rvalue_free_manual(c, locp, &zero);
+ gen_rvalue_free(c, locp, &tmp1);
+ gen_rvalue_free(c, locp, &tmp2);
+ break;
+ }
+}
+
+static void gen_minmax_op(Context *c, YYLTYPE *locp, unsigned bit_width,
+ HexValue *res, enum OpTypes op_types,
+ HexValue *op1, HexValue *op2, bool minmax)
+{
+ const char *mm;
+ HexValue op1_m = *op1;
+ HexValue op2_m = *op2;
+ bool is_unsigned;
+
+ assert_signedness(c, locp, res->signedness);
+ is_unsigned = res->signedness == UNSIGNED;
+
+ if (minmax) {
+ /* Max */
+ mm = is_unsigned ? "tcg_gen_umax" : "tcg_gen_smax";
+ } else {
+ /* Min */
+ mm = is_unsigned ? "tcg_gen_umin" : "tcg_gen_smin";
+ }
+ switch (op_types) {
+ case IMM_IMM: {
+ const char *s = minmax ? " <= " : " >= ";
+ HexSignedness signedness = bin_op_signedness(c, locp,
+ op1->signedness,
+ op2->signedness);
+ gen_c_int_type(c, locp, bit_width, signedness);
+ OUT(c, locp, " ", res, " = (", op1, s);
+ OUT(c, locp, op2, ") ? ", op1, " : ", op2, ";\n");
+ } break;
+ case IMM_REG:
+ op1_m.bit_width = bit_width;
+ op1_m = rvalue_materialize(c, locp, &op1_m);
+ OUT(c, locp, mm, "_i", &bit_width, "(");
+ OUT(c, locp, res, ", ", &op1_m, ", ", op2, ");\n");
+ break;
+ case REG_IMM:
+ op2_m.bit_width = bit_width;
+ op2_m = rvalue_materialize(c, locp, &op2_m);
+ /* Fallthrough */
+ case REG_REG:
+ OUT(c, locp, mm, "_i", &bit_width, "(");
+ OUT(c, locp, res, ", ", op1, ", ", &op2_m, ");\n");
+ break;
+ }
+ gen_rvalue_free(c, locp, &op1_m);
+ gen_rvalue_free(c, locp, &op2_m);
+}
+
+static void gen_mod_op(Context *c, YYLTYPE *locp, HexValue *res,
+ enum OpTypes op_types, HexValue *op1, HexValue *op2)
+{
+ switch (op_types) {
+ case IMM_IMM: {
+ HexSignedness signedness = bin_op_signedness(c, locp,
+ op1->signedness,
+ op2->signedness);
+ gen_c_int_type(c, locp, res->bit_width, signedness);
+ OUT(c, locp, " ", res, " = ", op1, " % ", op2, ";\n");
+ } break;
+ case IMM_REG:
+ case REG_IMM:
+ case REG_REG:
+ OUT(c, locp, "gen_helper_mod(",
+ res, ", ", op1, ", ", op2, ");\n");
+ break;
+ }
+ gen_rvalue_free(c, locp, op1);
+ gen_rvalue_free(c, locp, op2);
+}
+
+/* Code generation functions */
+HexValue gen_bin_op(Context *c,
+ YYLTYPE *locp,
+ OpType type,
+ HexValue *op1,
+ HexValue *op2)
+{
+ /* Replicate operands to avoid side effects */
+ HexValue op1_m = *op1;
+ HexValue op2_m = *op2;
+ enum OpTypes op_types;
+ bool op_is64bit;
+ HexSignedness signedness;
+ unsigned bit_width;
+ const char *bit_suffix;
+ HexValue res;
+
+ memset(&res, 0, sizeof(HexValue));
+
+ /*
+ * If the operands are VARID's we need to look up the
+ * type information.
+ */
+ if (op1_m.type == VARID) {
+ find_variable(c, locp, &op1_m, &op1_m);
+ }
+ if (op2_m.type == VARID) {
+ find_variable(c, locp, &op2_m, &op2_m);
+ }
+
+ op_types = (op1_m.type != IMMEDIATE) << 1
+ | (op2_m.type != IMMEDIATE);
+ op_is64bit = op1_m.bit_width == 64 || op2_m.bit_width == 64;
+ /* Shift greater than 32 are 64 bits wide */
+
+ if (type == ASL_OP && op2_m.type == IMMEDIATE &&
+ op2_m.imm.type == VALUE && op2_m.imm.value >= 32) {
+ op_is64bit = true;
+ }
+
+ bit_width = (op_is64bit) ? 64 : 32;
+ bit_suffix = op_is64bit ? "i64" : "i32";
+
+ /* Extend to 64-bits, if required */
+ if (op_is64bit) {
+ op1_m = gen_rvalue_extend(c, locp, &op1_m);
+ op2_m = gen_rvalue_extend(c, locp, &op2_m);
+ }
+
+ signedness = bin_op_signedness(c, locp, op1_m.signedness, op2_m.signedness);
+ if (op_types != IMM_IMM) {
+ res = gen_tmp(c, locp, bit_width, signedness);
+ } else {
+ res = gen_imm_qemu_tmp(c, locp, bit_width, signedness);
+ }
+
+ switch (type) {
+ case ADD_OP:
+ gen_simple_op(c, locp, bit_width, bit_suffix, &res,
+ op_types, &op1_m, &op2_m,
+ " + ",
+ "tcg_gen_addi_",
+ "tcg_gen_addi_",
+ "tcg_gen_add_");
+ break;
+ case SUB_OP:
+ gen_sub_op(c, locp, bit_width, bit_suffix, &res, op_types,
+ &op1_m, &op2_m);
+ break;
+ case MUL_OP:
+ gen_simple_op(c, locp, bit_width, bit_suffix, &res,
+ op_types, &op1_m, &op2_m,
+ " * ",
+ "tcg_gen_muli_",
+ "tcg_gen_muli_",
+ "tcg_gen_mul_");
+ break;
+ case ASL_OP:
+ gen_asl_op(c, locp, bit_width, op_is64bit, bit_suffix, &res, op_types,
+ &op1_m, &op2_m);
+ break;
+ case ASR_OP:
+ gen_asr_op(c, locp, bit_width, op_is64bit, bit_suffix, &res, op_types,
+ &op1_m, &op2_m);
+ break;
+ case LSR_OP:
+ gen_lsr_op(c, locp, bit_width, op_is64bit, bit_suffix, &res, op_types,
+ &op1_m, &op2_m);
+ break;
+ case ANDB_OP:
+ gen_simple_op(c, locp, bit_width, bit_suffix, &res,
+ op_types, &op1_m, &op2_m,
+ " & ",
+ "tcg_gen_andi_",
+ "tcg_gen_andi_",
+ "tcg_gen_and_");
+ break;
+ case ORB_OP:
+ gen_simple_op(c, locp, bit_width, bit_suffix, &res,
+ op_types, &op1_m, &op2_m,
+ " | ",
+ "tcg_gen_ori_",
+ "tcg_gen_ori_",
+ "tcg_gen_or_");
+ break;
+ case XORB_OP:
+ gen_simple_op(c, locp, bit_width, bit_suffix, &res,
+ op_types, &op1_m, &op2_m,
+ " ^ ",
+ "tcg_gen_xori_",
+ "tcg_gen_xori_",
+ "tcg_gen_xor_");
+ break;
+ case ANDL_OP:
+ gen_andl_op(c, locp, bit_width, bit_suffix, &res, op_types, &op1_m,
+ &op2_m);
+ break;
+ case MINI_OP:
+ gen_minmax_op(c, locp, bit_width, &res, op_types, &op1_m, &op2_m,
+ false);
+ break;
+ case MAXI_OP:
+ gen_minmax_op(c, locp, bit_width, &res, op_types, &op1_m, &op2_m, true);
+ break;
+ case MOD_OP:
+ gen_mod_op(c, locp, &res, op_types, &op1_m, &op2_m);
+ break;
+ }
+ return res;
+}
+
+HexValue gen_cast_op(Context *c,
+ YYLTYPE *locp,
+ HexValue *src,
+ unsigned target_width,
+ HexSignedness signedness)
+{
+ assert_signedness(c, locp, src->signedness);
+ if (src->bit_width == target_width) {
+ return *src;
+ } else if (src->type == IMMEDIATE) {
+ HexValue res = *src;
+ res.bit_width = target_width;
+ res.signedness = signedness;
+ return res;
+ } else {
+ HexValue res = gen_tmp(c, locp, target_width, signedness);
+ /* Truncate */
+ if (src->bit_width > target_width) {
+ OUT(c, locp, "tcg_gen_trunc_i64_tl(", &res, ", ", src, ");\n");
+ } else {
+ assert_signedness(c, locp, src->signedness);
+ if (src->signedness == UNSIGNED) {
+ /* Extend unsigned */
+ OUT(c, locp, "tcg_gen_extu_i32_i64(",
+ &res, ", ", src, ");\n");
+ } else {
+ /* Extend signed */
+ OUT(c, locp, "tcg_gen_ext_i32_i64(",
+ &res, ", ", src, ");\n");
+ }
+ }
+ gen_rvalue_free(c, locp, src);
+ return res;
+ }
+}
+
+
+/*
+ * Implements an extension when the `src_width` is an immediate.
+ * If the `value` to extend is also an immediate we use `extract/sextract`
+ * from QEMU `bitops.h`. If `value` is a TCGv then we rely on
+ * `tcg_gen_extract/tcg_gen_sextract`.
+ */
+static HexValue gen_extend_imm_width_op(Context *c,
+ YYLTYPE *locp,
+ HexValue *src_width,
+ unsigned dst_width,
+ HexValue *value,
+ HexSignedness signedness)
+{
+ /*
+ * If the source width is not an immediate value, we need to guard
+ * our extend op with if statements to handle the case where
+ * `src_width_m` is 0.
+ */
+ const char *sign_prefix;
+ bool need_guarding;
+
+ assert_signedness(c, locp, signedness);
+ assert(dst_width == 64 || dst_width == 32);
+ assert(src_width->type == IMMEDIATE);
+
+ sign_prefix = (signedness == UNSIGNED) ? "" : "s";
+ need_guarding = (src_width->imm.type != VALUE);
+
+ if (src_width->imm.type == VALUE &&
+ src_width->imm.value == 0) {
+ /*
+ * We can bail out early if the source width is known to be zero
+ * at translation time.
+ */
+ return gen_imm_value(c, locp, 0, dst_width, signedness);
+ }
+
+ if (value->type == IMMEDIATE) {
+ /*
+ * If both the value and source width are immediates,
+ * we can perform the extension at translation time
+ * using QEMUs bitops.
+ */
+ HexValue res = gen_imm_qemu_tmp(c, locp, dst_width, signedness);
+ gen_c_int_type(c, locp, dst_width, signedness);
+ OUT(c, locp, " ", &res, " = 0;\n");
+ if (need_guarding) {
+ OUT(c, locp, "if (", src_width, " != 0) {\n");
+ }
+ OUT(c, locp, &res, " = ", sign_prefix, "extract", &dst_width);
+ OUT(c, locp, "(", value, ", 0, ", src_width, ");\n");
+ if (need_guarding) {
+ OUT(c, locp, "}\n");
+ }
+
+ gen_rvalue_free(c, locp, value);
+ return res;
+ } else {
+ /*
+ * If the source width is an immediate and the value to
+ * extend is a TCGv, then use tcg_gen_extract/tcg_gen_sextract
+ */
+ HexValue res = gen_tmp(c, locp, dst_width, signedness);
+
+ /*
+ * If the width is an immediate value we know it is non-zero
+ * at this point, otherwise we need an if-statement
+ */
+ if (need_guarding) {
+ OUT(c, locp, "if (", src_width, " != 0) {\n");
+ }
+ OUT(c, locp, "tcg_gen_", sign_prefix, "extract_i", &dst_width);
+ OUT(c, locp, "(", &res, ", ", value, ", 0, ", src_width,
+ ");\n");
+ if (need_guarding) {
+ OUT(c, locp, "} else {\n");
+ OUT(c, locp, "tcg_gen_movi_i", &dst_width, "(", &res,
+ ", 0);\n");
+ OUT(c, locp, "}\n");
+ }
+
+ gen_rvalue_free(c, locp, value);
+ return res;
+ }
+}
+
+/*
+ * Implements an extension when the `src_width` is given by
+ * a TCGv. Here we need to reimplement the behaviour of
+ * `tcg_gen_extract` and the like using shifts and masks.
+ */
+static HexValue gen_extend_tcg_width_op(Context *c,
+ YYLTYPE *locp,
+ HexValue *src_width,
+ unsigned dst_width,
+ HexValue *value,
+ HexSignedness signedness)
+{
+ HexValue src_width_m = rvalue_materialize(c, locp, src_width);
+ HexValue zero = gen_constant(c, locp, "0", dst_width, UNSIGNED);
+ HexValue shift = gen_tmp(c, locp, dst_width, UNSIGNED);
+ HexValue res;
+
+ assert_signedness(c, locp, signedness);
+ assert(dst_width == 64 || dst_width == 32);
+ assert(src_width->type != IMMEDIATE);
+
+ res = gen_tmp(c, locp, dst_width, signedness);
+
+ OUT(c, locp, "tcg_gen_subfi_i", &dst_width);
+ OUT(c, locp, "(", &shift, ", ", &dst_width, ", ", &src_width_m, ");\n");
+ if (signedness == UNSIGNED) {
+ const char *mask_str = (dst_width == 32)
+ ? "0xffffffff"
+ : "0xffffffffffffffff";
+ HexValue mask = gen_tmp_value(c, locp, mask_str,
+ dst_width, UNSIGNED);
+ OUT(c, locp, "tcg_gen_shr_i", &dst_width, "(",
+ &mask, ", ", &mask, ", ", &shift, ");\n");
+ OUT(c, locp, "tcg_gen_and_i", &dst_width, "(",
+ &res, ", ", value, ", ", &mask, ");\n");
+ gen_rvalue_free(c, locp, &mask);
+ } else {
+ OUT(c, locp, "tcg_gen_shl_i", &dst_width, "(",
+ &res, ", ", value, ", ", &shift, ");\n");
+ OUT(c, locp, "tcg_gen_sar_i", &dst_width, "(",
+ &res, ", ", &res, ", ", &shift, ");\n");
+ }
+ OUT(c, locp, "tcg_gen_movcond_i", &dst_width, "(TCG_COND_EQ, ", &res,
+ ", ");
+ OUT(c, locp, &src_width_m, ", ", &zero, ", ", &zero, ", ", &res,
+ ");\n");
+
+ gen_rvalue_free(c, locp, &src_width_m);
+ gen_rvalue_free(c, locp, value);
+ gen_rvalue_free(c, locp, &shift);
+
+ return res;
+}
+
+HexValue gen_extend_op(Context *c,
+ YYLTYPE *locp,
+ HexValue *src_width,
+ unsigned dst_width,
+ HexValue *value,
+ HexSignedness signedness)
+{
+ unsigned bit_width = (dst_width = 64) ? 64 : 32;
+ HexValue value_m = *value;
+ HexValue src_width_m = *src_width;
+
+ assert_signedness(c, locp, signedness);
+
+ if (value_m.bit_width < bit_width) {
+ value_m = gen_rvalue_extend(c, locp, &value_m);
+ } else if (value_m.bit_width > bit_width) {
+ value_m = gen_rvalue_truncate(c, locp, &value_m);
+ }
+
+ if (src_width_m.bit_width < bit_width) {
+ src_width_m = gen_rvalue_extend(c, locp, &src_width_m);
+ } else if (src_width_m.bit_width > bit_width) {
+ src_width_m = gen_rvalue_truncate(c, locp, &src_width_m);
+ }
+
+ if (src_width_m.type == IMMEDIATE) {
+ return gen_extend_imm_width_op(c, locp, &src_width_m, bit_width,
+ &value_m, signedness);
+ } else {
+ return gen_extend_tcg_width_op(c, locp, &src_width_m, bit_width,
+ &value_m, signedness);
+ }
+}
+
+/*
+ * Implements `rdeposit` for the special case where `width` is
+ * of immediate type. Here we rely on `tcg_gen_deposit_*` to
+ * perform the deposit.
+ */
+static void gen_rdeposit_imm_width_op(Context *c,
+ YYLTYPE *locp,
+ HexValue *dst,
+ HexValue *value,
+ HexValue *begin,
+ HexValue *width)
+{
+ /*
+ * If the width of the deposit op is known at translatin time
+ * we can rely on tcg_gen_deposit
+ */
+
+ /* If the width is known to be 0, just no-op */
+ if (width->imm.type == VALUE && width->imm.value == 0) {
+ return;
+ }
+
+ /*
+ * If the width is an immediate value we know it is non-zero
+ * at this point, otherwise we need an if-statement
+ */
+ if (width->imm.type != VALUE) {
+ OUT(c, locp, "if (", width, " > 0) {\n");
+ }
+ OUT(c, locp, "tcg_gen_deposit_i", &dst->bit_width, "(", dst, ", ");
+ OUT(c, locp, dst, ", ", value, ", ", &begin->imm.value, ", ",
+ width, ");\n");
+ if (width->imm.type != VALUE) {
+ OUT(c, locp, "}\n");
+ }
+}
+
+/*
+ * Implements `rdeposit` for the special case where `width`
+ * is of TCGv type. In this case we need to reimplement the behaviour
+ * of `tcg_gen_deposit*` using binary operations and masks/shifts.
+ */
+static void gen_rdeposit_tcg_width_op(Context *c,
+ YYLTYPE *locp,
+ HexValue *dst,
+ HexValue *value,
+ HexValue *begin,
+ HexValue *width)
+{
+ /*
+ * Otherwise if the width is not known, we fallback on reimplementing
+ * desposit in TCG.
+ */
+ HexValue begin_m = *begin;
+ HexValue value_m = *value;
+ HexValue width_orig = *width;
+ HexValue width_m = width_orig;
+ const char *mask_str = (dst->bit_width == 32)
+ ? "0xffffffffUL"
+ : "0xffffffffffffffffUL";
+ HexValue mask = gen_constant(c, locp, mask_str, dst->bit_width,
+ UNSIGNED);
+ const char *dst_width_str = (dst->bit_width == 32) ? "32" : "64";
+ HexValue k64 = gen_constant(c, locp, dst_width_str, dst->bit_width,
+ UNSIGNED);
+ HexValue res;
+ HexValue zero;
+
+ width_orig.is_manual = true;
+
+ if (value_m.bit_width < dst->bit_width) {
+ value_m = gen_rvalue_extend(c, locp, &value_m);
+ } else if (value_m.bit_width > dst->bit_width) {
+ value_m = gen_rvalue_truncate(c, locp, &value_m);
+ }
+
+ if (begin_m.bit_width < dst->bit_width) {
+ begin_m = gen_rvalue_extend(c, locp, &begin_m);
+ } else if (begin_m.bit_width > dst->bit_width) {
+ begin_m = gen_rvalue_truncate(c, locp, &begin_m);
+ }
+ if (width_m.bit_width < dst->bit_width) {
+ width_m = gen_rvalue_extend(c, locp, &width_orig);
+ } else if (width_m.bit_width > dst->bit_width) {
+ width_m = gen_rvalue_truncate(c, locp, &width_orig);
+ }
+ width_m = rvalue_materialize(c, locp, &width_m);
+
+ /*
+ * mask = 0xffffffffffffffff >> (64 - width)
+ * mask = mask << begin
+ * value = (value << begin) & mask
+ * res = dst & ~mask
+ * res = res | value
+ * dst = (width != 0) ? res : dst
+ */
+ k64 = gen_bin_op(c, locp, SUB_OP, &k64, &width_m);
+ mask = gen_bin_op(c, locp, LSR_OP, &mask, &k64);
+ begin_m.is_manual = true;
+ mask = gen_bin_op(c, locp, ASL_OP, &mask, &begin_m);
+ mask.is_manual = true;
+ value_m = gen_bin_op(c, locp, ASL_OP, &value_m, &begin_m);
+ value_m = gen_bin_op(c, locp, ANDB_OP, &value_m, &mask);
+
+ OUT(c, locp, "tcg_gen_not_i", &dst->bit_width, "(", &mask, ", ",
+ &mask, ");\n");
+ mask.is_manual = false;
+ res = gen_bin_op(c, locp, ANDB_OP, dst, &mask);
+ res = gen_bin_op(c, locp, ORB_OP, &res, &value_m);
+
+ if (dst->bit_width != res.bit_width) {
+ res = gen_rvalue_truncate(c, locp, &res);
+ }
+
+ /* If the width is zero, then return the identity dst = dst */
+ zero = gen_constant(c, locp, "0", res.bit_width, UNSIGNED);
+ OUT(c, locp, "tcg_gen_movcond_i", &res.bit_width, "(TCG_COND_NE, ",
+ dst);
+ OUT(c, locp, ", ", &width_orig, ", ", &zero, ", ", &res, ", ", dst,
+ ");\n");
+
+ gen_rvalue_free(c, locp, width);
+ gen_rvalue_free(c, locp, &res);
+}
+
+
+void gen_rdeposit_op(Context *c,
+ YYLTYPE *locp,
+ HexValue *dst,
+ HexValue *value,
+ HexValue *begin,
+ HexValue *width)
+{
+ HexValue dst_m = *dst;
+ dst_m.is_manual = true;
+
+ assert(dst->bit_width >= value->bit_width);
+ assert(begin->type == IMMEDIATE && begin->imm.type == VALUE);
+ assert(dst->type == REGISTER_ARG);
+
+ if (width->type == IMMEDIATE) {
+ gen_rdeposit_imm_width_op(c, locp, &dst_m, value, begin, width);
+ } else {
+ gen_rdeposit_tcg_width_op(c, locp, &dst_m, value, begin, width);
+ }
+}
+
+void gen_deposit_op(Context *c,
+ YYLTYPE *locp,
+ HexValue *dst,
+ HexValue *value,
+ HexValue *index,
+ HexCast *cast)
+{
+ HexValue value_m = *value;
+ unsigned bit_width = (dst->bit_width == 64) ? 64 : 32;
+ unsigned width = cast->bit_width;
+
+ yyassert(c, locp, index->type == IMMEDIATE,
+ "Deposit index must be immediate!\n");
+
+ /*
+ * Using tcg_gen_deposit_i**(dst, dst, ...) requires dst to be
+ * initialized.
+ */
+ gen_inst_init_args(c, locp);
+
+ /* If the destination value is 32, truncate the value, otherwise extend */
+ if (dst->bit_width != value->bit_width) {
+ if (bit_width == 32) {
+ value_m = gen_rvalue_truncate(c, locp, &value_m);
+ } else {
+ value_m = gen_rvalue_extend(c, locp, &value_m);
+ }
+ }
+ value_m = rvalue_materialize(c, locp, &value_m);
+ OUT(c, locp, "tcg_gen_deposit_i", &bit_width, "(", dst, ", ", dst, ", ");
+ OUT(c, locp, &value_m, ", ", index, " * ", &width, ", ", &width, ");\n");
+ gen_rvalue_free(c, locp, index);
+ gen_rvalue_free(c, locp, &value_m);
+}
+
+HexValue gen_rextract_op(Context *c,
+ YYLTYPE *locp,
+ HexValue *src,
+ unsigned begin,
+ unsigned width)
+{
+ unsigned bit_width = (src->bit_width == 64) ? 64 : 32;
+ HexValue res = gen_tmp(c, locp, bit_width, UNSIGNED);
+ OUT(c, locp, "tcg_gen_extract_i", &bit_width, "(", &res);
+ OUT(c, locp, ", ", src, ", ", &begin, ", ", &width, ");\n");
+ gen_rvalue_free(c, locp, src);
+ return res;
+}
+
+HexValue gen_extract_op(Context *c,
+ YYLTYPE *locp,
+ HexValue *src,
+ HexValue *index,
+ HexExtract *extract)
+{
+ unsigned bit_width = (src->bit_width == 64) ? 64 : 32;
+ unsigned width = extract->bit_width;
+ const char *sign_prefix;
+ HexValue res;
+
+ yyassert(c, locp, index->type == IMMEDIATE,
+ "Extract index must be immediate!\n");
+ assert_signedness(c, locp, extract->signedness);
+
+ sign_prefix = (extract->signedness == UNSIGNED) ? "" : "s";
+ res = gen_tmp(c, locp, bit_width, extract->signedness);
+
+ OUT(c, locp, "tcg_gen_", sign_prefix, "extract_i", &bit_width,
+ "(", &res, ", ", src);
+ OUT(c, locp, ", ", index, " * ", &width, ", ", &width, ");\n");
+
+ /* Some extract operations have bit_width != storage_bit_width */
+ if (extract->storage_bit_width > bit_width) {
+ HexValue tmp = gen_tmp(c, locp, extract->storage_bit_width,
+ extract->signedness);
+ if (extract->signedness == UNSIGNED) {
+ /* Extend unsigned */
+ OUT(c, locp, "tcg_gen_extu_i32_i64(",
+ &tmp, ", ", &res, ");\n");
+ } else {
+ /* Extend signed */
+ OUT(c, locp, "tcg_gen_ext_i32_i64(",
+ &tmp, ", ", &res, ");\n");
+ }
+ gen_rvalue_free(c, locp, &res);
+ res = tmp;
+ }
+
+ gen_rvalue_free(c, locp, src);
+ gen_rvalue_free(c, locp, index);
+ return res;
+}
+
+HexValue gen_read_reg(Context *c, YYLTYPE *locp, HexValue *reg)
+{
+ yyassert(c, locp, reg->type == REGISTER_ARG || reg->type == REGISTER,
+ "reg must be a register arg or register!");
+ if (reg->type == REGISTER) {
+ HexValue tmp = gen_tmp(c, locp, 32, reg->signedness);
+ OUT(c, locp, "gen_read_reg(", &tmp, ", ", ®->reg.id, ");\n");
+ gen_rvalue_free(c, locp, reg);
+ return tmp;
+ }
+ return *reg;
+}
+
+void gen_write_reg(Context *c, YYLTYPE *locp, HexValue *reg, HexValue *value)
+{
+ HexValue value_m = *value;
+ yyassert(c, locp, reg->type == REGISTER, "reg must be a register!");
+ value_m = gen_rvalue_truncate(c, locp, &value_m);
+ value_m = rvalue_materialize(c, locp, &value_m);
+ OUT(c,
+ locp,
+ "gen_log_reg_write(", ®->reg.id, ", ",
+ &value_m, ");\n");
+ OUT(c,
+ locp,
+ "ctx_log_reg_write(ctx, ", ®->reg.id,
+ ");\n");
+ gen_rvalue_free(c, locp, reg);
+ gen_rvalue_free(c, locp, &value_m);
+}
+
+void gen_assign(Context *c,
+ YYLTYPE *locp,
+ HexValue *dst,
+ HexValue *value)
+{
+ HexValue value_m = *value;
+ unsigned bit_width;
+
+ yyassert(c, locp,
+ !is_inside_ternary(c) ||
+ !(dst->type == REGISTER),
+ "register assign in ternary");
+
+ if (dst->type == REGISTER) {
+ gen_write_reg(c, locp, dst, &value_m);
+ return;
+ }
+
+ if (dst->type == VARID) {
+ find_variable(c, locp, dst, dst);
+ }
+ bit_width = dst->bit_width == 64 ? 64 : 32;
+
+ if (bit_width != value_m.bit_width) {
+ if (bit_width == 64) {
+ value_m = gen_rvalue_extend(c, locp, &value_m);
+ } else {
+ value_m = gen_rvalue_truncate(c, locp, &value_m);
+ }
+ }
+ if (is_inside_ternary(c)) {
+ HexValue zero = gen_constant(c, locp, "0", bit_width, UNSIGNED);
+ HexValue cond = get_ternary_cond(c, locp);
+ value_m = rvalue_materialize(c, locp, &value_m);
+ if (cond.bit_width != bit_width) {
+ if (cond.bit_width == 64) {
+ cond = gen_rvalue_truncate(c, locp, &cond);
+ } else {
+ cond = gen_rvalue_extend(c, locp, &cond);
+ }
+ }
+ OUT(c, locp, "tcg_gen_movcond_i", &bit_width, "(TCG_COND_NE, ", dst);
+ OUT(c, locp, ", ", &cond, ", ", &zero, ", ");
+ OUT(c, locp, &value_m, ", ", dst, ");\n");
+ gen_rvalue_free(c, locp, &cond);
+ } else {
+ if (value_m.type == IMMEDIATE) {
+ OUT(c, locp, "tcg_gen_movi_i", &bit_width,
+ "(", dst, ", ", &value_m, ");\n");
+ } else {
+ OUT(c, locp, "tcg_gen_mov_i", &bit_width,
+ "(", dst, ", ", &value_m, ");\n");
+ }
+ }
+ gen_rvalue_free(c, locp, &value_m);
+}
+
+HexValue gen_convround(Context *c,
+ YYLTYPE *locp,
+ HexValue *src)
+{
+ HexValue src_m = *src;
+ unsigned bit_width = src_m.bit_width;
+ const char *size = (bit_width == 32) ? "32" : "64";
+ HexValue res = gen_tmp(c, locp, bit_width, src->signedness);
+ HexValue mask = gen_constant(c, locp, "0x3", bit_width, UNSIGNED);
+ HexValue one = gen_constant(c, locp, "1", bit_width, UNSIGNED);
+ HexValue and;
+ HexValue src_p1;
+
+ src_m.is_manual = true;
+
+ and = gen_bin_op(c, locp, ANDB_OP, &src_m, &mask);
+ src_p1 = gen_bin_op(c, locp, ADD_OP, &src_m, &one);
+
+ OUT(c, locp, "tcg_gen_movcond_i", size, "(TCG_COND_EQ, ", &res);
+ OUT(c, locp, ", ", &and, ", ", &mask, ", ");
+ OUT(c, locp, &src_p1, ", ", &src_m, ");\n");
+
+ /* Free src but use the original `is_manual` value */
+ gen_rvalue_free(c, locp, src);
+
+ /* Free the rest of the values */
+ gen_rvalue_free(c, locp, &src_p1);
+
+ return res;
+}
+
+static HexValue gen_convround_n_b(Context *c,
+ YYLTYPE *locp,
+ HexValue *a,
+ HexValue *n)
+{
+ HexValue one = gen_constant(c, locp, "1", 32, UNSIGNED);
+ HexValue res = gen_tmp(c, locp, 64, UNSIGNED);
+ HexValue tmp = gen_tmp(c, locp, 32, UNSIGNED);
+ HexValue tmp_64 = gen_tmp(c, locp, 64, UNSIGNED);
+
+ assert(n->type != IMMEDIATE);
+ OUT(c, locp, "tcg_gen_ext_i32_i64(", &res, ", ", a, ");\n");
+ OUT(c, locp, "tcg_gen_shl_i32(", &tmp);
+ OUT(c, locp, ", ", &one, ", ", n, ");\n");
+ OUT(c, locp, "tcg_gen_and_i32(", &tmp);
+ OUT(c, locp, ", ", &tmp, ", ", a, ");\n");
+ OUT(c, locp, "tcg_gen_shri_i32(", &tmp);
+ OUT(c, locp, ", ", &tmp, ", 1);\n");
+ OUT(c, locp, "tcg_gen_ext_i32_i64(", &tmp_64, ", ", &tmp, ");\n");
+ OUT(c, locp, "tcg_gen_add_i64(", &res);
+ OUT(c, locp, ", ", &res, ", ", &tmp_64, ");\n");
+
+ gen_rvalue_free(c, locp, &tmp);
+ gen_rvalue_free(c, locp, &tmp_64);
+
+ return res;
+}
+
+static HexValue gen_convround_n_c(Context *c,
+ YYLTYPE *locp,
+ HexValue *a,
+ HexValue *n)
+{
+ HexValue res = gen_tmp(c, locp, 64, UNSIGNED);
+ HexValue one = gen_constant(c, locp, "1", 32, UNSIGNED);
+ HexValue tmp = gen_tmp(c, locp, 32, UNSIGNED);
+ HexValue tmp_64 = gen_tmp(c, locp, 64, UNSIGNED);
+
+ OUT(c, locp, "tcg_gen_ext_i32_i64(", &res, ", ", a, ");\n");
+ OUT(c, locp, "tcg_gen_subi_i32(", &tmp);
+ OUT(c, locp, ", ", n, ", 1);\n");
+ OUT(c, locp, "tcg_gen_shl_i32(", &tmp);
+ OUT(c, locp, ", ", &one, ", ", &tmp, ");\n");
+ OUT(c, locp, "tcg_gen_ext_i32_i64(", &tmp_64, ", ", &tmp, ");\n");
+ OUT(c, locp, "tcg_gen_add_i64(", &res);
+ OUT(c, locp, ", ", &res, ", ", &tmp_64, ");\n");
+
+ gen_rvalue_free(c, locp, &one);
+ gen_rvalue_free(c, locp, &tmp);
+ gen_rvalue_free(c, locp, &tmp_64);
+
+ return res;
+}
+
+HexValue gen_convround_n(Context *c,
+ YYLTYPE *locp,
+ HexValue *src,
+ HexValue *pos)
+{
+ HexValue zero = gen_constant(c, locp, "0", 64, UNSIGNED);
+ HexValue l_32 = gen_constant(c, locp, "1", 32, UNSIGNED);
+ HexValue cond = gen_tmp(c, locp, 32, UNSIGNED);
+ HexValue cond_64 = gen_tmp(c, locp, 64, UNSIGNED);
+ HexValue mask = gen_tmp(c, locp, 32, UNSIGNED);
+ HexValue n_64 = gen_tmp(c, locp, 64, UNSIGNED);
+ HexValue res = gen_tmp(c, locp, 64, UNSIGNED);
+ /* If input is 64 bit cast it to 32 */
+ HexValue src_casted = gen_cast_op(c, locp, src, 32, src->signedness);
+ HexValue pos_casted = gen_cast_op(c, locp, pos, 32, pos->signedness);
+ HexValue r1;
+ HexValue r2;
+ HexValue r3;
+
+ src_casted = rvalue_materialize(c, locp, &src_casted);
+ pos_casted = rvalue_materialize(c, locp, &pos_casted);
+
+ /*
+ * r1, r2, and r3 represent the results of three different branches.
+ * - r1 picked if pos_casted == 0
+ * - r2 picked if (src_casted & ((1 << (pos_casted - 1)) - 1)) == 0),
+ * that is if bits 0, ..., pos_casted-1 are all 0.
+ * - r3 picked otherwise.
+ */
+ r1 = gen_rvalue_extend(c, locp, &src_casted);
+ r2 = gen_convround_n_b(c, locp, &src_casted, &pos_casted);
+ r3 = gen_convround_n_c(c, locp, &src_casted, &pos_casted);
+
+ /*
+ * Calculate the condition
+ * (src_casted & ((1 << (pos_casted - 1)) - 1)) == 0),
+ * which checks if the bits 0,...,pos-1 are all 0.
+ */
+ OUT(c, locp, "tcg_gen_sub_i32(", &mask);
+ OUT(c, locp, ", ", &pos_casted, ", ", &l_32, ");\n");
+ OUT(c, locp, "tcg_gen_shl_i32(", &mask);
+ OUT(c, locp, ", ", &l_32, ", ", &mask, ");\n");
+ OUT(c, locp, "tcg_gen_sub_i32(", &mask);
+ OUT(c, locp, ", ", &mask, ", ", &l_32, ");\n");
+ OUT(c, locp, "tcg_gen_and_i32(", &cond);
+ OUT(c, locp, ", ", &src_casted, ", ", &mask, ");\n");
+ OUT(c, locp, "tcg_gen_extu_i32_i64(", &cond_64, ", ", &cond, ");\n");
+
+ OUT(c, locp, "tcg_gen_ext_i32_i64(", &n_64, ", ", &pos_casted, ");\n");
+
+ /*
+ * if the bits 0, ..., pos_casted-1 are all 0, then pick r2 otherwise,
+ * pick r3.
+ */
+ OUT(c, locp, "tcg_gen_movcond_i64");
+ OUT(c, locp, "(TCG_COND_EQ, ", &res, ", ", &cond_64, ", ", &zero);
+ OUT(c, locp, ", ", &r2, ", ", &r3, ");\n");
+
+ /* Lastly, if the pos_casted == 0, then pick r1 */
+ OUT(c, locp, "tcg_gen_movcond_i64");
+ OUT(c, locp, "(TCG_COND_EQ, ", &res, ", ", &n_64, ", ", &zero);
+ OUT(c, locp, ", ", &r1, ", ", &res, ");\n");
+
+ /* Finally shift back val >>= n */
+ OUT(c, locp, "tcg_gen_shr_i64(", &res);
+ OUT(c, locp, ", ", &res, ", ", &n_64, ");\n");
+
+ gen_rvalue_free(c, locp, &src_casted);
+ gen_rvalue_free(c, locp, &pos_casted);
+
+ gen_rvalue_free(c, locp, &r1);
+ gen_rvalue_free(c, locp, &r2);
+ gen_rvalue_free(c, locp, &r3);
+
+ gen_rvalue_free(c, locp, &cond);
+ gen_rvalue_free(c, locp, &cond_64);
+ gen_rvalue_free(c, locp, &mask);
+ gen_rvalue_free(c, locp, &n_64);
+
+ res = gen_rvalue_truncate(c, locp, &res);
+ return res;
+}
+
+HexValue gen_round(Context *c,
+ YYLTYPE *locp,
+ HexValue *src,
+ HexValue *pos)
+{
+ HexValue zero = gen_constant(c, locp, "0", 64, UNSIGNED);
+ HexValue one = gen_constant(c, locp, "1", 64, UNSIGNED);
+ HexValue res;
+ HexValue n_m1;
+ HexValue shifted;
+ HexValue sum;
+ HexValue src_width;
+ HexValue a;
+ HexValue b;
+
+ assert_signedness(c, locp, src->signedness);
+ yyassert(c, locp, src->bit_width <= 32,
+ "fRNDN not implemented for bit widths > 32!");
+
+ res = gen_tmp(c, locp, 64, src->signedness);
+
+ src_width = gen_imm_value(c, locp, src->bit_width, 32, UNSIGNED);
+ a = gen_extend_op(c, locp, &src_width, 64, src, SIGNED);
+ a = rvalue_materialize(c, locp, &a);
+
+ src_width = gen_imm_value(c, locp, 5, 32, UNSIGNED);
+ b = gen_extend_op(c, locp, &src_width, 64, pos, UNSIGNED);
+ b = rvalue_materialize(c, locp, &b);
+
+ /* Disable auto-free of values used more than once */
+ a.is_manual = true;
+ b.is_manual = true;
+
+ n_m1 = gen_bin_op(c, locp, SUB_OP, &b, &one);
+ shifted = gen_bin_op(c, locp, ASL_OP, &one, &n_m1);
+ sum = gen_bin_op(c, locp, ADD_OP, &shifted, &a);
+
+ OUT(c, locp, "tcg_gen_movcond_i64");
+ OUT(c, locp, "(TCG_COND_EQ, ", &res, ", ", &b, ", ", &zero);
+ OUT(c, locp, ", ", &a, ", ", &sum, ");\n");
+
+ gen_rvalue_free_manual(c, locp, &a);
+ gen_rvalue_free_manual(c, locp, &b);
+ gen_rvalue_free(c, locp, &sum);
+
+ return res;
+}
+
+/* Circular addressing mode with auto-increment */
+void gen_circ_op(Context *c,
+ YYLTYPE *locp,
+ HexValue *addr,
+ HexValue *increment,
+ HexValue *modifier)
+{
+ HexValue cs = gen_tmp(c, locp, 32, UNSIGNED);
+ HexValue increment_m = *increment;
+ increment_m = rvalue_materialize(c, locp, &increment_m);
+ OUT(c, locp, "gen_read_reg(", &cs, ", HEX_REG_CS0 + MuN);\n");
+ OUT(c,
+ locp,
+ "gen_helper_fcircadd(",
+ addr,
+ ", ",
+ addr,
+ ", ",
+ &increment_m,
+ ", ",
+ modifier);
+ OUT(c, locp, ", ", &cs, ");\n");
+ gen_rvalue_free(c, locp, &increment_m);
+ gen_rvalue_free(c, locp, modifier);
+ gen_rvalue_free(c, locp, &cs);
+}
+
+HexValue gen_locnt_op(Context *c, YYLTYPE *locp, HexValue *src)
+{
+ const char *bit_suffix = src->bit_width == 64 ? "64" : "32";
+ HexValue src_m = *src;
+ HexValue res;
+
+ assert_signedness(c, locp, src->signedness);
+ res = gen_tmp(c, locp, src->bit_width == 64 ? 64 : 32, src->signedness);
+ src_m = rvalue_materialize(c, locp, &src_m);
+ OUT(c, locp, "tcg_gen_not_i", bit_suffix, "(",
+ &res, ", ", &src_m, ");\n");
+ OUT(c, locp, "tcg_gen_clzi_i", bit_suffix, "(", &res, ", ", &res, ", ");
+ OUT(c, locp, bit_suffix, ");\n");
+ gen_rvalue_free(c, locp, &src_m);
+ return res;
+}
+
+HexValue gen_ctpop_op(Context *c, YYLTYPE *locp, HexValue *src)
+{
+ const char *bit_suffix = src->bit_width == 64 ? "64" : "32";
+ HexValue src_m = *src;
+ HexValue res;
+ assert_signedness(c, locp, src->signedness);
+ res = gen_tmp(c, locp, src->bit_width == 64 ? 64 : 32, src->signedness);
+ src_m = rvalue_materialize(c, locp, &src_m);
+ OUT(c, locp, "tcg_gen_ctpop_i", bit_suffix,
+ "(", &res, ", ", &src_m, ");\n");
+ gen_rvalue_free(c, locp, &src_m);
+ return res;
+}
+
+HexValue gen_rotl(Context *c, YYLTYPE *locp, HexValue *src, HexValue *width)
+{
+ const char *suffix = src->bit_width == 64 ? "i64" : "i32";
+ HexValue amount = *width;
+ HexValue res;
+ assert_signedness(c, locp, src->signedness);
+ res = gen_tmp(c, locp, src->bit_width, src->signedness);
+ if (amount.bit_width < src->bit_width) {
+ amount = gen_rvalue_extend(c, locp, &amount);
+ } else {
+ amount = gen_rvalue_truncate(c, locp, &amount);
+ }
+ amount = rvalue_materialize(c, locp, &amount);
+ OUT(c, locp, "tcg_gen_rotl_", suffix, "(",
+ &res, ", ", src, ", ", &amount, ");\n");
+ gen_rvalue_free(c, locp, src);
+ gen_rvalue_free(c, locp, &amount);
+
+ return res;
+}
+
+HexValue gen_carry_from_add(Context *c,
+ YYLTYPE *locp,
+ HexValue *op1,
+ HexValue *op2,
+ HexValue *op3)
+{
+ HexValue zero = gen_constant(c, locp, "0", 64, UNSIGNED);
+ HexValue res = gen_tmp(c, locp, 64, UNSIGNED);
+ HexValue cf = gen_tmp(c, locp, 64, UNSIGNED);
+ HexValue op1_m = rvalue_materialize(c, locp, op1);
+ HexValue op2_m = rvalue_materialize(c, locp, op2);
+ HexValue op3_m = rvalue_materialize(c, locp, op3);
+ op3_m = gen_rvalue_extend(c, locp, &op3_m);
+
+ OUT(c, locp, "tcg_gen_add2_i64(", &res, ", ", &cf, ", ", &op1_m, ", ",
+ &zero);
+ OUT(c, locp, ", ", &op3_m, ", ", &zero, ");\n");
+ OUT(c, locp, "tcg_gen_add2_i64(", &res, ", ", &cf, ", ", &res, ", ", &cf);
+ OUT(c, locp, ", ", &op2_m, ", ", &zero, ");\n");
+
+ gen_rvalue_free(c, locp, &op1_m);
+ gen_rvalue_free(c, locp, &op2_m);
+ gen_rvalue_free(c, locp, &op3_m);
+ gen_rvalue_free(c, locp, &res);
+ return cf;
+}
+
+void gen_addsat64(Context *c,
+ YYLTYPE *locp,
+ HexValue *dst,
+ HexValue *op1,
+ HexValue *op2)
+{
+ HexValue op1_m = rvalue_materialize(c, locp, op1);
+ HexValue op2_m = rvalue_materialize(c, locp, op2);
+ OUT(c, locp, "gen_add_sat_i64(", dst, ", ", &op1_m, ", ", &op2_m, ");\n");
+}
+
+void gen_inst(Context *c, GString *iname)
+{
+ c->total_insn++;
+ c->inst.name = iname;
+ c->inst.allocated = g_array_new(FALSE, FALSE, sizeof(Var));
+ c->inst.init_list = g_array_new(FALSE, FALSE, sizeof(HexValue));
+ c->inst.strings = g_array_new(FALSE, FALSE, sizeof(GString *));
+ EMIT_SIG(c, "void emit_%s(DisasContext *ctx, Insn *insn, Packet *pkt",
+ c->inst.name->str);
+}
+
+
+/*
+ * Initialize declared but uninitialized registers, but only for
+ * non-conditional instructions
+ */
+void gen_inst_init_args(Context *c, YYLTYPE *locp)
+{
+ if (!c->inst.init_list) {
+ return;
+ }
+
+ for (unsigned i = 0; i < c->inst.init_list->len; i++) {
+ HexValue *val = &g_array_index(c->inst.init_list, HexValue, i);
+ if (val->type == REGISTER_ARG) {
+ char reg_id[5];
+ reg_compose(c, locp, &val->reg, reg_id);
+ EMIT_HEAD(c, "tcg_gen_movi_i%u(%s, 0);\n", val->bit_width, reg_id);
+ } else if (val->type == PREDICATE) {
+ char suffix = val->is_dotnew ? 'N' : 'V';
+ EMIT_HEAD(c, "tcg_gen_movi_i%u(P%c%c, 0);\n", val->bit_width,
+ val->pred.id, suffix);
+ } else {
+ yyassert(c, locp, false, "Invalid arg type!");
+ }
+ }
+
+ /* Free argument init list once we have initialized everything */
+ g_array_free(c->inst.init_list, TRUE);
+ c->inst.init_list = NULL;
+}
+
+void gen_inst_code(Context *c, YYLTYPE *locp)
+{
+ if (c->inst.error_count != 0) {
+ fprintf(stderr,
+ "Parsing of instruction %s generated %d errors!\n",
+ c->inst.name->str,
+ c->inst.error_count);
+ } else {
+ free_variables(c, locp);
+ c->implemented_insn++;
+ fprintf(c->enabled_file, "%s\n", c->inst.name->str);
+ emit_footer(c);
+ commit(c);
+ }
+ free_instruction(c);
+}
+
+void gen_pred_assign(Context *c, YYLTYPE *locp, HexValue *left_pred,
+ HexValue *right_pred)
+{
+ char pred_id[2] = {left_pred->pred.id, 0};
+ bool is_direct = is_direct_predicate(left_pred);
+ HexValue r = rvalue_materialize(c, locp, right_pred);
+ r = gen_rvalue_truncate(c, locp, &r);
+ /* Extract predicate TCGv */
+ if (is_direct) {
+ *left_pred = gen_tmp_value(c, locp, "0", 32, UNSIGNED);
+ }
+ /* Extract first 8 bits, and store new predicate value */
+ if (is_inside_ternary(c)) {
+ HexValue zero = gen_constant(c, locp, "0", r.bit_width, UNSIGNED);
+ HexValue tmp = gen_tmp(c, locp, r.bit_width, UNSIGNED);
+ HexValue cond = get_ternary_cond(c, locp);
+ yyassert(c, locp, !is_direct, "direct pred assign inside ternary op");
+ OUT(c, locp, "tcg_gen_mov_i32(", &tmp, ", ", &r, ");\n");
+ OUT(c, locp, "tcg_gen_andi_i32(", &tmp, ", ", &tmp, ", 0xff);\n");
+ OUT(c, locp, "tcg_gen_movcond_i", &r.bit_width);
+ OUT(c, locp, "(TCG_COND_NE, ", left_pred, ", ", &cond, ", ", &zero);
+ OUT(c, locp, ", ", &tmp, ", ", left_pred, ");\n");
+ gen_rvalue_free(c, locp, &tmp);
+ gen_rvalue_free(c, locp, &cond);
+ } else {
+ OUT(c, locp, "tcg_gen_mov_i32(", left_pred, ", ", &r, ");\n");
+ OUT(c, locp, "tcg_gen_andi_i32(", left_pred, ", ", left_pred,
+ ", 0xff);\n");
+ }
+ if (is_direct) {
+ OUT(c, locp, "gen_log_pred_write(ctx, ", pred_id, ", ", left_pred,
+ ");\n");
+ OUT(c, locp, "ctx_log_pred_write(ctx, ", pred_id, ");\n");
+ gen_rvalue_free(c, locp, left_pred);
+ }
+ /* Free temporary value */
+ gen_rvalue_free(c, locp, &r);
+}
+
+void gen_load(Context *c, YYLTYPE *locp, HexValue *width,
+ HexSignedness signedness, HexValue *ea, HexValue *dst)
+{
+ char size_suffix[4] = {0};
+ const char *sign_suffix;
+ /* Memop width is specified in the load macro */
+ assert_signedness(c, locp, signedness);
+ sign_suffix = (width->imm.value > 4)
+ ? ""
+ : ((signedness == UNSIGNED) ? "u" : "s");
+ /* If dst is a variable, assert that is declared and load the type info */
+ if (dst->type == VARID) {
+ find_variable(c, locp, dst, dst);
+ }
+
+ snprintf(size_suffix, 4, "%" PRIu64, width->imm.value * 8);
+ /* Lookup the effective address EA */
+ find_variable(c, locp, ea, ea);
+ OUT(c, locp, "if (insn->slot == 0 && pkt->pkt_has_store_s1) {\n");
+ OUT(c, locp, "process_store(ctx, pkt, 1);\n");
+ OUT(c, locp, "}\n");
+ OUT(c, locp, "tcg_gen_qemu_ld", size_suffix, sign_suffix);
+ OUT(c, locp, "(");
+ if (dst->bit_width > width->imm.value * 8) {
+ /*
+ * Cast to the correct TCG type if necessary, to avoid implict cast
+ * warnings. This is needed when the width of the destination var is
+ * larger than the size of the requested load.
+ */
+ OUT(c, locp, "(TCGv) ");
+ }
+ OUT(c, locp, dst, ", ", ea, ", ctx->mem_idx);\n");
+ /* If the var in EA was truncated it is now a tmp HexValue, so free it. */
+ gen_rvalue_free(c, locp, ea);
+}
+
+void gen_store(Context *c, YYLTYPE *locp, HexValue *width, HexValue *ea,
+ HexValue *src)
+{
+ HexValue src_m = *src;
+ /* Memop width is specified in the store macro */
+ unsigned mem_width = width->imm.value;
+ /* Lookup the effective address EA */
+ find_variable(c, locp, ea, ea);
+ src_m = rvalue_materialize(c, locp, &src_m);
+ OUT(c, locp, "gen_store", &mem_width, "(cpu_env, ", ea, ", ", &src_m);
+ OUT(c, locp, ", ctx, insn->slot);\n");
+ gen_rvalue_free(c, locp, &src_m);
+ /* If the var in ea was truncated it is now a tmp HexValue, so free it. */
+ gen_rvalue_free(c, locp, ea);
+}
+
+void gen_sethalf(Context *c, YYLTYPE *locp, HexCast *sh, HexValue *n,
+ HexValue *dst, HexValue *value)
+{
+ yyassert(c, locp, n->type == IMMEDIATE,
+ "Deposit index must be immediate!\n");
+ if (dst->type == VARID) {
+ find_variable(c, locp, dst, dst);
+ }
+
+ gen_deposit_op(c, locp, dst, value, n, sh);
+}
+
+void gen_setbits(Context *c, YYLTYPE *locp, HexValue *hi, HexValue *lo,
+ HexValue *dst, HexValue *value)
+{
+ unsigned len;
+ HexValue tmp;
+
+ yyassert(c, locp, hi->type == IMMEDIATE &&
+ hi->imm.type == VALUE &&
+ lo->type == IMMEDIATE &&
+ lo->imm.type == VALUE,
+ "Range deposit needs immediate values!\n");
+
+ *value = gen_rvalue_truncate(c, locp, value);
+ len = hi->imm.value + 1 - lo->imm.value;
+ tmp = gen_tmp(c, locp, 32, value->signedness);
+ /* Emit an `and` to ensure `value` is either 0 or 1. */
+ OUT(c, locp, "tcg_gen_andi_i32(", &tmp, ", ", value, ", 1);\n");
+ /* Use `neg` to map 0 -> 0 and 1 -> 0xffff... */
+ OUT(c, locp, "tcg_gen_neg_i32(", &tmp, ", ", &tmp, ");\n");
+ OUT(c, locp, "tcg_gen_deposit_i32(", dst, ", ", dst,
+ ", ", &tmp, ", ");
+ OUT(c, locp, lo, ", ", &len, ");\n");
+
+ gen_rvalue_free(c, locp, &tmp);
+ gen_rvalue_free(c, locp, hi);
+ gen_rvalue_free(c, locp, lo);
+ gen_rvalue_free(c, locp, value);
+}
+
+unsigned gen_if_cond(Context *c, YYLTYPE *locp, HexValue *cond)
+{
+ const char *bit_suffix;
+ /* Generate an end label, if false branch to that label */
+ OUT(c, locp, "TCGLabel *if_label_", &c->inst.if_count,
+ " = gen_new_label();\n");
+ *cond = rvalue_materialize(c, locp, cond);
+ bit_suffix = (cond->bit_width == 64) ? "i64" : "i32";
+ OUT(c, locp, "tcg_gen_brcondi_", bit_suffix, "(TCG_COND_EQ, ", cond,
+ ", 0, if_label_", &c->inst.if_count, ");\n");
+ gen_rvalue_free(c, locp, cond);
+ return c->inst.if_count++;
+}
+
+unsigned gen_if_else(Context *c, YYLTYPE *locp, unsigned index)
+{
+ unsigned if_index = c->inst.if_count++;
+ /* Generate label to jump if else is not verified */
+ OUT(c, locp, "TCGLabel *if_label_", &if_index,
+ " = gen_new_label();\n");
+ /* Jump out of the else statement */
+ OUT(c, locp, "tcg_gen_br(if_label_", &if_index, ");\n");
+ /* Fix the else label */
+ OUT(c, locp, "gen_set_label(if_label_", &index, ");\n");
+ return if_index;
+}
+
+HexValue gen_rvalue_pred(Context *c, YYLTYPE *locp, HexValue *pred)
+{
+ /* Predicted instructions need to zero out result args */
+ gen_inst_init_args(c, locp);
+
+ if (is_direct_predicate(pred)) {
+ bool is_dotnew = pred->is_dotnew;
+ char predicate_id[2] = { pred->pred.id, '\0' };
+ char *pred_str = (char *) &predicate_id;
+ *pred = gen_tmp_value(c, locp, "0", 32, UNSIGNED);
+ if (is_dotnew) {
+ OUT(c, locp, "tcg_gen_mov_i32(", pred,
+ ", hex_new_pred_value[");
+ OUT(c, locp, pred_str, "]);\n");
+ } else {
+ OUT(c, locp, "gen_read_preg(", pred, ", ", pred_str, ");\n");
+ }
+ }
+
+ return *pred;
+}
+
+HexValue gen_rvalue_var(Context *c, YYLTYPE *locp, HexValue *var)
+{
+ find_variable(c, locp, var, var);
+ return *var;
+}
+
+HexValue gen_rvalue_mpy(Context *c, YYLTYPE *locp, HexMpy *mpy,
+ HexValue *op1, HexValue *op2)
+{
+ HexValue res;
+ memset(&res, 0, sizeof(HexValue));
+
+ assert_signedness(c, locp, mpy->first_signedness);
+ assert_signedness(c, locp, mpy->second_signedness);
+
+ *op1 = gen_cast_op(c, locp, op1, mpy->first_bit_width * 2,
+ mpy->first_signedness);
+ /* Handle fMPTY3216.. */
+ if (mpy->first_bit_width == 32) {
+ *op2 = gen_cast_op(c, locp, op2, 64, mpy->second_signedness);
+ } else {
+ *op2 = gen_cast_op(c, locp, op2, mpy->second_bit_width * 2,
+ mpy->second_signedness);
+ }
+ res = gen_bin_op(c, locp, MUL_OP, op1, op2);
+ /* Handle special cases required by the language */
+ if (mpy->first_bit_width == 16 && mpy->second_bit_width == 16) {
+ HexValue src_width = gen_imm_value(c, locp, 32, 32, UNSIGNED);
+ HexSignedness signedness = bin_op_signedness(c, locp,
+ mpy->first_signedness,
+ mpy->second_signedness);
+ res = gen_extend_op(c, locp, &src_width, 64, &res,
+ signedness);
+ }
+ return res;
+}
+
+static inline HexValue gen_rvalue_simple_unary(Context *c, YYLTYPE *locp,
+ HexValue *value,
+ const char *c_code,
+ const char *tcg_code)
+{
+ unsigned bit_width = (value->bit_width == 64) ? 64 : 32;
+ HexValue res;
+ if (value->type == IMMEDIATE) {
+ res = gen_imm_qemu_tmp(c, locp, bit_width, value->signedness);
+ gen_c_int_type(c, locp, value->bit_width, value->signedness);
+ OUT(c, locp, " ", &res, " = ", c_code, "(", value, ");\n");
+ } else {
+ res = gen_tmp(c, locp, bit_width, value->signedness);
+ OUT(c, locp, tcg_code, "_i", &bit_width, "(", &res, ", ", value,
+ ");\n");
+ gen_rvalue_free(c, locp, value);
+ }
+ return res;
+}
+
+
+HexValue gen_rvalue_not(Context *c, YYLTYPE *locp, HexValue *value)
+{
+ return gen_rvalue_simple_unary(c, locp, value, "~", "tcg_gen_not");
+}
+
+HexValue gen_rvalue_notl(Context *c, YYLTYPE *locp, HexValue *value)
+{
+ unsigned bit_width = (value->bit_width == 64) ? 64 : 32;
+ HexValue res;
+ if (value->type == IMMEDIATE) {
+ res = gen_imm_qemu_tmp(c, locp, bit_width, value->signedness);
+ gen_c_int_type(c, locp, value->bit_width, value->signedness);
+ OUT(c, locp, " ", &res, " = !", value, ";\n");
+ } else {
+ HexValue zero = gen_constant(c, locp, "0", bit_width, UNSIGNED);
+ HexValue one = gen_constant(c, locp, "0xff", bit_width, UNSIGNED);
+ res = gen_tmp(c, locp, bit_width, value->signedness);
+ OUT(c, locp, "tcg_gen_movcond_i", &bit_width);
+ OUT(c, locp, "(TCG_COND_EQ, ", &res, ", ", value, ", ", &zero);
+ OUT(c, locp, ", ", &one, ", ", &zero, ");\n");
+ gen_rvalue_free(c, locp, value);
+ }
+ return res;
+}
+
+void gen_set_overflow(Context *c, YYLTYPE *locp, HexValue *value)
+{
+ HexValue value_m = *value;
+
+ if (is_inside_ternary(c)) {
+ /* Inside ternary operator, need to take care of the side-effect */
+ HexValue cond = get_ternary_cond(c, locp);
+ HexValue zero = gen_constant(c, locp, "0", cond.bit_width, UNSIGNED);
+ bool is_64bit = cond.bit_width == 64;
+ unsigned bit_width = cond.bit_width;
+ value_m = rvalue_materialize(c, locp, &value_m);
+ if (is_64bit) {
+ value_m = gen_rvalue_extend(c, locp, &value_m);
+ }
+ OUT(c, locp, "tcg_gen_movcond_i", &bit_width,
+ "(TCG_COND_NE, ", &value_m, ", ", &cond);
+ OUT(c, locp, ", ", &zero, ", ", &value_m, ", ", &zero, ");\n");
+ if (is_64bit) {
+ value_m = gen_rvalue_truncate(c, locp, &value_m);
+ }
+ gen_rvalue_free(c, locp, &cond);
+ }
+
+ OUT(c, locp, "SET_USR_FIELD(USR_OVF, ", &value_m, ");\n");
+ gen_rvalue_free(c, locp, &value_m);
+}
+
+HexValue gen_rvalue_sat(Context *c, YYLTYPE *locp, HexSat *sat,
+ HexValue *width, HexValue *value)
+{
+ const char *unsigned_str;
+ const char *bit_suffix = (value->bit_width == 64) ? "i64" : "i32";
+ HexValue res;
+ assert_signedness(c, locp, sat->signedness);
+ res = gen_tmp(c, locp, value->bit_width, sat->signedness);
+ unsigned_str = (sat->signedness == UNSIGNED) ? "u" : "";
+ if (sat->set_overflow) {
+ yyassert(c, locp, width->imm.value < value->bit_width,
+ "To compute overflow, source width must be greater than"
+ "saturation width!");
+ }
+ if (sat->set_overflow) {
+ HexValue ovfl = gen_tmp(c, locp, 32, sat->signedness);
+ OUT(c, locp, "gen_sat", unsigned_str, "_", bit_suffix, "_ovfl(");
+ OUT(c, locp, &ovfl, ", ", &res, ", ", value, ", ", &width->imm.value,
+ ");\n");
+ gen_set_overflow(c, locp, &ovfl);
+ } else {
+ OUT(c, locp, "gen_sat", unsigned_str, "_", bit_suffix, "(", &res, ", ");
+ OUT(c, locp, value, ", ", &width->imm.value, ");\n");
+ }
+ gen_rvalue_free(c, locp, value);
+ return res;
+}
+
+HexValue gen_rvalue_fscr(Context *c, YYLTYPE *locp, HexValue *value)
+{
+ HexValue key = gen_tmp(c, locp, 64, UNSIGNED);
+ HexValue res = gen_tmp(c, locp, 64, UNSIGNED);
+ HexValue frame_key = gen_tmp(c, locp, 32, UNSIGNED);
+ *value = gen_rvalue_extend(c, locp, value);
+ OUT(c, locp, "gen_read_reg(", &frame_key, ", HEX_REG_FRAMEKEY);\n");
+ OUT(c, locp, "tcg_gen_concat_i32_i64(",
+ &key, ", ", &frame_key, ", ", &frame_key, ");\n");
+ OUT(c, locp, "tcg_gen_xor_i64(", &res, ", ", value, ", ", &key, ");\n");
+ gen_rvalue_free(c, locp, &key);
+ gen_rvalue_free(c, locp, &frame_key);
+ gen_rvalue_free(c, locp, value);
+ return res;
+}
+
+HexValue gen_rvalue_abs(Context *c, YYLTYPE *locp, HexValue *value)
+{
+ return gen_rvalue_simple_unary(c, locp, value, "abs", "tcg_gen_abs");
+}
+
+HexValue gen_rvalue_neg(Context *c, YYLTYPE *locp, HexValue *value)
+{
+ return gen_rvalue_simple_unary(c, locp, value, "-", "tcg_gen_neg");
+}
+
+HexValue gen_rvalue_brev(Context *c, YYLTYPE *locp, HexValue *value)
+{
+ HexValue res;
+ yyassert(c, locp, value->bit_width <= 32,
+ "fbrev not implemented for 64-bit integers!");
+ res = gen_tmp(c, locp, value->bit_width, value->signedness);
+ *value = rvalue_materialize(c, locp, value);
+ OUT(c, locp, "gen_helper_fbrev(", &res, ", ", value, ");\n");
+ gen_rvalue_free(c, locp, value);
+ return res;
+}
+
+HexValue gen_rvalue_ternary(Context *c, YYLTYPE *locp, HexValue *cond,
+ HexValue *true_branch, HexValue *false_branch)
+{
+ bool is_64bit = (true_branch->bit_width == 64) ||
+ (false_branch->bit_width == 64);
+ unsigned bit_width = (is_64bit) ? 64 : 32;
+ HexValue zero = gen_constant(c, locp, "0", bit_width, UNSIGNED);
+ HexValue res = gen_tmp(c, locp, bit_width, UNSIGNED);
+ Ternary *ternary = NULL;
+
+ if (is_64bit) {
+ *cond = gen_rvalue_extend(c, locp, cond);
+ *true_branch = gen_rvalue_extend(c, locp, true_branch);
+ *false_branch = gen_rvalue_extend(c, locp, false_branch);
+ } else {
+ *cond = gen_rvalue_truncate(c, locp, cond);
+ }
+ *cond = rvalue_materialize(c, locp, cond);
+ *true_branch = rvalue_materialize(c, locp, true_branch);
+ *false_branch = rvalue_materialize(c, locp, false_branch);
+
+ OUT(c, locp, "tcg_gen_movcond_i", &bit_width);
+ OUT(c, locp, "(TCG_COND_NE, ", &res, ", ", cond, ", ", &zero);
+ OUT(c, locp, ", ", true_branch, ", ", false_branch, ");\n");
+
+ assert(c->ternary->len > 0);
+ ternary = &g_array_index(c->ternary, Ternary, c->ternary->len - 1);
+ gen_rvalue_free_manual(c, locp, &ternary->cond);
+ g_array_remove_index(c->ternary, c->ternary->len - 1);
+
+ gen_rvalue_free(c, locp, cond);
+ gen_rvalue_free(c, locp, true_branch);
+ gen_rvalue_free(c, locp, false_branch);
+ return res;
+}
+
+const char *cond_to_str(TCGCond cond)
+{
+ switch (cond) {
+ case TCG_COND_NEVER:
+ return "TCG_COND_NEVER";
+ case TCG_COND_ALWAYS:
+ return "TCG_COND_ALWAYS";
+ case TCG_COND_EQ:
+ return "TCG_COND_EQ";
+ case TCG_COND_NE:
+ return "TCG_COND_NE";
+ case TCG_COND_LT:
+ return "TCG_COND_LT";
+ case TCG_COND_GE:
+ return "TCG_COND_GE";
+ case TCG_COND_LE:
+ return "TCG_COND_LE";
+ case TCG_COND_GT:
+ return "TCG_COND_GT";
+ case TCG_COND_LTU:
+ return "TCG_COND_LTU";
+ case TCG_COND_GEU:
+ return "TCG_COND_GEU";
+ case TCG_COND_LEU:
+ return "TCG_COND_LEU";
+ case TCG_COND_GTU:
+ return "TCG_COND_GTU";
+ default:
+ abort();
+ }
+}
+
+void emit_arg(Context *c, YYLTYPE *locp, HexValue *arg)
+{
+ switch (arg->type) {
+ case REGISTER_ARG:
+ if (arg->reg.type == DOTNEW) {
+ EMIT_SIG(c, ", TCGv N%cN", arg->reg.id);
+ } else {
+ bool is64 = (arg->bit_width == 64);
+ const char *type = is64 ? "TCGv_i64" : "TCGv_i32";
+ char reg_id[5];
+ reg_compose(c, locp, &(arg->reg), reg_id);
+ EMIT_SIG(c, ", %s %s", type, reg_id);
+ /* MuV register requires also MuN to provide its index */
+ if (arg->reg.type == MODIFIER) {
+ EMIT_SIG(c, ", int MuN");
+ }
+ }
+ break;
+ case PREDICATE:
+ {
+ char suffix = arg->is_dotnew ? 'N' : 'V';
+ EMIT_SIG(c, ", TCGv P%c%c", arg->pred.id, suffix);
+ }
+ break;
+ default:
+ {
+ fprintf(stderr, "emit_arg got unsupported argument!");
+ abort();
+ }
+ }
+}
+
+void emit_footer(Context *c)
+{
+ EMIT(c, "}\n");
+ EMIT(c, "\n");
+}
+
+void track_string(Context *c, GString *s)
+{
+ g_array_append_val(c->inst.strings, s);
+}
+
+void free_variables(Context *c, YYLTYPE *locp)
+{
+ for (unsigned i = 0; i < c->inst.allocated->len; ++i) {
+ Var *var = &g_array_index(c->inst.allocated, Var, i);
+ const char *suffix = var->bit_width == 64 ? "i64" : "i32";
+ OUT(c, locp, "tcg_temp_free_", suffix, "(", var->name->str, ");\n");
+ }
+}
+
+void free_instruction(Context *c)
+{
+ assert(c->ternary->len == 0);
+ /* Free the strings */
+ g_string_truncate(c->signature_str, 0);
+ g_string_truncate(c->out_str, 0);
+ g_string_truncate(c->header_str, 0);
+ /* Free strings allocated by the instruction */
+ for (unsigned i = 0; i < c->inst.strings->len; i++) {
+ g_string_free(g_array_index(c->inst.strings, GString*, i), TRUE);
+ }
+ g_array_free(c->inst.strings, TRUE);
+ /* Free INAME token value */
+ g_string_free(c->inst.name, TRUE);
+ /* Free variables and registers */
+ g_array_free(c->inst.allocated, TRUE);
+ /* Initialize instruction-specific portion of the context */
+ memset(&(c->inst), 0, sizeof(Inst));
+}
+
+void assert_signedness(Context *c,
+ YYLTYPE *locp,
+ HexSignedness signedness)
+{
+ yyassert(c, locp,
+ signedness != UNKNOWN_SIGNEDNESS,
+ "Unspecified signedness");
+}
diff --git a/target/hexagon/idef-parser/parser-helpers.h b/target/hexagon/idef-parser/parser-helpers.h
new file mode 100644
index 0000000000..af19eb2f41
--- /dev/null
+++ b/target/hexagon/idef-parser/parser-helpers.h
@@ -0,0 +1,375 @@
+/*
+ * Copyright(c) 2019-2021 rev.ng Labs Srl. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PARSER_HELPERS_H
+#define PARSER_HELPERS_H
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "tcg/tcg-cond.h"
+
+#include "idef-parser.tab.h"
+#include "idef-parser.yy.h"
+#include "idef-parser.h"
+
+/* Decomment this to disable yyasserts */
+/* #define NDEBUG */
+
+#define ERR_LINE_CONTEXT 40
+
+#define START_COMMENT "/" "*"
+#define END_COMMENT "*" "/"
+
+void yyerror(YYLTYPE *locp,
+ yyscan_t scanner __attribute__((unused)),
+ Context *c,
+ const char *s);
+
+#ifndef NDEBUG
+#define yyassert(context, locp, condition, msg) \
+ if (!(condition)) { \
+ yyerror(locp, (context)->scanner, (context), (msg)); \
+ }
+#endif
+
+bool is_direct_predicate(HexValue *value);
+
+/**
+ * Print functions
+ */
+
+void str_print(Context *c, YYLTYPE *locp, const char *string);
+
+void uint8_print(Context *c, YYLTYPE *locp, uint8_t *num);
+
+void uint64_print(Context *c, YYLTYPE *locp, uint64_t *num);
+
+void int_print(Context *c, YYLTYPE *locp, int *num);
+
+void uint_print(Context *c, YYLTYPE *locp, unsigned *num);
+
+void tmp_print(Context *c, YYLTYPE *locp, HexTmp *tmp);
+
+void pred_print(Context *c, YYLTYPE *locp, HexPred *pred, bool is_dotnew);
+
+void reg_compose(Context *c, YYLTYPE *locp, HexReg *reg, char reg_id[5]);
+
+void reg_print(Context *c, YYLTYPE *locp, HexReg *reg);
+
+void imm_print(Context *c, YYLTYPE *locp, HexImm *imm);
+
+void var_print(Context *c, YYLTYPE *locp, HexVar *var);
+
+void rvalue_print(Context *c, YYLTYPE *locp, void *pointer);
+
+void out_assert(Context *c, YYLTYPE *locp, void *dummy);
+
+/**
+ * Copies output code buffer into stdout
+ */
+void commit(Context *c);
+
+#define OUT_IMPL(c, locp, x) \
+ _Generic(*x, \
+ char: str_print, \
+ uint8_t: uint8_print, \
+ uint64_t: uint64_print, \
+ int: int_print, \
+ unsigned: uint_print, \
+ HexValue: rvalue_print, \
+ default: out_assert \
+ )(c, locp, x);
+
+/* FOREACH macro */
+#define FE_1(c, locp, WHAT, X) WHAT(c, locp, X)
+#define FE_2(c, locp, WHAT, X, ...) \
+ WHAT(c, locp, X)FE_1(c, locp, WHAT, __VA_ARGS__)
+#define FE_3(c, locp, WHAT, X, ...) \
+ WHAT(c, locp, X)FE_2(c, locp, WHAT, __VA_ARGS__)
+#define FE_4(c, locp, WHAT, X, ...) \
+ WHAT(c, locp, X)FE_3(c, locp, WHAT, __VA_ARGS__)
+#define FE_5(c, locp, WHAT, X, ...) \
+ WHAT(c, locp, X)FE_4(c, locp, WHAT, __VA_ARGS__)
+#define FE_6(c, locp, WHAT, X, ...) \
+ WHAT(c, locp, X)FE_5(c, locp, WHAT, __VA_ARGS__)
+#define FE_7(c, locp, WHAT, X, ...) \
+ WHAT(c, locp, X)FE_6(c, locp, WHAT, __VA_ARGS__)
+#define FE_8(c, locp, WHAT, X, ...) \
+ WHAT(c, locp, X)FE_7(c, locp, WHAT, __VA_ARGS__)
+#define FE_9(c, locp, WHAT, X, ...) \
+ WHAT(c, locp, X)FE_8(c, locp, WHAT, __VA_ARGS__)
+/* repeat as needed */
+
+#define GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, NAME, ...) NAME
+
+#define FOR_EACH(c, locp, action, ...) \
+ do { \
+ GET_MACRO(__VA_ARGS__, \
+ FE_9, \
+ FE_8, \
+ FE_7, \
+ FE_6, \
+ FE_5, \
+ FE_4, \
+ FE_3, \
+ FE_2, \
+ FE_1)(c, locp, action, \
+ __VA_ARGS__) \
+ } while (0)
+
+#define OUT(c, locp, ...) FOR_EACH((c), (locp), OUT_IMPL, __VA_ARGS__)
+
+const char *cmp_swap(Context *c, YYLTYPE *locp, const char *type);
+
+/**
+ * Temporary values creation
+ */
+
+HexValue gen_tmp(Context *c,
+ YYLTYPE *locp,
+ unsigned bit_width,
+ HexSignedness signedness);
+
+HexValue gen_tmp_value(Context *c,
+ YYLTYPE *locp,
+ const char *value,
+ unsigned bit_width,
+ HexSignedness signedness);
+
+HexValue gen_imm_value(Context *c __attribute__((unused)),
+ YYLTYPE *locp,
+ int value,
+ unsigned bit_width,
+ HexSignedness signedness);
+
+HexValue gen_imm_qemu_tmp(Context *c, YYLTYPE *locp, unsigned bit_width,
+ HexSignedness signedness);
+
+void gen_rvalue_free(Context *c, YYLTYPE *locp, HexValue *rvalue);
+
+HexValue rvalue_materialize(Context *c, YYLTYPE *locp, HexValue *rvalue);
+
+HexValue gen_rvalue_extend(Context *c, YYLTYPE *locp, HexValue *rvalue);
+
+HexValue gen_rvalue_truncate(Context *c, YYLTYPE *locp, HexValue *rvalue);
+
+void gen_varid_allocate(Context *c,
+ YYLTYPE *locp,
+ HexValue *varid,
+ unsigned bit_width,
+ HexSignedness signedness);
+
+/**
+ * Code generation functions
+ */
+
+HexValue gen_bin_cmp(Context *c,
+ YYLTYPE *locp,
+ TCGCond type,
+ HexValue *op1,
+ HexValue *op2);
+
+HexValue gen_bin_op(Context *c,
+ YYLTYPE *locp,
+ OpType type,
+ HexValue *op1,
+ HexValue *op2);
+
+HexValue gen_cast_op(Context *c,
+ YYLTYPE *locp,
+ HexValue *src,
+ unsigned target_width,
+ HexSignedness signedness);
+
+/**
+ * gen_extend_op extends a region of src_width_ptr bits stored in a
+ * value_ptr to the size of dst_width. Note: src_width_ptr is a
+ * HexValue * to handle the special case where it is unknown at
+ * translation time.
+ */
+HexValue gen_extend_op(Context *c,
+ YYLTYPE *locp,
+ HexValue *src_width,
+ unsigned dst_width,
+ HexValue *value,
+ HexSignedness signedness);
+
+void gen_rdeposit_op(Context *c,
+ YYLTYPE *locp,
+ HexValue *dst,
+ HexValue *value,
+ HexValue *begin,
+ HexValue *width);
+
+void gen_deposit_op(Context *c,
+ YYLTYPE *locp,
+ HexValue *dst,
+ HexValue *value,
+ HexValue *index,
+ HexCast *cast);
+
+HexValue gen_rextract_op(Context *c,
+ YYLTYPE *locp,
+ HexValue *src,
+ unsigned begin,
+ unsigned width);
+
+HexValue gen_extract_op(Context *c,
+ YYLTYPE *locp,
+ HexValue *src,
+ HexValue *index,
+ HexExtract *extract);
+
+HexValue gen_read_reg(Context *c, YYLTYPE *locp, HexValue *reg);
+
+void gen_write_reg(Context *c, YYLTYPE *locp, HexValue *reg, HexValue *value);
+
+void gen_assign(Context *c,
+ YYLTYPE *locp,
+ HexValue *dst,
+ HexValue *value);
+
+HexValue gen_convround(Context *c,
+ YYLTYPE *locp,
+ HexValue *src);
+
+HexValue gen_round(Context *c,
+ YYLTYPE *locp,
+ HexValue *src,
+ HexValue *position);
+
+HexValue gen_convround_n(Context *c,
+ YYLTYPE *locp,
+ HexValue *src,
+ HexValue *pos);
+
+/**
+ * Circular addressing mode with auto-increment
+ */
+void gen_circ_op(Context *c,
+ YYLTYPE *locp,
+ HexValue *addr,
+ HexValue *increment,
+ HexValue *modifier);
+
+HexValue gen_locnt_op(Context *c, YYLTYPE *locp, HexValue *src);
+
+HexValue gen_ctpop_op(Context *c, YYLTYPE *locp, HexValue *src);
+
+HexValue gen_rotl(Context *c, YYLTYPE *locp, HexValue *src, HexValue *n);
+
+HexValue gen_deinterleave(Context *c, YYLTYPE *locp, HexValue *mixed);
+
+HexValue gen_interleave(Context *c,
+ YYLTYPE *locp,
+ HexValue *odd,
+ HexValue *even);
+
+HexValue gen_carry_from_add(Context *c,
+ YYLTYPE *locp,
+ HexValue *op1,
+ HexValue *op2,
+ HexValue *op3);
+
+void gen_addsat64(Context *c,
+ YYLTYPE *locp,
+ HexValue *dst,
+ HexValue *op1,
+ HexValue *op2);
+
+void gen_inst(Context *c, GString *iname);
+
+void gen_inst_init_args(Context *c, YYLTYPE *locp);
+
+void gen_inst_code(Context *c, YYLTYPE *locp);
+
+void gen_pred_assign(Context *c, YYLTYPE *locp, HexValue *left_pred,
+ HexValue *right_pred);
+
+void gen_load(Context *c, YYLTYPE *locp, HexValue *size,
+ HexSignedness signedness, HexValue *ea, HexValue *dst);
+
+void gen_store(Context *c, YYLTYPE *locp, HexValue *size, HexValue *ea,
+ HexValue *src);
+
+void gen_sethalf(Context *c, YYLTYPE *locp, HexCast *sh, HexValue *n,
+ HexValue *dst, HexValue *value);
+
+void gen_setbits(Context *c, YYLTYPE *locp, HexValue *hi, HexValue *lo,
+ HexValue *dst, HexValue *value);
+
+unsigned gen_if_cond(Context *c, YYLTYPE *locp, HexValue *cond);
+
+unsigned gen_if_else(Context *c, YYLTYPE *locp, unsigned index);
+
+HexValue gen_rvalue_pred(Context *c, YYLTYPE *locp, HexValue *pred);
+
+HexValue gen_rvalue_var(Context *c, YYLTYPE *locp, HexValue *var);
+
+HexValue gen_rvalue_mpy(Context *c, YYLTYPE *locp, HexMpy *mpy, HexValue *op1,
+ HexValue *op2);
+
+HexValue gen_rvalue_not(Context *c, YYLTYPE *locp, HexValue *value);
+
+HexValue gen_rvalue_notl(Context *c, YYLTYPE *locp, HexValue *value);
+
+HexValue gen_rvalue_sat(Context *c, YYLTYPE *locp, HexSat *sat, HexValue *n,
+ HexValue *value);
+
+HexValue gen_rvalue_ternary(Context *c, YYLTYPE *locp, HexValue *cond,
+ HexValue *true_branch, HexValue *false_branch);
+
+HexValue gen_rvalue_fscr(Context *c, YYLTYPE *locp, HexValue *value);
+
+HexValue gen_rvalue_abs(Context *c, YYLTYPE *locp, HexValue *value);
+
+HexValue gen_rvalue_neg(Context *c, YYLTYPE *locp, HexValue *value);
+
+HexValue gen_rvalue_brev(Context *c, YYLTYPE *locp, HexValue *value);
+
+void gen_set_overflow(Context *c, YYLTYPE *locp, HexValue *value);
+
+HexValue gen_rvalue_ternary(Context *c, YYLTYPE *locp, HexValue *cond,
+ HexValue *true_branch, HexValue *false_branch);
+
+const char *cond_to_str(TCGCond cond);
+
+void emit_header(Context *c);
+
+void emit_arg(Context *c, YYLTYPE *locp, HexValue *arg);
+
+void emit_footer(Context *c);
+
+void track_string(Context *c, GString *s);
+
+void free_variables(Context *c, YYLTYPE *locp);
+
+void free_instruction(Context *c);
+
+void assert_signedness(Context *c,
+ YYLTYPE *locp,
+ HexSignedness signedness);
+
+#endif /* PARSER_HELPERS_h */
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index 63f13e1d21..bfc74ba441 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -200,4 +200,29 @@ flex = generator(find_program('flex'),
output: ['@BASENAME@.yy.c', '@BASENAME@.yy.h'],
arguments: ['-o', '@OUTPUT0@', '--header-file=@OUTPUT1@', '@INPUT@'])
+bison = generator(find_program('bison'),
+ output: ['@BASENAME@.tab.c', '@BASENAME@.tab.h'],
+ arguments: ['@INPUT@', '--defines=@OUTPUT1@', '--output=@OUTPUT0@'])
+
+glib_dep = dependency('glib-2.0', native: true)
+
+idef_parser = executable('idef-parser',
+ [flex.process(idef_parser_dir / 'idef-parser.lex'),
+ bison.process(idef_parser_dir / 'idef-parser.y'),
+ idef_parser_dir / 'parser-helpers.c'],
+ include_directories: ['idef-parser', '../../include/'],
+ dependencies: [glib_dep],
+ c_args: ['-Wextra'],
+ native: true)
+
+idef_generated_tcg = custom_target(
+ 'idef-generated-tcg',
+ output: ['idef-generated-emitter.c',
+ 'idef-generated-emitter.h.inc',
+ 'idef-generated-enabled-instructions'],
+ input: preprocessed_idef_parser_input_generated,
+ depend_files: [hex_common_py],
+ command: [idef_parser, '@INPUT@', '@OUTPUT0@', '@OUTPUT1@', '@OUTPUT2@'],
+)
+
target_arch += {'hexagon': hexagon_ss}
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v8 11/12] target/hexagon: call idef-parser functions
2022-02-09 17:03 [PATCH v8 00/12] target/hexagon: introduce idef-parser Anton Johansson via
` (9 preceding siblings ...)
2022-02-09 17:03 ` [PATCH v8 10/12] target/hexagon: import parser " Anton Johansson via
@ 2022-02-09 17:03 ` Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 12/12] target/hexagon: import additional tests Anton Johansson via
11 siblings, 0 replies; 23+ messages in thread
From: Anton Johansson via @ 2022-02-09 17:03 UTC (permalink / raw)
To: qemu-devel
Cc: ale, tsimpson, bcain, mlambert, babush, nizzo, richard.henderson
From: Alessandro Di Federico <ale@rev.ng>
Extend gen_tcg_funcs.py in order to emit calls to the functions emitted
by the idef-parser, if available. An option is also added to fully
disable the output of the idef-parser, which is useful for debugging
purposes.
Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Taylor Simpson <tsimpson@quicinc.com>
---
meson_options.txt | 3 +
target/hexagon/gen_helper_funcs.py | 17 +++++-
target/hexagon/gen_helper_protos.py | 17 +++++-
target/hexagon/gen_tcg_funcs.py | 41 ++++++++++++-
target/hexagon/hex_common.py | 10 ++++
target/hexagon/meson.build | 92 +++++++++++++++++++----------
6 files changed, 146 insertions(+), 34 deletions(-)
diff --git a/meson_options.txt b/meson_options.txt
index 921967eddb..3d66149356 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -208,3 +208,6 @@ option('fdt', type: 'combo', value: 'auto',
option('selinux', type: 'feature', value: 'auto',
description: 'SELinux support in qemu-nbd')
+
+option('hexagon_idef_parser_enabled', type : 'boolean', value : true,
+ description: 'Whether idef-parser should be used to automatically generate TCG code for the Hexagon frontend')
diff --git a/target/hexagon/gen_helper_funcs.py b/target/hexagon/gen_helper_funcs.py
index a446c45384..71d611283a 100755
--- a/target/hexagon/gen_helper_funcs.py
+++ b/target/hexagon/gen_helper_funcs.py
@@ -287,11 +287,24 @@ def main():
hex_common.read_attribs_file(sys.argv[2])
hex_common.read_overrides_file(sys.argv[3])
hex_common.read_overrides_file(sys.argv[4])
+ ## Whether or not idef-parser is enabled is
+ ## determined by the number of arguments to
+ ## this script:
+ ##
+ ## 5 args. -> not enabled,
+ ## 6 args. -> idef-parser enabled.
+ ##
+ ## The 6:th arg. then holds a list of the successfully
+ ## parsed instructions.
+ is_idef_parser_enabled = len(sys.argv) > 6
+ if is_idef_parser_enabled:
+ hex_common.read_idef_parser_enabled_file(sys.argv[5])
hex_common.calculate_attribs()
tagregs = hex_common.get_tagregs()
tagimms = hex_common.get_tagimms()
- with open(sys.argv[5], 'w') as f:
+ output_file = sys.argv[-1]
+ with open(output_file, 'w') as f:
for tag in hex_common.tags:
## Skip the priv instructions
if ( "A_PRIV" in hex_common.attribdict[tag] ) :
@@ -308,6 +321,8 @@ def main():
continue
if ( hex_common.skip_qemu_helper(tag) ):
continue
+ if ( hex_common.is_idef_parser_enabled(tag) ):
+ continue
gen_helper_function(f, tag, tagregs, tagimms)
diff --git a/target/hexagon/gen_helper_protos.py b/target/hexagon/gen_helper_protos.py
index 3b4e993fd1..74eff457a6 100755
--- a/target/hexagon/gen_helper_protos.py
+++ b/target/hexagon/gen_helper_protos.py
@@ -136,11 +136,24 @@ def main():
hex_common.read_attribs_file(sys.argv[2])
hex_common.read_overrides_file(sys.argv[3])
hex_common.read_overrides_file(sys.argv[4])
+ ## Whether or not idef-parser is enabled is
+ ## determined by the number of arguments to
+ ## this script:
+ ##
+ ## 5 args. -> not enabled,
+ ## 6 args. -> idef-parser enabled.
+ ##
+ ## The 6:th arg. then holds a list of the successfully
+ ## parsed instructions.
+ is_idef_parser_enabled = len(sys.argv) > 6
+ if is_idef_parser_enabled:
+ hex_common.read_idef_parser_enabled_file(sys.argv[5])
hex_common.calculate_attribs()
tagregs = hex_common.get_tagregs()
tagimms = hex_common.get_tagimms()
- with open(sys.argv[5], 'w') as f:
+ output_file = sys.argv[-1]
+ with open(output_file, 'w') as f:
for tag in hex_common.tags:
## Skip the priv instructions
if ( "A_PRIV" in hex_common.attribdict[tag] ) :
@@ -158,6 +171,8 @@ def main():
if ( hex_common.skip_qemu_helper(tag) ):
continue
+ if ( hex_common.is_idef_parser_enabled(tag) ):
+ continue
gen_helper_prototype(f, tag, tagregs, tagimms)
diff --git a/target/hexagon/gen_tcg_funcs.py b/target/hexagon/gen_tcg_funcs.py
index 1fd9de95d5..4d12e192a7 100755
--- a/target/hexagon/gen_tcg_funcs.py
+++ b/target/hexagon/gen_tcg_funcs.py
@@ -610,7 +610,29 @@ def gen_tcg_func(f, tag, regs, imms):
if (hex_common.is_read(regid)):
genptr_src_read_opn(f,regtype,regid,tag)
- if ( hex_common.skip_qemu_helper(tag) ):
+ if hex_common.is_idef_parser_enabled(tag):
+ declared = []
+ ## Handle registers
+ for regtype,regid,toss,numregs in regs:
+ if (hex_common.is_pair(regid)
+ or (hex_common.is_single(regid)
+ and hex_common.is_old_val(regtype, regid, tag))):
+ declared.append("%s%sV" % (regtype, regid))
+ if regtype == "M":
+ declared.append("%s%sN" % (regtype, regid))
+ elif hex_common.is_new_val(regtype, regid, tag):
+ declared.append("%s%sN" % (regtype,regid))
+ else:
+ print("Bad register parse: ",regtype,regid,toss,numregs)
+
+ ## Handle immediates
+ for immlett,bits,immshift in imms:
+ declared.append(hex_common.imm_name(immlett))
+
+ arguments = ", ".join(["ctx", "insn", "pkt"] + declared)
+ f.write(" emit_%s(%s);\n" % (tag, arguments))
+
+ elif ( hex_common.skip_qemu_helper(tag) ):
f.write(" fGEN_TCG_%s(%s);\n" % (tag, hex_common.semdict[tag]))
else:
## Generate the call to the helper
@@ -677,12 +699,27 @@ def main():
hex_common.read_overrides_file(sys.argv[3])
hex_common.read_overrides_file(sys.argv[4])
hex_common.calculate_attribs()
+ ## Whether or not idef-parser is enabled is
+ ## determined by the number of arguments to
+ ## this script:
+ ##
+ ## 5 args. -> not enabled,
+ ## 6 args. -> idef-parser enabled.
+ ##
+ ## The 6:th arg. then holds a list of the successfully
+ ## parsed instructions.
+ is_idef_parser_enabled = len(sys.argv) > 6
+ if is_idef_parser_enabled:
+ hex_common.read_idef_parser_enabled_file(sys.argv[5])
tagregs = hex_common.get_tagregs()
tagimms = hex_common.get_tagimms()
- with open(sys.argv[5], 'w') as f:
+ output_file = sys.argv[-1]
+ with open(output_file, 'w') as f:
f.write("#ifndef HEXAGON_TCG_FUNCS_H\n")
f.write("#define HEXAGON_TCG_FUNCS_H\n\n")
+ if is_idef_parser_enabled:
+ f.write("#include \"idef-generated-emitter.h.inc\"\n\n")
for tag in hex_common.tags:
## Skip the priv instructions
diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py
index c81aca8d2a..901041d557 100755
--- a/target/hexagon/hex_common.py
+++ b/target/hexagon/hex_common.py
@@ -28,6 +28,7 @@
attribinfo = {} # Register information and misc
tags = [] # list of all tags
overrides = {} # tags with helper overrides
+idef_parser_enabled = {} # tags enabled for idef-parser
# We should do this as a hash for performance,
# but to keep order let's keep it as a list.
@@ -216,6 +217,9 @@ def is_tmp_result(tag):
def is_new_result(tag):
return ('A_CVI_NEW' in attribdict[tag])
+def is_idef_parser_enabled(tag):
+ return tag in idef_parser_enabled
+
def imm_name(immlett):
return "%siV" % immlett
@@ -247,3 +251,9 @@ def read_overrides_file(name):
continue
tag = overridere.findall(line)[0]
overrides[tag] = True
+
+def read_idef_parser_enabled_file(name):
+ global idef_parser_enabled
+ with open(name, "r") as idef_parser_enabled_file:
+ lines = idef_parser_enabled_file.read().strip().split("\n")
+ idef_parser_enabled = set(lines)
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index bfc74ba441..6adf7e2464 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -43,10 +43,7 @@ hexagon_ss.add(semantics_generated)
# Step 2
# We use Python scripts to generate the following files
# shortcode_generated.h.inc
-# helper_protos_generated.h.inc
-# tcg_funcs_generated.c.inc
# tcg_func_table_generated.c.inc
-# helper_funcs_generated.c.inc
# printinsn_generated.h.inc
# op_regs_generated.h.inc
# op_attribs_generated.h.inc
@@ -61,24 +58,6 @@ shortcode_generated = custom_target(
)
hexagon_ss.add(shortcode_generated)
-helper_protos_generated = custom_target(
- 'helper_protos_generated.h.inc',
- output: 'helper_protos_generated.h.inc',
- depends: [semantics_generated],
- depend_files: [hex_common_py, attribs_def, gen_tcg_h, gen_tcg_hvx_h],
- command: [python, files('gen_helper_protos.py'), semantics_generated, attribs_def, gen_tcg_h, gen_tcg_hvx_h, '@OUTPUT@'],
-)
-hexagon_ss.add(helper_protos_generated)
-
-tcg_funcs_generated = custom_target(
- 'tcg_funcs_generated.c.inc',
- output: 'tcg_funcs_generated.c.inc',
- depends: [semantics_generated],
- depend_files: [hex_common_py, attribs_def, gen_tcg_h, gen_tcg_hvx_h],
- command: [python, files('gen_tcg_funcs.py'), semantics_generated, attribs_def, gen_tcg_h, gen_tcg_hvx_h, '@OUTPUT@'],
-)
-hexagon_ss.add(tcg_funcs_generated)
-
tcg_func_table_generated = custom_target(
'tcg_func_table_generated.c.inc',
output: 'tcg_func_table_generated.c.inc',
@@ -88,15 +67,6 @@ tcg_func_table_generated = custom_target(
)
hexagon_ss.add(tcg_func_table_generated)
-helper_funcs_generated = custom_target(
- 'helper_funcs_generated.c.inc',
- output: 'helper_funcs_generated.c.inc',
- depends: [semantics_generated],
- depend_files: [hex_common_py, attribs_def, gen_tcg_h, gen_tcg_hvx_h],
- command: [python, files('gen_helper_funcs.py'), semantics_generated, attribs_def, gen_tcg_h, gen_tcg_hvx_h, '@OUTPUT@'],
-)
-hexagon_ss.add(helper_funcs_generated)
-
printinsn_generated = custom_target(
'printinsn_generated.h.inc',
output: 'printinsn_generated.h.inc',
@@ -180,6 +150,8 @@ hexagon_ss.add(files(
'mmvec/system_ext_mmvec.c',
))
+idef_parser_enabled = get_option('hexagon_idef_parser_enabled')
+
idef_parser_input_generated = custom_target(
'idef_parser_input.h.inc',
output: 'idef_parser_input.h.inc',
@@ -225,4 +197,64 @@ idef_generated_tcg = custom_target(
command: [idef_parser, '@INPUT@', '@OUTPUT0@', '@OUTPUT1@', '@OUTPUT2@'],
)
+indent = find_program('indent', required: false)
+if indent.found()
+ idef_generated_tcg_c = custom_target('asd',
+ input: idef_generated_tcg[0],
+ output: 'idef-generated-emitter.indented.c',
+ command: [indent, '-linux', '@INPUT@', '-o', '@OUTPUT@'])
+else
+ idef_generated_tcg_c = custom_target('asd',
+ input: idef_generated_tcg[0],
+ output: 'idef-generated-emitter.indented.c',
+ command: ['cp', '@INPUT@', '@OUTPUT@'])
+endif
+
+idef_generated_list = idef_generated_tcg[2].full_path()
+
+hexagon_ss.add(idef_generated_tcg_c)
+
+#
+# Step 5
+# We use Python scripts to generate the following files
+# helper_protos_generated.h.inc
+# helper_funcs_generated.c.inc
+# tcg_funcs_generated.c.inc
+#
+if idef_parser_enabled
+ helper_dep = [semantics_generated, idef_generated_tcg_c, idef_generated_tcg]
+ helper_in = [semantics_generated, attribs_def, gen_tcg_h, gen_tcg_hvx_h,
+ idef_generated_list]
+else
+ helper_dep = [semantics_generated]
+ helper_in = [semantics_generated, attribs_def, gen_tcg_h, gen_tcg_hvx_h]
+endif
+
+helper_protos_generated = custom_target(
+ 'helper_protos_generated.h.inc',
+ output: 'helper_protos_generated.h.inc',
+ depends: helper_dep,
+ depend_files: [hex_common_py, attribs_def, gen_tcg_h, gen_tcg_hvx_h],
+ command: [python, files('gen_helper_protos.py'), helper_in, '@OUTPUT@'],
+)
+hexagon_ss.add(helper_protos_generated)
+
+helper_funcs_generated = custom_target(
+ 'helper_funcs_generated.c.inc',
+ output: 'helper_funcs_generated.c.inc',
+ depends: helper_dep,
+ depend_files: [hex_common_py, attribs_def, gen_tcg_h, gen_tcg_hvx_h],
+ command: [python, files('gen_helper_funcs.py'), helper_in, '@OUTPUT@'],
+)
+hexagon_ss.add(helper_funcs_generated)
+
+tcg_funcs_generated = custom_target(
+ 'tcg_funcs_generated.c.inc',
+ output: 'tcg_funcs_generated.c.inc',
+ depends: helper_dep,
+ depend_files: [hex_common_py, attribs_def, gen_tcg_h, gen_tcg_hvx_h],
+ command: [python, files('gen_tcg_funcs.py'), helper_in, '@OUTPUT@'],
+)
+hexagon_ss.add(tcg_funcs_generated)
+
target_arch += {'hexagon': hexagon_ss}
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v8 12/12] target/hexagon: import additional tests
2022-02-09 17:03 [PATCH v8 00/12] target/hexagon: introduce idef-parser Anton Johansson via
` (10 preceding siblings ...)
2022-02-09 17:03 ` [PATCH v8 11/12] target/hexagon: call idef-parser functions Anton Johansson via
@ 2022-02-09 17:03 ` Anton Johansson via
2022-03-21 18:58 ` Taylor Simpson
11 siblings, 1 reply; 23+ messages in thread
From: Anton Johansson via @ 2022-02-09 17:03 UTC (permalink / raw)
To: qemu-devel
Cc: ale, tsimpson, bcain, mlambert, babush, nizzo, richard.henderson
From: Niccolò Izzo <nizzo@rev.ng>
Signed-off-by: Alessandro Di Federico <ale@rev.ng>
Signed-off-by: Niccolò Izzo <nizzo@rev.ng>
Signed-off-by: Anton Johansson <anjo@rev.ng>
---
tests/tcg/hexagon/Makefile.target | 28 ++++++++++++-
tests/tcg/hexagon/crt.S | 14 +++++++
tests/tcg/hexagon/test_abs.S | 17 ++++++++
tests/tcg/hexagon/test_bitcnt.S | 40 +++++++++++++++++++
tests/tcg/hexagon/test_bitsplit.S | 22 ++++++++++
tests/tcg/hexagon/test_call.S | 64 ++++++++++++++++++++++++++++++
tests/tcg/hexagon/test_clobber.S | 29 ++++++++++++++
tests/tcg/hexagon/test_cmp.S | 31 +++++++++++++++
tests/tcg/hexagon/test_dotnew.S | 38 ++++++++++++++++++
tests/tcg/hexagon/test_ext.S | 13 ++++++
tests/tcg/hexagon/test_fibonacci.S | 30 ++++++++++++++
tests/tcg/hexagon/test_hl.S | 16 ++++++++
tests/tcg/hexagon/test_hwloops.S | 19 +++++++++
tests/tcg/hexagon/test_jmp.S | 22 ++++++++++
tests/tcg/hexagon/test_lsr.S | 36 +++++++++++++++++
tests/tcg/hexagon/test_mpyi.S | 17 ++++++++
tests/tcg/hexagon/test_packet.S | 29 ++++++++++++++
tests/tcg/hexagon/test_reorder.S | 33 +++++++++++++++
tests/tcg/hexagon/test_round.S | 29 ++++++++++++++
tests/tcg/hexagon/test_vavgw.S | 31 +++++++++++++++
tests/tcg/hexagon/test_vcmpb.S | 30 ++++++++++++++
tests/tcg/hexagon/test_vcmpw.S | 30 ++++++++++++++
tests/tcg/hexagon/test_vlsrw.S | 20 ++++++++++
tests/tcg/hexagon/test_vmaxh.S | 35 ++++++++++++++++
tests/tcg/hexagon/test_vminh.S | 35 ++++++++++++++++
tests/tcg/hexagon/test_vpmpyh.S | 28 +++++++++++++
tests/tcg/hexagon/test_vspliceb.S | 31 +++++++++++++++
27 files changed, 766 insertions(+), 1 deletion(-)
create mode 100644 tests/tcg/hexagon/crt.S
create mode 100644 tests/tcg/hexagon/test_abs.S
create mode 100644 tests/tcg/hexagon/test_bitcnt.S
create mode 100644 tests/tcg/hexagon/test_bitsplit.S
create mode 100644 tests/tcg/hexagon/test_call.S
create mode 100644 tests/tcg/hexagon/test_clobber.S
create mode 100644 tests/tcg/hexagon/test_cmp.S
create mode 100644 tests/tcg/hexagon/test_dotnew.S
create mode 100644 tests/tcg/hexagon/test_ext.S
create mode 100644 tests/tcg/hexagon/test_fibonacci.S
create mode 100644 tests/tcg/hexagon/test_hl.S
create mode 100644 tests/tcg/hexagon/test_hwloops.S
create mode 100644 tests/tcg/hexagon/test_jmp.S
create mode 100644 tests/tcg/hexagon/test_lsr.S
create mode 100644 tests/tcg/hexagon/test_mpyi.S
create mode 100644 tests/tcg/hexagon/test_packet.S
create mode 100644 tests/tcg/hexagon/test_reorder.S
create mode 100644 tests/tcg/hexagon/test_round.S
create mode 100644 tests/tcg/hexagon/test_vavgw.S
create mode 100644 tests/tcg/hexagon/test_vcmpb.S
create mode 100644 tests/tcg/hexagon/test_vcmpw.S
create mode 100644 tests/tcg/hexagon/test_vlsrw.S
create mode 100644 tests/tcg/hexagon/test_vmaxh.S
create mode 100644 tests/tcg/hexagon/test_vminh.S
create mode 100644 tests/tcg/hexagon/test_vpmpyh.S
create mode 100644 tests/tcg/hexagon/test_vspliceb.S
diff --git a/tests/tcg/hexagon/Makefile.target b/tests/tcg/hexagon/Makefile.target
index 8b07a28166..508ab08065 100644
--- a/tests/tcg/hexagon/Makefile.target
+++ b/tests/tcg/hexagon/Makefile.target
@@ -24,7 +24,7 @@ CFLAGS += -fno-unroll-loops
HEX_SRC=$(SRC_PATH)/tests/tcg/hexagon
VPATH += $(HEX_SRC)
-first: $(HEX_SRC)/first.S
+%: $(HEX_SRC)/%.S $(HEX_SRC)/crt.S
$(CC) -static -mv67 -nostdlib $^ -o $@
HEX_TESTS = first
@@ -42,4 +42,30 @@ HEX_TESTS += atomics
HEX_TESTS += fpstuff
HEX_TESTS += overflow
+HEX_TESTS += test_abs
+HEX_TESTS += test_bitcnt
+HEX_TESTS += test_bitsplit
+HEX_TESTS += test_call
+HEX_TESTS += test_clobber
+HEX_TESTS += test_cmp
+HEX_TESTS += test_dotnew
+HEX_TESTS += test_ext
+HEX_TESTS += test_fibonacci
+HEX_TESTS += test_hl
+HEX_TESTS += test_hwloops
+HEX_TESTS += test_jmp
+HEX_TESTS += test_lsr
+HEX_TESTS += test_mpyi
+HEX_TESTS += test_packet
+HEX_TESTS += test_reorder
+HEX_TESTS += test_round
+HEX_TESTS += test_vavgw
+HEX_TESTS += test_vcmpb
+HEX_TESTS += test_vcmpw
+HEX_TESTS += test_vlsrw
+HEX_TESTS += test_vmaxh
+HEX_TESTS += test_vminh
+HEX_TESTS += test_vpmpyh
+HEX_TESTS += test_vspliceb
+
TESTS += $(HEX_TESTS)
diff --git a/tests/tcg/hexagon/crt.S b/tests/tcg/hexagon/crt.S
new file mode 100644
index 0000000000..f9e6bc80f7
--- /dev/null
+++ b/tests/tcg/hexagon/crt.S
@@ -0,0 +1,14 @@
+#define SYS_exit_group 94
+
+ .text
+ .globl pass
+pass:
+ r0 = #0
+ r6 = #SYS_exit_group
+ trap0(#1)
+
+ .globl fail
+fail:
+ r0 = #1
+ r6 = #SYS_exit_group
+ trap0(#1)
diff --git a/tests/tcg/hexagon/test_abs.S b/tests/tcg/hexagon/test_abs.S
new file mode 100644
index 0000000000..d68aea6f64
--- /dev/null
+++ b/tests/tcg/hexagon/test_abs.S
@@ -0,0 +1,17 @@
+/* Purpose: test example, verify the soundness of the abs operation */
+
+ .text
+ .globl _start
+
+_start:
+ {
+ r1 = #-2
+ r2 = #2
+ }
+ {
+ r3 = abs(r1)
+ }
+ {
+ p0 = cmp.eq(r3, r2); if (p0.new) jump:t pass
+ jump fail
+ }
diff --git a/tests/tcg/hexagon/test_bitcnt.S b/tests/tcg/hexagon/test_bitcnt.S
new file mode 100644
index 0000000000..624460488e
--- /dev/null
+++ b/tests/tcg/hexagon/test_bitcnt.S
@@ -0,0 +1,40 @@
+/*
+ * Purpose: test example, verify the soundness of the cl[01] operations.
+ *
+ * The number 0x000001aa has 23 leading zeroes
+ * they become 55 when considered as 64 bit register
+ * and it has 1 trailing zero.
+ */
+ .text
+ .globl _start
+
+_start:
+ {
+ r0 = #426
+ r1 = #0
+ }
+ {
+ r2 = cl0(r0)
+ }
+ {
+ p0 = cmp.eq(r2, #23); if (p0.new) jump:t test2
+ jump fail
+ }
+
+test2:
+ {
+ r2 = cl0(r1:0)
+ }
+ {
+ p0 = cmp.eq(r2, #55); if (p0.new) jump:t test3
+ jump fail
+ }
+
+test3:
+ {
+ r2 = ct0(r0)
+ }
+ {
+ p0 = cmp.eq(r2, #1); if (p0.new) jump:t pass
+ jump fail
+ }
diff --git a/tests/tcg/hexagon/test_bitsplit.S b/tests/tcg/hexagon/test_bitsplit.S
new file mode 100644
index 0000000000..275658e613
--- /dev/null
+++ b/tests/tcg/hexagon/test_bitsplit.S
@@ -0,0 +1,22 @@
+/* Purpose: test example, verify the soundness of the bitsplit operation */
+
+ .text
+ .globl _start
+
+_start:
+ {
+ r1 = #187
+ }
+ {
+ r3:2 = bitsplit(r1, #3)
+ }
+ {
+ p0 = cmp.eq(r2, #3); if (p0.new) jump:t test2
+ jump fail
+ }
+
+test2:
+ {
+ p0 = cmp.eq(r3, #23); if (p0.new) jump:t pass
+ jump fail
+ }
diff --git a/tests/tcg/hexagon/test_call.S b/tests/tcg/hexagon/test_call.S
new file mode 100644
index 0000000000..338cd04e40
--- /dev/null
+++ b/tests/tcg/hexagon/test_call.S
@@ -0,0 +1,64 @@
+/*
+ * Purpose: test function calls and duplex instructions.
+ * The string "Hello there, I'm a test string!" with the first letter replaced
+ * with a capital L should be printed out.
+ */
+
+#define SYS_write 64
+#define FD_STDOUT 1
+
+ .text
+ .globl test
+test:
+ {
+ jumpr r31
+ memb(r0+#0) = #76
+ }
+.Lfunc_end0:
+.Ltmp0:
+ .size test, .Ltmp0-test
+
+ .globl _start
+_start:
+ {
+ r0 = ##dummy_buffer
+ allocframe(#0)
+ call test
+ }
+ {
+ call write
+ }
+ {
+ deallocframe
+ jump pass
+ }
+.Lfunc_end1:
+.Ltmp1:
+ .size _start, .Ltmp1-_start
+
+write:
+ {
+ r6 = #SYS_write
+ r0 = #FD_STDOUT
+ r1 = ##dummy_buffer
+ r2 = #33
+ }
+ {
+ trap0(#1)
+ }
+ {
+ jumpr r31
+ }
+
+.Lfunc_end2:
+.Ltmp2:
+ .size write, .Ltmp2-write
+
+ .type dummy_buffer,@object
+ .data
+ .globl dummy_buffer
+ .p2align 3
+dummy_buffer:
+ .string "Hello there, I'm a test string!\n"
+ .space 223
+ .size dummy_buffer, 256
diff --git a/tests/tcg/hexagon/test_clobber.S b/tests/tcg/hexagon/test_clobber.S
new file mode 100644
index 0000000000..a7aeb2b60c
--- /dev/null
+++ b/tests/tcg/hexagon/test_clobber.S
@@ -0,0 +1,29 @@
+/*
+ * Purpose: demonstrate the succesful operation of the register save mechanism,
+ * in which the caller saves the registers that will be clobbered, and restores
+ * them after the call.
+ */
+
+ .text
+ .globl _start
+
+_start:
+ allocframe(#8)
+ {
+ r16 = #47
+ r17 = #155
+ }
+ memd(sp+#0) = r17:16
+ {
+ r16 = #255
+ r17 = #42
+ }
+ {
+ deallocframe
+ r17:16 = memd(sp+#0)
+ }
+ {
+ p0 = cmp.eq(r16, #47)
+ p0 = cmp.eq(r17, #155); if (p0.new) jump:t pass
+ jump fail
+ }
diff --git a/tests/tcg/hexagon/test_cmp.S b/tests/tcg/hexagon/test_cmp.S
new file mode 100644
index 0000000000..1db87d3db5
--- /dev/null
+++ b/tests/tcg/hexagon/test_cmp.S
@@ -0,0 +1,31 @@
+/* Purpose: test a signed and unsigned comparison */
+
+ .text
+ .globl _start
+
+_start:
+ {
+ jump signed
+ }
+
+ .globl signed
+signed:
+ {
+ r0 = #-2
+ r1 = #0
+ }
+ {
+ p0 = cmp.lt(r0, r1); if (p0.new) jump:t unsigned
+ jump fail
+ }
+
+ .globl unsigned
+unsigned:
+ {
+ r0 = #-2
+ r1 = #0
+ }
+ {
+ p0 = cmp.gtu(r0, r1); if (p0.new) jump:t pass
+ jump fail
+ }
diff --git a/tests/tcg/hexagon/test_dotnew.S b/tests/tcg/hexagon/test_dotnew.S
new file mode 100644
index 0000000000..b18b6a72e2
--- /dev/null
+++ b/tests/tcg/hexagon/test_dotnew.S
@@ -0,0 +1,38 @@
+/* Purpose: test the .new operator while performing memory stores. */
+
+ .text
+ .globl _start
+
+_start:
+ {
+ allocframe(#16)
+ }
+ {
+ r0 = #1
+ memw(sp+#0) = r0.new
+ }
+ {
+ r1 = #2
+ memw(sp+#4) = r1.new
+ }
+ {
+ r2 = #3
+ memw(sp+#8) = r2.new
+ }
+ {
+ r0 = memw(sp+#8)
+ }
+ {
+ r1 = memw(sp+#4)
+ }
+ {
+ r2 = memw(sp+#0)
+ }
+ {
+ r3 = mpyi(r1, r2)
+ }
+ {
+ deallocframe
+ p0 = cmp.eq(r3, #2); if (p0.new) jump:t pass
+ jump fail
+ }
diff --git a/tests/tcg/hexagon/test_ext.S b/tests/tcg/hexagon/test_ext.S
new file mode 100644
index 0000000000..03e7bce2a7
--- /dev/null
+++ b/tests/tcg/hexagon/test_ext.S
@@ -0,0 +1,13 @@
+/* Purpose: test immediate extender instructions. */
+
+ .text
+ .globl _start
+
+_start:
+ {
+ r2 = ##-559038737
+ }
+ {
+ p0 = cmp.eq(r2, ##-559038737); if (p0.new) jump:t pass
+ jump fail
+ }
diff --git a/tests/tcg/hexagon/test_fibonacci.S b/tests/tcg/hexagon/test_fibonacci.S
new file mode 100644
index 0000000000..4ef2c3896e
--- /dev/null
+++ b/tests/tcg/hexagon/test_fibonacci.S
@@ -0,0 +1,30 @@
+/* Purpose: computes the Fibonacci series up to a constant number. */
+
+ .text
+ .globl _start
+
+_start:
+ {
+ r2 = #100
+ }
+ {
+ p0 = cmp.gt(r2, #0); if (!p0.new) jump:nt .LBB0_3
+ }
+ {
+ r3 = #0
+ r4 = #1
+ }
+.LBB0_2:
+ {
+ r5 = r4
+ }
+ {
+ p0 = cmp.gt(r2, r5); if (p0.new) jump:nt .LBB0_2
+ r4 = add(r3, r4)
+ r3 = r5
+ }
+.LBB0_3:
+ {
+ p0 = cmp.eq(r3, #144); if (p0.new) jump:t pass
+ jump fail
+ }
diff --git a/tests/tcg/hexagon/test_hl.S b/tests/tcg/hexagon/test_hl.S
new file mode 100644
index 0000000000..93ace46aeb
--- /dev/null
+++ b/tests/tcg/hexagon/test_hl.S
@@ -0,0 +1,16 @@
+/* Purpose: test example, verify the soundness of the high/low assignment */
+
+ .text
+ .globl _start
+
+_start:
+ {
+ r0.H = #42
+ }
+ {
+ r0.L = #69
+ }
+ {
+ p0 = cmp.eq(r0, #2752581); if (p0.new) jump:t pass
+ jump fail
+ }
diff --git a/tests/tcg/hexagon/test_hwloops.S b/tests/tcg/hexagon/test_hwloops.S
new file mode 100644
index 0000000000..42785e6f25
--- /dev/null
+++ b/tests/tcg/hexagon/test_hwloops.S
@@ -0,0 +1,19 @@
+/* Purpose: simple C Program to test hardware loops. */
+
+ .text
+ .globl _start
+
+_start:
+ {
+ loop0(.LBB0_1, #10)
+ r2 = #0
+ }
+.LBB0_1:
+ {
+ r2 = add(r2, #1)
+ nop
+ }:endloop0
+ {
+ p0 = cmp.eq(r2, #10); if (p0.new) jump:t pass
+ jump fail
+ }
diff --git a/tests/tcg/hexagon/test_jmp.S b/tests/tcg/hexagon/test_jmp.S
new file mode 100644
index 0000000000..5be25c52b2
--- /dev/null
+++ b/tests/tcg/hexagon/test_jmp.S
@@ -0,0 +1,22 @@
+/* Purpose: test example, verify the soundness of the jump operation */
+
+#define SYS_exit_group 94
+
+ .text
+ .globl _start
+
+_start:
+ {
+ jump pass
+ }
+ /*
+ * Inlined fail label in crt.S so we can fail without
+ * having a functioning jump
+ */
+ {
+ r0 = #1
+ r6 = #SYS_exit_group
+ }
+ {
+ trap0(#1)
+ }
diff --git a/tests/tcg/hexagon/test_lsr.S b/tests/tcg/hexagon/test_lsr.S
new file mode 100644
index 0000000000..b30aa64673
--- /dev/null
+++ b/tests/tcg/hexagon/test_lsr.S
@@ -0,0 +1,36 @@
+/* Purpose: test the soundness of the lsr operation */
+
+ .text
+ .globl _start
+
+_start:
+ {
+ r0 = #-56984
+ r1 = #2147483647
+ }
+ {
+ r2 = #0x19
+ }
+ {
+ r0 &= lsr(r1, r2)
+ }
+ {
+ p0 = cmp.eq(r0, #0x28); if (p0.new) jump:t test2
+ jump fail
+ }
+
+test2:
+ {
+ r0 = #0x0000000a
+ r1 = #0x00000000
+ }
+ {
+ r2 = #-1
+ }
+ {
+ r1:0 = lsl(r1:0, r2)
+ }
+ {
+ p0 = cmp.eq(r0, #0x5); if (p0.new) jump:t pass
+ jump fail
+ }
diff --git a/tests/tcg/hexagon/test_mpyi.S b/tests/tcg/hexagon/test_mpyi.S
new file mode 100644
index 0000000000..953b46e57e
--- /dev/null
+++ b/tests/tcg/hexagon/test_mpyi.S
@@ -0,0 +1,17 @@
+/* Purpose: test a simple multiplication operation */
+
+ .text
+ .globl _start
+
+_start:
+ {
+ r1 = #4
+ r2 = #6
+ }
+ {
+ r3 = mpyi(r1, r2)
+ }
+ {
+ p0 = cmp.eq(r3, #24); if (p0.new) jump:t pass
+ jump fail
+ }
diff --git a/tests/tcg/hexagon/test_packet.S b/tests/tcg/hexagon/test_packet.S
new file mode 100644
index 0000000000..9ec9d8d6fb
--- /dev/null
+++ b/tests/tcg/hexagon/test_packet.S
@@ -0,0 +1,29 @@
+/*
+ * Purpose: test that writes of a register in a packet are performed only after
+ * that packet has finished its execution.
+ */
+
+ .text
+ .globl _start
+
+_start:
+ {
+ allocframe(#8)
+ }
+ {
+ r2 = #4
+ r3 = #6
+ }
+ {
+ memw(sp+#0) = r2
+ }
+ {
+ r3 = memw(sp+#0)
+ r0 = add(r2, r3)
+ }
+ {
+ deallocframe
+ p0 = cmp.eq(r3, #4)
+ p0 = cmp.eq(r0, #10); if (p0.new) jump:t pass
+ jump fail
+ }
diff --git a/tests/tcg/hexagon/test_reorder.S b/tests/tcg/hexagon/test_reorder.S
new file mode 100644
index 0000000000..5ee0539836
--- /dev/null
+++ b/tests/tcg/hexagon/test_reorder.S
@@ -0,0 +1,33 @@
+/*
+ * Purpose: demonstrate handling of .new uses appearing before the associated
+ * definition.
+ * Here we perform a jump that skips the code resetting R2 from 0xDEADBEEF to 0,
+ * only if P0.new is true, but P0 is assigned to 1 (R4) in the next instruction
+ * in the packet.
+ */
+
+ .text
+ .globl _start
+
+_start:
+ {
+ r2 = #-559038737
+ }
+ {
+ r4 = #1
+ }
+ {
+ if (p0.new) jump:nt skip
+ p0 = r4;
+ }
+
+fallthrough:
+ {
+ r2 = #0
+ }
+
+skip:
+ {
+ p0 = cmp.eq(r2, #-559038737); if (p0.new) jump:t pass
+ jump fail
+ }
diff --git a/tests/tcg/hexagon/test_round.S b/tests/tcg/hexagon/test_round.S
new file mode 100644
index 0000000000..3c83812fe8
--- /dev/null
+++ b/tests/tcg/hexagon/test_round.S
@@ -0,0 +1,29 @@
+/*
+ * Purpose: test example, verify the soundness of the cround operation
+ * 106 = 0b1101010 with the comma at third digit is 12.5 which is crounded to 12
+ * but rounded to 13.
+ */
+
+ .text
+ .globl _start
+
+_start:
+ {
+ r1 = #200
+ }
+ {
+ r2 = round(r1, #4)
+ }
+ {
+ p0 = cmp.eq(r2, #13); if (p0.new) jump:t test2
+ jump fail
+ }
+
+test2:
+ {
+ r2 = cround(r1, #4)
+ }
+ {
+ p0 = cmp.eq(r2, #12); if (p0.new) jump:t pass
+ jump fail
+ }
diff --git a/tests/tcg/hexagon/test_vavgw.S b/tests/tcg/hexagon/test_vavgw.S
new file mode 100644
index 0000000000..53c9df706a
--- /dev/null
+++ b/tests/tcg/hexagon/test_vavgw.S
@@ -0,0 +1,31 @@
+/*
+ * Purpose: test example, verify the soundness of the vavgw operation.
+ *
+ * 0x00030001 averaged with 0x00010003 results 0x00020002.
+ */
+
+ .text
+ .globl _start
+
+_start:
+ {
+ r0 = #3
+ r1 = #1
+ }
+ {
+ r2 = #1
+ r3 = #3
+ }
+ {
+ r1:0 = vavgw(r1:0, r3:2):crnd
+ }
+ {
+ p0 = cmp.eq(r0, #2); if (p0.new) jump:t test2
+ jump fail
+ }
+
+test2:
+ {
+ p0 = cmp.eq(r1, #2); if (p0.new) jump:t pass
+ jump fail
+ }
diff --git a/tests/tcg/hexagon/test_vcmpb.S b/tests/tcg/hexagon/test_vcmpb.S
new file mode 100644
index 0000000000..66d253eb48
--- /dev/null
+++ b/tests/tcg/hexagon/test_vcmpb.S
@@ -0,0 +1,30 @@
+/*
+ * Purpose: test example, verify the soundness of the vector compare bytes
+ * operation.
+ *
+ * Vector byte comparison between 0x1234567887654321 and 0x1234567800000000
+ * should result in 0b11110000 in binary, or 0xf0 in hex.
+ */
+
+ .text
+ .globl _start
+
+_start:
+ {
+ r0 = #0x87654321
+ r1 = #0x12345678
+ }
+ {
+ r2 = #0x00000000
+ r3 = #0x12345678
+ }
+ {
+ p2 = vcmpb.eq(r1:0, r3:2)
+ }
+ {
+ r4 = p2
+ }
+ {
+ p0 = cmp.eq(r4, #0xf0); if (p0.new) jump:t pass
+ jump fail
+ }
diff --git a/tests/tcg/hexagon/test_vcmpw.S b/tests/tcg/hexagon/test_vcmpw.S
new file mode 100644
index 0000000000..5be88d1e2e
--- /dev/null
+++ b/tests/tcg/hexagon/test_vcmpw.S
@@ -0,0 +1,30 @@
+/*
+ * Purpose: test example, verify the soundness of the vector compare words
+ * operation.
+ *
+ * Vector word comparison between 0x1234567887654321 and 0x1234567800000000
+ * should result in 0b11110000 in binary, or 0xf0 in hex.
+ */
+
+ .text
+ .globl _start
+
+_start:
+ {
+ r0 = #0x87654321
+ r1 = #0x12345678
+ }
+ {
+ r2 = #0x00000000
+ r3 = #0x12345678
+ }
+ {
+ p2 = vcmpw.eq(r1:0, r3:2)
+ }
+ {
+ r4 = p2
+ }
+ {
+ p0 = cmp.eq(r4, #0xf0); if (p0.new) jump:t pass
+ jump fail
+ }
diff --git a/tests/tcg/hexagon/test_vlsrw.S b/tests/tcg/hexagon/test_vlsrw.S
new file mode 100644
index 0000000000..912e49aa0b
--- /dev/null
+++ b/tests/tcg/hexagon/test_vlsrw.S
@@ -0,0 +1,20 @@
+/* Purpose: test the soundness of the vlsrw operation */
+
+ .text
+ .globl _start
+
+_start:
+ {
+ r0 = #0x00000001
+ r1 = #0x00000001
+ }
+ {
+ r1:0 = vlsrw(r1:0, #1)
+ }
+ {
+ r0 = add(r0, r1)
+ }
+ {
+ p0 = cmp.eq(r0, #0); if (p0.new) jump:t pass
+ jump fail
+ }
diff --git a/tests/tcg/hexagon/test_vmaxh.S b/tests/tcg/hexagon/test_vmaxh.S
new file mode 100644
index 0000000000..4ea6bd9d96
--- /dev/null
+++ b/tests/tcg/hexagon/test_vmaxh.S
@@ -0,0 +1,35 @@
+/*
+ * Purpose: test example, verify the soundness of the vrmaxh operation.
+ *
+ * The maximum between 0x0002000300010005 and 0x0003000200020007 is
+ * 0x0003000300020007.
+ *
+ * input: r1 = 0x00010003 r0 = 0x00010005 r3 = 0x00030002 r2 = 0x00020007
+ * output: r1 = 0x00030003 r0 = 0x00020007
+ */
+
+ .text
+ .globl _start
+
+_start:
+ {
+ r0 = #65541
+ r1 = #65539
+ }
+ {
+ r2 = #131079
+ r3 = #196610
+ }
+ {
+ r1:0 = vmaxh(r1:0, r3:2)
+ }
+ {
+ p0 = cmp.eq(r0, #131079); if (p0.new) jump:t test2
+ jump fail
+ }
+
+test2:
+ {
+ p0 = cmp.eq(r1, #196611); if (p0.new) jump:t pass
+ jump fail
+ }
diff --git a/tests/tcg/hexagon/test_vminh.S b/tests/tcg/hexagon/test_vminh.S
new file mode 100644
index 0000000000..e5fcf2eb94
--- /dev/null
+++ b/tests/tcg/hexagon/test_vminh.S
@@ -0,0 +1,35 @@
+/*
+ * Purpose: test example, verify the soundness of the vrmaxh operation.
+ *
+ * The minimum between 0x0002000300010005 and 0x0003000200020007 is
+ * 0x0003000300020007.
+ *
+ * input: r1 = 0x00010003 r0 = 0x00010005 r3 = 0x00030002 r2 = 0x00020007
+ * output: r1 = 0x00010002 r0 = 0x00010005
+ */
+
+ .text
+ .globl _start
+
+_start:
+ {
+ r0 = #65541
+ r1 = #65539
+ }
+ {
+ r2 = #131079
+ r3 = #196610
+ }
+ {
+ r1:0 = vminh(r1:0, r3:2)
+ }
+ {
+ p0 = cmp.eq(r0, #65541); if (p0.new) jump:t test2
+ jump fail
+ }
+
+test2:
+ {
+ p0 = cmp.eq(r1, #65538); if (p0.new) jump:t pass
+ jump fail
+ }
diff --git a/tests/tcg/hexagon/test_vpmpyh.S b/tests/tcg/hexagon/test_vpmpyh.S
new file mode 100644
index 0000000000..f02758e449
--- /dev/null
+++ b/tests/tcg/hexagon/test_vpmpyh.S
@@ -0,0 +1,28 @@
+/*
+ * Purpose: test example, verify the soundness of the vpmpyh operator.
+ *
+ * 0x01020304 vector polynomial multiplied with 0x04030201 results
+ * 0x000400060b060b04.
+ */
+
+ .text
+ .globl _start
+
+_start:
+ {
+ r0 = #16909060
+ r1 = #67305985
+ }
+ {
+ r1:0 = vpmpyh(r0, r1)
+ }
+ {
+ p0 = cmp.eq(r0, #184945412); if (p0.new) jump:t test2
+ jump fail
+ }
+
+test2:
+ {
+ p0 = cmp.eq(r1, #262150); if (p0.new) jump:t pass
+ jump fail
+ }
diff --git a/tests/tcg/hexagon/test_vspliceb.S b/tests/tcg/hexagon/test_vspliceb.S
new file mode 100644
index 0000000000..53c4a91c51
--- /dev/null
+++ b/tests/tcg/hexagon/test_vspliceb.S
@@ -0,0 +1,31 @@
+/*
+ * Purpose: test example, verify the soundness of the vspliceb operation
+ * the operation is a binary splice of two 64bit operators.
+ *
+ * vspliceb(0xffffffffffffffff,0x0000000000000000,5) = 0x000000ffffffffff.
+ */
+ .text
+ .globl _start
+
+_start:
+ {
+ r0 = #-1
+ r1 = #-1
+ }
+ {
+ r2 = #0
+ r3 = #0
+ }
+ {
+ r5:4 = vspliceb(r1:0, r3:2, #5)
+ }
+ {
+ p0 = cmp.eq(r4, #-1); if (p0.new) jump:t test2
+ jump fail
+ }
+
+test2:
+ {
+ p0 = cmp.eq(r5, #255); if (p0.new) jump:t pass
+ jump fail
+ }
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* RE: [PATCH v8 05/12] target/hexagon: introduce new helper functions
2022-02-09 17:03 ` [PATCH v8 05/12] target/hexagon: introduce new helper functions Anton Johansson via
@ 2022-03-21 18:28 ` Taylor Simpson
0 siblings, 0 replies; 23+ messages in thread
From: Taylor Simpson @ 2022-03-21 18:28 UTC (permalink / raw)
To: Anton Johansson, qemu-devel
Cc: ale, Brian Cain, richard.henderson, babush, nizzo, Michael Lambert
> -----Original Message-----
> From: Anton Johansson <anjo@rev.ng>
> Sent: Wednesday, February 9, 2022 11:03 AM
> To: qemu-devel@nongnu.org
> Cc: ale@rev.ng; Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; Michael Lambert <mlambert@quicinc.com>;
> babush@rev.ng; nizzo@rev.ng; richard.henderson@linaro.org
> Subject: [PATCH v8 05/12] target/hexagon: introduce new helper functions
>
> From: Niccolò Izzo <nizzo@rev.ng>
>
> These helpers will be employed by the idef-parser generated code, to
> correctly implement instruction semantics. "Helper" functions, in the context
> of this patch, refers to functions which provide a manual TCG
> implementation of certain features.
>
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Niccolò Izzo <nizzo@rev.ng>
> Signed-off-by: Anton Johansson <anjo@rev.ng>
> ---
> target/hexagon/genptr.c | 167
> ++++++++++++++++++++++++++++++++++++++--
> target/hexagon/genptr.h | 16 +++-
> target/hexagon/macros.h | 9 +++
> 3 files changed, 184 insertions(+), 8 deletions(-)
Reviewed-by: Taylor Simpson <tsimpson@quicinc.com>
^ permalink raw reply [flat|nested] 23+ messages in thread
* RE: [PATCH v8 07/12] target/hexagon: prepare input for the idef-parser
2022-02-09 17:03 ` [PATCH v8 07/12] target/hexagon: prepare input for the idef-parser Anton Johansson via
@ 2022-03-21 18:33 ` Taylor Simpson
0 siblings, 0 replies; 23+ messages in thread
From: Taylor Simpson @ 2022-03-21 18:33 UTC (permalink / raw)
To: Anton Johansson, qemu-devel
Cc: ale, Brian Cain, richard.henderson, babush, nizzo, Michael Lambert
> -----Original Message-----
> From: Anton Johansson <anjo@rev.ng>
> Sent: Wednesday, February 9, 2022 11:03 AM
> To: qemu-devel@nongnu.org
> Cc: ale@rev.ng; Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; Michael Lambert <mlambert@quicinc.com>;
> babush@rev.ng; nizzo@rev.ng; richard.henderson@linaro.org
> Subject: [PATCH v8 07/12] target/hexagon: prepare input for the idef-parser
>
> From: Alessandro Di Federico <ale@rev.ng>
>
> Introduce infrastructure necessary to produce a file suitable for being parsed
> by the idef-parser.
>
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Anton Johansson <anjo@rev.ng>
> ---
> target/hexagon/gen_idef_parser_funcs.py | 125
> +++++++++++++++++++++
> target/hexagon/idef-parser/macros.inc | 140
> ++++++++++++++++++++++++
> target/hexagon/idef-parser/prepare | 24 ++++
> target/hexagon/meson.build | 17 +++
> 4 files changed, 306 insertions(+)
> create mode 100644 target/hexagon/gen_idef_parser_funcs.py
> create mode 100644 target/hexagon/idef-parser/macros.inc
> create mode 100755 target/hexagon/idef-parser/prepare
Reviewed-by: Taylor Simpson <tsimpson@quicinc.com>
^ permalink raw reply [flat|nested] 23+ messages in thread
* RE: [PATCH v8 09/12] target/hexagon: import lexer for idef-parser
2022-02-09 17:03 ` [PATCH v8 09/12] target/hexagon: import lexer for idef-parser Anton Johansson via
@ 2022-03-21 18:40 ` Taylor Simpson
0 siblings, 0 replies; 23+ messages in thread
From: Taylor Simpson @ 2022-03-21 18:40 UTC (permalink / raw)
To: Anton Johansson, qemu-devel
Cc: ale, Brian Cain, richard.henderson, babush, nizzo, Michael Lambert
> -----Original Message-----
> From: Anton Johansson <anjo@rev.ng>
> Sent: Wednesday, February 9, 2022 11:03 AM
> To: qemu-devel@nongnu.org
> Cc: ale@rev.ng; Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; Michael Lambert <mlambert@quicinc.com>;
> babush@rev.ng; nizzo@rev.ng; richard.henderson@linaro.org
> Subject: [PATCH v8 09/12] target/hexagon: import lexer for idef-parser
>
> From: Paolo Montesel <babush@rev.ng>
>
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Paolo Montesel <babush@rev.ng>
> Signed-off-by: Anton Johansson <anjo@rev.ng>
> ---
> target/hexagon/idef-parser/idef-parser.h | 254 +++++++++
> target/hexagon/idef-parser/idef-parser.lex | 566
> +++++++++++++++++++++
> target/hexagon/meson.build | 4 +
> 3 files changed, 824 insertions(+)
> create mode 100644 target/hexagon/idef-parser/idef-parser.h
> create mode 100644 target/hexagon/idef-parser/idef-parser.lex
Reviewed-by: Taylor Simpson <tsimpson@quicinc.com>
^ permalink raw reply [flat|nested] 23+ messages in thread
* RE: [PATCH v8 12/12] target/hexagon: import additional tests
2022-02-09 17:03 ` [PATCH v8 12/12] target/hexagon: import additional tests Anton Johansson via
@ 2022-03-21 18:58 ` Taylor Simpson
0 siblings, 0 replies; 23+ messages in thread
From: Taylor Simpson @ 2022-03-21 18:58 UTC (permalink / raw)
To: Anton Johansson, qemu-devel
Cc: ale, Brian Cain, richard.henderson, babush, nizzo, Michael Lambert
> -----Original Message-----
> From: Anton Johansson <anjo@rev.ng>
> Sent: Wednesday, February 9, 2022 11:03 AM
> To: qemu-devel@nongnu.org
> Cc: ale@rev.ng; Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; Michael Lambert <mlambert@quicinc.com>;
> babush@rev.ng; nizzo@rev.ng; richard.henderson@linaro.org
> Subject: [PATCH v8 12/12] target/hexagon: import additional tests
>
> From: Niccolò Izzo <nizzo@rev.ng>
>
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Niccolò Izzo <nizzo@rev.ng>
> Signed-off-by: Anton Johansson <anjo@rev.ng>
> ---
> tests/tcg/hexagon/Makefile.target | 28 ++++++++++++-
> tests/tcg/hexagon/crt.S | 14 +++++++
> tests/tcg/hexagon/test_abs.S | 17 ++++++++
> tests/tcg/hexagon/test_bitcnt.S | 40 +++++++++++++++++++
> tests/tcg/hexagon/test_bitsplit.S | 22 ++++++++++
> tests/tcg/hexagon/test_call.S | 64 ++++++++++++++++++++++++++++++
> tests/tcg/hexagon/test_clobber.S | 29 ++++++++++++++
> tests/tcg/hexagon/test_cmp.S | 31 +++++++++++++++
> tests/tcg/hexagon/test_dotnew.S | 38 ++++++++++++++++++
> tests/tcg/hexagon/test_ext.S | 13 ++++++
> tests/tcg/hexagon/test_fibonacci.S | 30 ++++++++++++++
> tests/tcg/hexagon/test_hl.S | 16 ++++++++
> tests/tcg/hexagon/test_hwloops.S | 19 +++++++++
> tests/tcg/hexagon/test_jmp.S | 22 ++++++++++
> tests/tcg/hexagon/test_lsr.S | 36 +++++++++++++++++
> tests/tcg/hexagon/test_mpyi.S | 17 ++++++++
> tests/tcg/hexagon/test_packet.S | 29 ++++++++++++++
> tests/tcg/hexagon/test_reorder.S | 33 +++++++++++++++
> tests/tcg/hexagon/test_round.S | 29 ++++++++++++++
> tests/tcg/hexagon/test_vavgw.S | 31 +++++++++++++++
> tests/tcg/hexagon/test_vcmpb.S | 30 ++++++++++++++
> tests/tcg/hexagon/test_vcmpw.S | 30 ++++++++++++++
> tests/tcg/hexagon/test_vlsrw.S | 20 ++++++++++
> tests/tcg/hexagon/test_vmaxh.S | 35 ++++++++++++++++
> tests/tcg/hexagon/test_vminh.S | 35 ++++++++++++++++
> tests/tcg/hexagon/test_vpmpyh.S | 28 +++++++++++++
> tests/tcg/hexagon/test_vspliceb.S | 31 +++++++++++++++
> 27 files changed, 766 insertions(+), 1 deletion(-) create mode 100644
> tests/tcg/hexagon/crt.S create mode 100644 tests/tcg/hexagon/test_abs.S
> create mode 100644 tests/tcg/hexagon/test_bitcnt.S create mode 100644
> tests/tcg/hexagon/test_bitsplit.S create mode 100644
> tests/tcg/hexagon/test_call.S create mode 100644
> tests/tcg/hexagon/test_clobber.S create mode 100644
> tests/tcg/hexagon/test_cmp.S create mode 100644
> tests/tcg/hexagon/test_dotnew.S create mode 100644
> tests/tcg/hexagon/test_ext.S create mode 100644
> tests/tcg/hexagon/test_fibonacci.S
> create mode 100644 tests/tcg/hexagon/test_hl.S create mode 100644
> tests/tcg/hexagon/test_hwloops.S create mode 100644
> tests/tcg/hexagon/test_jmp.S create mode 100644
> tests/tcg/hexagon/test_lsr.S create mode 100644
> tests/tcg/hexagon/test_mpyi.S create mode 100644
> tests/tcg/hexagon/test_packet.S create mode 100644
> tests/tcg/hexagon/test_reorder.S create mode 100644
> tests/tcg/hexagon/test_round.S create mode 100644
> tests/tcg/hexagon/test_vavgw.S create mode 100644
> tests/tcg/hexagon/test_vcmpb.S create mode 100644
> tests/tcg/hexagon/test_vcmpw.S create mode 100644
> tests/tcg/hexagon/test_vlsrw.S create mode 100644
> tests/tcg/hexagon/test_vmaxh.S create mode 100644
> tests/tcg/hexagon/test_vminh.S create mode 100644
> tests/tcg/hexagon/test_vpmpyh.S create mode 100644
> tests/tcg/hexagon/test_vspliceb.S
Reviewed-by: Taylor Simpson <tsimpson@quicinc.com>
^ permalink raw reply [flat|nested] 23+ messages in thread
* RE: [PATCH v8 10/12] target/hexagon: import parser for idef-parser
2022-02-09 17:03 ` [PATCH v8 10/12] target/hexagon: import parser " Anton Johansson via
@ 2022-04-11 15:20 ` Taylor Simpson
2022-04-12 15:10 ` Anton Johansson via
0 siblings, 1 reply; 23+ messages in thread
From: Taylor Simpson @ 2022-04-11 15:20 UTC (permalink / raw)
To: Anton Johansson, qemu-devel
Cc: ale, Brian Cain, richard.henderson, babush, nizzo, Michael Lambert
> -----Original Message-----
> From: Anton Johansson <anjo@rev.ng>
> Sent: Wednesday, February 9, 2022 11:03 AM
> To: qemu-devel@nongnu.org
> Cc: ale@rev.ng; Taylor Simpson <tsimpson@quicinc.com>; Brian Cain
> <bcain@quicinc.com>; Michael Lambert <mlambert@quicinc.com>;
> babush@rev.ng; nizzo@rev.ng; richard.henderson@linaro.org
> Subject: [PATCH v8 10/12] target/hexagon: import parser for idef-parser
>
> Signed-off-by: Alessandro Di Federico <ale@rev.ng>
> Signed-off-by: Paolo Montesel <babush@rev.ng>
> Signed-off-by: Anton Johansson <anjo@rev.ng>
> diff --git a/target/hexagon/idef-parser/parser-helpers.c
> b/target/hexagon/idef-parser/parser-helpers.c
> new file mode 100644
> +void gen_set_overflow(Context *c, YYLTYPE *locp, HexValue *value)
> +{
> + HexValue value_m = *value;
> +
> + if (is_inside_ternary(c)) {
> + /* Inside ternary operator, need to take care of the side-effect */
> + HexValue cond = get_ternary_cond(c, locp);
> + HexValue zero = gen_constant(c, locp, "0", cond.bit_width,
> UNSIGNED);
> + bool is_64bit = cond.bit_width == 64;
> + unsigned bit_width = cond.bit_width;
> + value_m = rvalue_materialize(c, locp, &value_m);
> + if (is_64bit) {
> + value_m = gen_rvalue_extend(c, locp, &value_m);
> + }
> + OUT(c, locp, "tcg_gen_movcond_i", &bit_width,
> + "(TCG_COND_NE, ", &value_m, ", ", &cond);
> + OUT(c, locp, ", ", &zero, ", ", &value_m, ", ", &zero, ");\n");
You shouldn't write zero when the condition is false - you should do nothing. Try a test where OVF is already set. You can't overwrite the bit with zero when the current instruction doesn't overflow.
> + if (is_64bit) {
> + value_m = gen_rvalue_truncate(c, locp, &value_m);
> + }
> + gen_rvalue_free(c, locp, &cond);
> + }
> +
> + OUT(c, locp, "SET_USR_FIELD(USR_OVF, ", &value_m, ");\n");
> + gen_rvalue_free(c, locp, &value_m);
> +}
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v8 10/12] target/hexagon: import parser for idef-parser
2022-04-11 15:20 ` Taylor Simpson
@ 2022-04-12 15:10 ` Anton Johansson via
2022-04-12 18:41 ` Taylor Simpson
0 siblings, 1 reply; 23+ messages in thread
From: Anton Johansson via @ 2022-04-12 15:10 UTC (permalink / raw)
To: Taylor Simpson, qemu-devel
Cc: ale, Brian Cain, Michael Lambert, babush, nizzo, richard.henderson
[-- Attachment #1: Type: text/plain, Size: 2896 bytes --]
Very nice catch, this is the bug that plagued us a few weeks ago when
rebasing,
it has since been fixed. Actually the `gen_set_overflow` fucntion has
been removed
completely as it was only called when we handled `asl/asr_r_r_sat`.
Current way we handle overflow:
Overflow is now only set by saturates, this assumption holds for the
instructions
we parse in phase 1. In the parser, all saturates call `gen_rvalue_sat`
which emits
a call to `gen_set_usr_field_if` in `genptr.c` to set USR_OVF only if
the value is
non-zero. It does this via OR'ing with the previous value.
See here
<https://gitlab.com/AntonJohansson/qemu/-/blob/feature/idef-parser/target/hexagon/idef-parser/parser-helpers.c#L2109>
for `gen_rvalue_sat`
and here
<https://gitlab.com/AntonJohansson/qemu/-/blob/feature/idef-parser/target/hexagon/genptr.c#L669>
for `gen_set_usr_field_if`
>
>> -----Original Message-----
>> From: Anton Johansson<anjo@rev.ng>
>> Sent: Wednesday, February 9, 2022 11:03 AM
>> To:qemu-devel@nongnu.org
>> Cc:ale@rev.ng; Taylor Simpson<tsimpson@quicinc.com>; Brian Cain
>> <bcain@quicinc.com>; Michael Lambert<mlambert@quicinc.com>;
>> babush@rev.ng;nizzo@rev.ng;richard.henderson@linaro.org
>> Subject: [PATCH v8 10/12] target/hexagon: import parser for idef-parser
>>
>> Signed-off-by: Alessandro Di Federico<ale@rev.ng>
>> Signed-off-by: Paolo Montesel<babush@rev.ng>
>> Signed-off-by: Anton Johansson<anjo@rev.ng>
>
>> diff --git a/target/hexagon/idef-parser/parser-helpers.c
>> b/target/hexagon/idef-parser/parser-helpers.c
>> new file mode 100644
>
>
>> +void gen_set_overflow(Context *c, YYLTYPE *locp, HexValue *value)
>> +{
>> + HexValue value_m = *value;
>> +
>> + if (is_inside_ternary(c)) {
>> + /* Inside ternary operator, need to take care of the side-effect */
>> + HexValue cond = get_ternary_cond(c, locp);
>> + HexValue zero = gen_constant(c, locp, "0", cond.bit_width,
>> UNSIGNED);
>> + bool is_64bit = cond.bit_width == 64;
>> + unsigned bit_width = cond.bit_width;
>> + value_m = rvalue_materialize(c, locp, &value_m);
>> + if (is_64bit) {
>> + value_m = gen_rvalue_extend(c, locp, &value_m);
>> + }
>> + OUT(c, locp, "tcg_gen_movcond_i", &bit_width,
>> + "(TCG_COND_NE, ", &value_m, ", ", &cond);
>> + OUT(c, locp, ", ", &zero, ", ", &value_m, ", ", &zero, ");\n");
> You shouldn't write zero when the condition is false - you should do nothing. Try a test where OVF is already set. You can't overwrite the bit with zero when the current instruction doesn't overflow.
>
>
>
>> + if (is_64bit) {
>> + value_m = gen_rvalue_truncate(c, locp, &value_m);
>> + }
>> + gen_rvalue_free(c, locp, &cond);
>> + }
>> +
>> + OUT(c, locp, "SET_USR_FIELD(USR_OVF, ", &value_m, ");\n");
>> + gen_rvalue_free(c, locp, &value_m);
>> +}
[-- Attachment #2: Type: text/html, Size: 4983 bytes --]
^ permalink raw reply [flat|nested] 23+ messages in thread
* RE: [PATCH v8 10/12] target/hexagon: import parser for idef-parser
2022-04-12 15:10 ` Anton Johansson via
@ 2022-04-12 18:41 ` Taylor Simpson
2022-04-21 11:50 ` Anton Johansson via
0 siblings, 1 reply; 23+ messages in thread
From: Taylor Simpson @ 2022-04-12 18:41 UTC (permalink / raw)
To: anjo, qemu-devel
Cc: ale, Brian Cain, richard.henderson, babush, nizzo, Michael Lambert
> From: Anton Johansson <anjo@rev.ng>
> Sent: Tuesday, April 12, 2022 10:11 AM
> To: Taylor Simpson <tsimpson@quicinc.com>; qemu-devel@nongnu.org
> Cc: ale@rev.ng; Brian Cain <bcain@quicinc.com>; Michael Lambert <mlambert@quicinc.com>; babush@rev.ng; nizzo@rev.ng; richard.henderson@linaro.org
> Subject: Re: [PATCH v8 10/12] target/hexagon: import parser for idef-parser
>
> Very nice catch, this is the bug that plagued us a few weeks ago when rebasing,
> it has since been fixed. Actually the `gen_set_overflow` fucntion has been removed
> completely as it was only called when we handled `asl/asr_r_r_sat`.
> Current way we handle overflow:
>
> Overflow is now only set by saturates, this assumption holds for the instructions
> we parse in phase 1. In the parser, all saturates call `gen_rvalue_sat` which emits
> a call to `gen_set_usr_field_if` in `genptr.c` to set USR_OVF only if the value is
> non-zero. It does this via OR'ing with the previous value.
>
> See https://gitlab.com/AntonJohansson/qemu/-/blob/feature/idef-parser/target/hexagon/idef-parser/parser-helpers.c#L2109 for `gen_rvalue_sat`
> and https://gitlab.com/AntonJohansson/qemu/-/blob/feature/idef-parser/target/hexagon/genptr.c#L669 for `gen_set_usr_field_if`
Your implementation of gen_set_usr_field_if is not correct. Don't extract the bits from the value based on the reg_field_info. The easiest thing to do is compare val with zero and jump over a call to gen_set_usr_field. If you are determined to do an "or", you have to assert that ref_field_info[field].width == 1. Then, you can extract 1 bit from val starting at offset zero and shift the result left by ref_field_info[field].offset and then "or" with USR.
Thanks,
Taylor
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v8 10/12] target/hexagon: import parser for idef-parser
2022-04-12 18:41 ` Taylor Simpson
@ 2022-04-21 11:50 ` Anton Johansson via
2022-04-21 14:22 ` Taylor Simpson
0 siblings, 1 reply; 23+ messages in thread
From: Anton Johansson via @ 2022-04-21 11:50 UTC (permalink / raw)
To: Taylor Simpson, qemu-devel
Cc: ale, Brian Cain, Michael Lambert, babush, nizzo, richard.henderson
Here's an updated version of `gen_set_usr_field_If`
https://gitlab.com/AntonJohansson/qemu/-/blob/feature/idef-parser/target/hexagon/genptr.c#L673
If this looks alright and we have your "reviewed-by" on this patch, I'll
go ahead and submit the new
patchset! :)
--
Anton Johansson,
rev.ng Labs Srl.
>
>> From: Anton Johansson <anjo@rev.ng>
>> Sent: Tuesday, April 12, 2022 10:11 AM
>> To: Taylor Simpson <tsimpson@quicinc.com>; qemu-devel@nongnu.org
>> Cc: ale@rev.ng; Brian Cain <bcain@quicinc.com>; Michael Lambert <mlambert@quicinc.com>; babush@rev.ng; nizzo@rev.ng; richard.henderson@linaro.org
>> Subject: Re: [PATCH v8 10/12] target/hexagon: import parser for idef-parser
>>
>> Very nice catch, this is the bug that plagued us a few weeks ago when rebasing,
>> it has since been fixed. Actually the `gen_set_overflow` fucntion has been removed
>> completely as it was only called when we handled `asl/asr_r_r_sat`.
>> Current way we handle overflow:
>>
>> Overflow is now only set by saturates, this assumption holds for the instructions
>> we parse in phase 1. In the parser, all saturates call `gen_rvalue_sat` which emits
>> a call to `gen_set_usr_field_if` in `genptr.c` to set USR_OVF only if the value is
>> non-zero. It does this via OR'ing with the previous value.
>>
>> See https://gitlab.com/AntonJohansson/qemu/-/blob/feature/idef-parser/target/hexagon/idef-parser/parser-helpers.c#L2109 for `gen_rvalue_sat`
>> and https://gitlab.com/AntonJohansson/qemu/-/blob/feature/idef-parser/target/hexagon/genptr.c#L669 for `gen_set_usr_field_if`
> Your implementation of gen_set_usr_field_if is not correct. Don't extract the bits from the value based on the reg_field_info. The easiest thing to do is compare val with zero and jump over a call to gen_set_usr_field. If you are determined to do an "or", you have to assert that ref_field_info[field].width == 1. Then, you can extract 1 bit from val starting at offset zero and shift the result left by ref_field_info[field].offset and then "or" with USR.
>
> Thanks,
> Taylor
^ permalink raw reply [flat|nested] 23+ messages in thread
* RE: [PATCH v8 10/12] target/hexagon: import parser for idef-parser
2022-04-21 11:50 ` Anton Johansson via
@ 2022-04-21 14:22 ` Taylor Simpson
2022-04-21 16:38 ` Anton Johansson via
0 siblings, 1 reply; 23+ messages in thread
From: Taylor Simpson @ 2022-04-21 14:22 UTC (permalink / raw)
To: anjo, qemu-devel
Cc: ale, Brian Cain, richard.henderson, babush, nizzo, Michael Lambert
> -----Original Message-----
> From: Anton Johansson <anjo@rev.ng>
> Sent: Thursday, April 21, 2022 6:51 AM
> To: Taylor Simpson <tsimpson@quicinc.com>; qemu-devel@nongnu.org
> Cc: ale@rev.ng; Brian Cain <bcain@quicinc.com>; Michael Lambert
> <mlambert@quicinc.com>; babush@rev.ng; nizzo@rev.ng;
> richard.henderson@linaro.org
> Subject: Re: [PATCH v8 10/12] target/hexagon: import parser for idef-parser
>
>
> Here's an updated version of `gen_set_usr_field_If`
>
> https://gitlab.com/AntonJohansson/qemu/-/blob/feature/idef-
> parser/target/hexagon/genptr.c#L673
>
> If this looks alright and we have your "reviewed-by" on this patch, I'll go
> ahead and submit the new patchset! :)
> /*
> * Note: Since this function might branch, `val` is
> * required to be a `tcg_temp_local`.
> */
> void gen_set_usr_field_if(int field, TCGv val)
> {
> /* Sets the USR field if `val` is non-zero */
> if (false && reg_field_info[field].width == 1) {
Remove the "false &&"
Otherwise
Reviewed-by: Taylor Simpson <tsimpson@quicinc.com>
> TCGv tmp = tcg_temp_new();
> tcg_gen_extract_tl(tmp, val, 0, reg_field_info[field].width);
> tcg_gen_shli_tl(tmp, tmp, reg_field_info[field].offset);
> tcg_gen_or_tl(hex_new_value[HEX_REG_USR],
> hex_new_value[HEX_REG_USR],
> tmp);
> tcg_temp_free(tmp);
> } else {
> TCGLabel *skip_label = gen_new_label();
> tcg_gen_brcondi_tl(TCG_COND_EQ, val, 0, skip_label);
> gen_set_usr_field(field, val);
> gen_set_label(skip_label);
> }
> }
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v8 10/12] target/hexagon: import parser for idef-parser
2022-04-21 14:22 ` Taylor Simpson
@ 2022-04-21 16:38 ` Anton Johansson via
0 siblings, 0 replies; 23+ messages in thread
From: Anton Johansson via @ 2022-04-21 16:38 UTC (permalink / raw)
To: Taylor Simpson, qemu-devel
Cc: ale, Brian Cain, Michael Lambert, babush, nizzo, richard.henderson
>
>> -----Original Message-----
>> From: Anton Johansson <anjo@rev.ng>
>> Sent: Thursday, April 21, 2022 6:51 AM
>> To: Taylor Simpson <tsimpson@quicinc.com>; qemu-devel@nongnu.org
>> Cc: ale@rev.ng; Brian Cain <bcain@quicinc.com>; Michael Lambert
>> <mlambert@quicinc.com>; babush@rev.ng; nizzo@rev.ng;
>> richard.henderson@linaro.org
>> Subject: Re: [PATCH v8 10/12] target/hexagon: import parser for idef-parser
>>
>>
>> Here's an updated version of `gen_set_usr_field_If`
>>
>> https://gitlab.com/AntonJohansson/qemu/-/blob/feature/idef-
>> parser/target/hexagon/genptr.c#L673
>>
>> If this looks alright and we have your "reviewed-by" on this patch, I'll go
>> ahead and submit the new patchset! :)
>> /*
>> * Note: Since this function might branch, `val` is
>> * required to be a `tcg_temp_local`.
>> */
>> void gen_set_usr_field_if(int field, TCGv val)
>> {
>> /* Sets the USR field if `val` is non-zero */
>> if (false && reg_field_info[field].width == 1) {
> Remove the "false &&"
>
> Otherwise
> Reviewed-by: Taylor Simpson <tsimpson@quicinc.com>
Ah ofc! Remnant of testing. Fixed.
I'll rebase and run the usual pre-submit tests once again.
>
>
>> TCGv tmp = tcg_temp_new();
>> tcg_gen_extract_tl(tmp, val, 0, reg_field_info[field].width);
>> tcg_gen_shli_tl(tmp, tmp, reg_field_info[field].offset);
>> tcg_gen_or_tl(hex_new_value[HEX_REG_USR],
>> hex_new_value[HEX_REG_USR],
>> tmp);
>> tcg_temp_free(tmp);
>> } else {
>> TCGLabel *skip_label = gen_new_label();
>> tcg_gen_brcondi_tl(TCG_COND_EQ, val, 0, skip_label);
>> gen_set_usr_field(field, val);
>> gen_set_label(skip_label);
>> }
>> }
^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2022-04-21 17:00 UTC | newest]
Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-09 17:03 [PATCH v8 00/12] target/hexagon: introduce idef-parser Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 01/12] target/hexagon: update MAINTAINERS for idef-parser Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 02/12] target/hexagon: import README " Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 03/12] target/hexagon: make slot number an unsigned Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 04/12] target/hexagon: make helper functions non-static Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 05/12] target/hexagon: introduce new helper functions Anton Johansson via
2022-03-21 18:28 ` Taylor Simpson
2022-02-09 17:03 ` [PATCH v8 06/12] target/hexagon: expose next PC in DisasContext Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 07/12] target/hexagon: prepare input for the idef-parser Anton Johansson via
2022-03-21 18:33 ` Taylor Simpson
2022-02-09 17:03 ` [PATCH v8 08/12] target/hexagon: import flex/bison to docker files Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 09/12] target/hexagon: import lexer for idef-parser Anton Johansson via
2022-03-21 18:40 ` Taylor Simpson
2022-02-09 17:03 ` [PATCH v8 10/12] target/hexagon: import parser " Anton Johansson via
2022-04-11 15:20 ` Taylor Simpson
2022-04-12 15:10 ` Anton Johansson via
2022-04-12 18:41 ` Taylor Simpson
2022-04-21 11:50 ` Anton Johansson via
2022-04-21 14:22 ` Taylor Simpson
2022-04-21 16:38 ` Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 11/12] target/hexagon: call idef-parser functions Anton Johansson via
2022-02-09 17:03 ` [PATCH v8 12/12] target/hexagon: import additional tests Anton Johansson via
2022-03-21 18:58 ` Taylor Simpson
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.