xref: /qemu/target/hexagon/idef-parser/README.rst (revision c3bef3b4)
1Hexagon ISA instruction definitions to tinycode generator compiler
2------------------------------------------------------------------
3
4idef-parser is a small compiler able to translate the Hexagon ISA description
5language into tinycode generator code, that can be easily integrated into QEMU.
6
7Compilation Example
8-------------------
9
10To better understand the scope of the idef-parser, we'll explore an applicative
11example. Let's start by one of the simplest Hexagon instruction: the ``add``.
12
13The ISA description language represents the ``add`` instruction as
14follows:
15
16.. code:: c
17
18   A2_add(RdV, in RsV, in RtV) {
19       { RdV=RsV+RtV;}
20   }
21
22idef-parser will compile the above code into the following code:
23
24.. code:: c
25
26   /* A2_add */
27   void emit_A2_add(DisasContext *ctx, Insn *insn, Packet *pkt, TCGv_i32 RdV,
28                    TCGv_i32 RsV, TCGv_i32 RtV)
29   /*  { RdV=RsV+RtV;} */
30   {
31       TCGv_i32 tmp_0 = tcg_temp_new_i32();
32       tcg_gen_add_i32(tmp_0, RsV, RtV);
33       tcg_gen_mov_i32(RdV, tmp_0);
34       tcg_temp_free_i32(tmp_0);
35   }
36
37The output of the compilation process will be a function, containing the
38tinycode generator code, implementing the correct semantics. That function will
39not access any global variable, because all the accessed data structures will be
40passed explicitly as function parameters. Among the passed parameters we will
41have TCGv (tinycode variables) representing the input and output registers of
42the architecture, integers representing the immediates that come from the code,
43and other data structures which hold information about the disassemblation
44context (``DisasContext`` struct).
45
46Let's begin by describing the input code. The ``add`` instruction is associated
47with a unique identifier, in this case ``A2_add``, which allows to distinguish
48variants of the same instruction, and expresses the class to which the
49instruction belongs, in this case ``A2`` corresponds to the Hexagon
50``ALU32/ALU`` instruction subclass.
51
52After the instruction identifier, we have a series of parameters that represents
53TCG variables that will be passed to the generated function. Parameters marked
54with ``in`` are already initialized, while the others are output parameters.
55
56We will leverage this information to infer several information:
57
58-  Fill in the output function signature with the correct TCGv registers
59-  Fill in the output function signature with the immediate integers
60-  Keep track of which registers, among the declared one, have been
61   initialized
62
63Let's now observe the actual instruction description code, in this case:
64
65.. code:: c
66
67   { RdV=RsV+RtV;}
68
69This code is composed by a subset of the C syntax, and is the result of the
70application of some macro definitions contained in the ``macros.h`` file.
71
72This file is used to reduce the complexity of the input language where complex
73variants of similar constructs can be mapped to a unique primitive, so that the
74idef-parser has to handle a lower number of computation primitives.
75
76As you may notice, the description code modifies the registers which have been
77declared by the declaration statements. In this case all the three registers
78will be declared, ``RsV`` and ``RtV`` will also be read and ``RdV`` will be
79written.
80
81Now let's have a quick look at the generated code, line by line.
82
83::
84
85   TCGv_i32 tmp_0 = tcg_temp_new_i32();
86
87This code starts by declaring a temporary TCGv to hold the result from the sum
88operation.
89
90::
91
92   tcg_gen_add_i32(tmp_0, RsV, RtV);
93
94Then, we are generating the sum tinycode operator between the selected
95registers, storing the result in the just declared temporary.
96
97::
98
99   tcg_gen_mov_i32(RdV, tmp_0);
100
101The result of the addition is now stored in the temporary, we move it into the
102correct destination register. This code may seem inefficient, but QEMU will
103perform some optimizations on the tinycode, reducing the unnecessary copy.
104
105::
106
107   tcg_temp_free_i32(tmp_0);
108
109Finally, we free the temporary we used to hold the addition result.
110
111Parser Input
112------------
113
114Before moving on to the structure of idef-parser itself, let us spend some words
115on its' input. There are two preprocessing steps applied to the generated
116instruction semantics in ``semantics_generated.pyinc`` that we need to consider.
117Firstly,
118
119::
120
121    gen_idef_parser_funcs.py
122
123which takes instruction semantics in ``semantics_generated.pyinc`` to C-like
124pseudo code, output into ``idef_parser_input.h.inc``. For instance, the
125``J2_jumpr`` instruction which jumps to an address stored in a register
126argument. This is instruction is defined as
127
128::
129
130    SEMANTICS( \
131        "J2_jumpr", \
132        "jumpr Rs32", \
133        """{fJUMPR(RsN,RsV,COF_TYPE_JUMPR);}""" \
134    )
135
136in ``semantics_generated.pyinc``. Running ``gen_idef_parser_funcs.py``
137we obtain the pseudo code
138
139::
140
141    J2_jumpr(in RsV) {
142        {fJUMPR(RsN,RsV,COF_TYPE_JUMPR);}
143    }
144
145with macros such as ``fJUMPR`` intact.
146
147The second step is to expand macros into a form suitable for our parser.
148These macros are defined in ``idef-parser/macros.inc`` and the step is
149carried out by the ``prepare`` script which runs the C preprocessor on
150``idef_parser_input.h.inc`` to produce
151``idef_parser_input.preprocessed.h.inc``.
152
153To finish the above example, after preprocessing ``J2_jumpr`` we obtain
154
155::
156
157    J2_jumpr(in RsV) {
158        {(PC = RsV);}
159    }
160
161where ``fJUMPR(RsN,RsV,COF_TYPE_JUMPR);`` was expanded to ``(PC = RsV)``,
162signifying a write to the Program Counter ``PC``.  Note, that ``PC`` in
163this expression is not a variable in the strict C sense since it is not
164declared anywhere, but rather a symbol which is easy to match in
165idef-parser later on.
166
167Parser Structure
168----------------
169
170The idef-parser is built using the ``flex`` and ``bison``.
171
172``flex`` is used to split the input string into tokens, each described using a
173regular expression. The token description is contained in the
174``idef-parser.lex`` source file. The flex-generated scanner takes care also to
175extract from the input text other meaningful information, e.g., the numerical
176value in case of an immediate constant, and decorates the token with the
177extracted information.
178
179``bison`` is used to generate the actual parser, starting from the parsing
180description contained in the ``idef-parser.y`` file. The generated parser
181executes the ``main`` function at the end of the ``idef-parser.y`` file, which
182opens input and output files, creates the parsing context, and eventually calls
183the ``yyparse()`` function, which starts the execution of the LALR(1) parser
184(see `Wikipedia <https://en.wikipedia.org/wiki/LALR_parser>`__ for more
185information about LALR parsing techniques). The LALR(1) parser, whenever it has
186to shift a token, calls the ``yylex()`` function, which is defined by the
187flex-generated code, and reads the input file returning the next scanned token.
188
189The tokens are mapped on the source language grammar, defined in the
190``idef-parser.y`` file to build a unique syntactic tree, according to the
191specified operator precedences and associativity rules.
192
193The grammar describes the whole file which contains the Hexagon instruction
194descriptions, therefore it starts from the ``input`` nonterminal, which is a
195list of instructions, each instruction is represented by the following grammar
196rule, representing the structure of the input file shown above:
197
198::
199
200   instruction : INAME arguments code
201               | error
202
203   arguments : '(' ')'
204             | '(' argument_list ')';
205
206   argument_list : argument_decl ',' argument_list
207                 | argument_decl
208
209   argument_decl : REG
210                 | PRED
211                 | IN REG
212                 | IN PRED
213                 | IMM
214                 | var
215                 ;
216
217   code        : '{' statements '}'
218
219   statements  : statements statement
220               | statement
221
222   statement   : control_statement
223               | var_decl ';'
224               | rvalue ';'
225               | code_block
226               | ';'
227
228   code_block  : '{' statements '}'
229               | '{' '}'
230
231With this initial portion of the grammar we are defining the instruction, its'
232arguments, and its' statements. Each argument is defined by the
233``argument_decl`` rule, and can be either
234
235::
236
237    Description                  Example
238    ----------------------------------------
239    output register              RsV
240    output predicate register    P0
241    input register               in RsV
242    input predicate register     in P0
243    immediate value              1234
244    local variable               EA
245
246Note, the only local variable allowed to be used as an argument is the effective
247address ``EA``. Similarly, each statement can be a ``control_statement``, a
248variable declaration such as ``int a;``, a code block, which is just a
249bracket-enclosed list of statements, a ``';'``, which is a ``nop`` instruction,
250and an ``rvalue ';'``.
251
252Expressions
253~~~~~~~~~~~
254
255Allowed in the input code are C language expressions with a few exceptions
256to simplify parsing. For instance, variable names such as ``RdV``, ``RssV``,
257``PdV``, ``CsV``, and other idiomatic register names from Hexagon, are
258reserved specifically for register arguments. These arguments then map to
259``TCGv_i32`` or ``TCGv_i64`` depending on the register size. Similarly, ``UiV``,
260``riV``, etc. refer to immediate arguments and will map to C integers.
261
262Also, as mentioned earlier, the names ``PC``, ``SP``, ``FP``, etc. are used to
263refer to Hexagon registers such as the program counter, stack pointer, and frame
264pointer seen here. Writes to these registers then correspond to assignments
265``PC = ...``, and reads correspond to uses of the variable ``PC``.
266
267Moreover, another example of one such exception is the selective expansion of
268macros present in ``macros.h``. As an example, consider the ``fABS`` macro which
269in plain C is defined as
270
271::
272
273    #define fABS(A) (((A) < 0) ? (-(A)) : (A))
274
275and returns the absolute value of the argument ``A``. This macro is not included
276in ``idef-parser/macros.inc`` and as such is not expanded and kept as a "call"
277``fABS(...)``. Reason being, that ``fABS`` is easier to match and map to
278``tcg_gen_abs_<width>``, compared to the full ternary expression above. Loads of
279macros in ``macros.h`` are kept unexpanded to aid in parsing, as seen in the
280example above, for more information see ``idef-parser/idef-parser.lex``.
281
282Finally, in mapping these input expressions to tinycode generators, idef-parser
283tries to perform as much as possible in plain C. Such as, performing binary
284operations in C instead of tinycode generators, thus effectively constant
285folding the expression.
286
287Variables and Variable Declarations
288~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
289
290Similarly to C, variables in the input code must be explicitly declared, such as
291``int var1;`` which declares an uninitialized variable ``var1``. Initialization
292``int var2 = 0;`` is also allowed and behaves as expected. In tinycode
293generators the previous declarations are mapped to
294
295::
296
297    int var1;           ->      TCGv_i32 var1 = tcg_temp_local_new_i32();
298
299    int var2 = 0;       ->      TCGv_i32 var1 = tcg_temp_local_new_i32();
300                                tcg_gen_movi_i32(j, ((int64_t) 0ULL));
301
302which are later automatically freed at the end of the function they're declared
303in. Contrary to C, we only allow variables to be declared with an integer type
304specified in the following table (without permutation of keywords)
305
306::
307
308    type                        bit-width    signedness
309    ----------------------------------------------------------
310    int                         32           signed
311    signed
312    signed int
313
314    unsigned                    32           unsigned
315    unsigned int
316
317    long                        64           signed
318    long int
319    signed long
320    signed long int
321
322    unsigned long               64           unsigned
323    unsigned long int
324
325    long long                   64           signed
326    long long int
327    signed long long
328    signed long long int
329
330    unsigned long long          64           unsigned
331    unsigned long long int
332
333    size[1,2,4,8][s,u]_t        8-64         signed or unsigned
334
335In idef-parser, variable names are matched by a generic ``VARID`` token,
336which will feature the variable name as a decoration. For a variable declaration
337idef-parser calls ``gen_varid_allocate`` with the ``VARID`` token to save the
338name, size, and bit width of the newly declared variable. In addition, this
339function also ensures that variables aren't declared multiple times, and prints
340and error message if that is the case. Upon use of a variable, the ``VARID``
341token is used to lookup the size and bit width of the variable.
342
343Type System
344~~~~~~~~~~~
345
346idef-parser features a simple type system which is used to correctly implement
347the signedness and bit width of the operations.
348
349The type of each ``rvalue`` is determined by two attributes: its bit width
350(``unsigned bit_width``) and its signedness (``HexSignedness signedness``).
351
352For each operation, the type of ``rvalue``\ s influence the way in which the
353operands are handled and emitted. For example a right shift between signed
354operators will be an arithmetic shift, while one between unsigned operators
355will be a logical shift. If one of the two operands is signed, and the other
356is unsigned, the operation will be signed.
357
358The bit width also influences the outcome of the operations, in particular while
359the input languages features a fine granularity type system, with types of 8,
36016, 32, 64 (and more for vectorial instructions) bits, the tinycode only
361features 32 and 64 bit widths. We propagate as much as possible the fine
362granularity type, until the value has to be used inside an operation between
363``rvalue``\ s; in that case if one of the two operands is greater than 32 bits
364we promote the whole operation to 64 bit, taking care of properly extending the
365two operands. Fortunately, the most critical instructions already feature
366explicit casts and zero/sign extensions which are properly propagated down to
367our parser.
368
369The combination of ``rvalue``\ s are handled through the use of the
370``gen_bin_op`` and ``gen_bin_cmp`` helper functions. These two functions handle
371the appropriate compile-time or run-time emission of operations to perform the
372required computation.
373
374Control Statements
375~~~~~~~~~~~~~~~~~~
376
377``control_statement``\ s are all the statements which modify the order of
378execution of the generated code according to input parameters. They are expanded
379by the following grammar rule:
380
381::
382
383   control_statement : frame_check
384                     | cancel_statement
385                     | if_statement
386                     | for_statement
387                     | fpart1_statement
388
389``if_statement``\ s require the emission of labels and branch instructions which
390effectively perform conditional jumps (``tcg_gen_brcondi``) according to the
391value of an expression. Note, the tinycode generators we produce for conditional
392statements do not perfectly mirror what would be expected in C, for instance we
393do not reproduce short-circuiting of the ``&&`` operator, and use of the ``||``
394operator is disallowed. All the predicated instructions, and in general all the
395instructions where there could be alternative values assigned to an ``lvalue``,
396like C-style ternary expressions:
397
398::
399
400   rvalue            : rvalue QMARK rvalue COLON rvalue
401
402are handled using the conditional move tinycode instruction
403(``tcg_gen_movcond``), which avoids the additional complexity of managing labels
404and jumps.
405
406Instead, regarding the ``for`` loops, exploiting the fact that they always
407iterate on immediate values, therefore their iteration ranges are always known
408at compile time, we implemented those emitting plain C ``for`` loops. This is
409possible because the loops will be executed in the QEMU code, leading to the
410consequential unrolling of the for loop, since the tinycode generator
411instructions will be executed multiple times, and the respective generated
412tinycode will represent the unrolled execution of the loop.
413
414Parsing Context
415~~~~~~~~~~~~~~~
416
417All the helper functions in ``idef-parser.y`` carry two fixed parameters, which
418are the parsing context ``c`` and the ``YYLLOC`` location information. The
419context is explicitly passed to all the functions because the parser we generate
420is a reentrant one, meaning that it does not have any global variable, and
421therefore the instruction compilation could easily be parallelized in the
422future. Finally for each rule we propagate information about the location of the
423involved tokens to generate pretty error reporting, able to highlight the
424portion of the input code which generated each error.
425
426Debugging
427---------
428
429Developing the idef-parser can lead to two types of errors: compile-time errors
430and parsing errors.
431
432Compile-time errors in Bison-generated parsers are usually due to conflicts in
433the described grammar. Conflicts forbid the grammar to produce a unique
434derivation tree, thus must be solved (except for the dangling else problem,
435which is marked as expected through the ``%expect 1`` Bison option).
436
437For solving conflicts you need a basic understanding of `shift-reduce conflicts
438<https://www.gnu.org/software/Bison/manual/html_node/Shift_002fReduce.html>`__
439and `reduce-reduce conflicts
440<https://www.gnu.org/software/Bison/manual/html_node/Reduce_002fReduce.html>`__,
441then, if you are using a Bison version > 3.7.1 you can ask Bison to generate
442some counterexamples which highlight ambiguous derivations, passing the
443``-Wcex`` option to Bison. In general shift/reduce conflicts are solved by
444redesigning the grammar in an unambiguous way or by setting the token priority
445correctly, while reduce/reduce conflicts are solved by redesigning the
446interested part of the grammar.
447
448Run-time errors can be divided between lexing and parsing errors, lexing errors
449are hard to detect, since the ``var`` token will catch everything which is not
450catched by other tokens, but easy to fix, because most of the time a simple
451regex editing will be enough.
452
453idef-parser features a fancy parsing error reporting scheme, which for each
454parsing error reports the fragment of the input text which was involved in the
455parsing rule that generated an error.
456
457Implementing an instruction goes through several sequential steps, here are some
458suggestions to make each instruction proceed to the next step.
459
460-  not-emitted
461
462   Means that the parsing of the input code relative to that instruction failed,
463   this could be due to a lexical error or to some mismatch between the order of
464   valid tokens and a parser rule. You should check that tokens are correctly
465   identified and mapped, and that there is a rule matching the token sequence
466   that you need to parse.
467
468-  emitted
469
470   This instruction class contains all the instructions which are emitted but
471   fail to compile when included in QEMU. The compilation errors are shown by
472   the QEMU building process and will lead to fixing the bug.  Most common
473   errors regard the mismatch of parameters for tinycode generator functions,
474   which boil down to errors in the idef-parser type system.
475
476-  compiled
477
478   These instruction generate valid tinycode generator code, which however fail
479   the QEMU or the harness tests, these cases must be handled manually by
480   looking into the failing tests and looking at the generated tinycode
481   generator instruction and at the generated tinycode itself. Tip: handle the
482   failing harness tests first, because they usually feature only a single
483   instruction, thus will require less execution trace navigation. If a
484   multi-threaded test fail, fixing all the other tests will be the easier
485   option, hoping that the multi-threaded one will be indirectly fixed.
486
487   An example of debugging this type of failure is provided in the following
488   section.
489
490-  tests-passed
491
492   This is the final goal for each instruction, meaning that the instruction
493   passes the test suite.
494
495Another approach to fix QEMU system test, where many instructions might fail, is
496to compare the execution trace of your implementation with the reference
497implementations already present in QEMU. To do so you should obtain a QEMU build
498where the instruction pass the test, and run it with the following command:
499
500::
501
502   sudo unshare -p sudo -u <USER> bash -c \
503   'env -i <qemu-hexagon full path> -d cpu <TEST>'
504
505And do the same for your implementation, the generated execution traces will be
506inherently aligned and can be inspected for behavioral differences using the
507``diff`` tool.
508
509Example of debugging erroneous tinycode generator code
510~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
511
512The goal of this section is to provide a complete example of debugging
513incorrectly emitted tinycode generator for a single instruction.
514
515Let's first introduce a bug in the tinycode generator of the ``A2_add``
516instruction,
517
518::
519
520    void emit_A2_add(DisasContext *ctx, Insn *insn, Packet *pkt, TCGv_i32 RdV,
521                     TCGv_i32 RsV, TCGv_i32 RtV)
522    /*  RdV=RsV+RtV;} */
523    {
524        TCGv_i32 tmp_0 = tcg_temp_new_i32();
525        tcg_gen_add_i32(tmp_0, RsV, RsV);
526        tcg_gen_mov_i32(RdV, tmp_0);
527        tcg_temp_free_i32(tmp_0);
528    }
529
530Here the bug, albeit hard to spot, is in ``tcg_gen_add_i32(tmp_0, RsV, RsV);``
531where we compute ``RsV + RsV`` instead of ``RsV + RtV``, as would be expected.
532This particular bug is a bit tricky to pinpoint when debugging, since the
533``A2_add`` instruction is so ubiquitous. As a result, pretty much all tests will
534fail and therefore not provide a lot of information about the bug.
535
536For example, let's run the ``check-tcg`` tests
537
538::
539
540    make check-tcg TIMEOUT=1200 \
541                   DOCKER_IMAGE=debian-hexagon-cross \
542                   ENGINE=podman V=1 \
543                   DOCKER_CROSS_CC_GUEST=hexagon-unknown-linux-musl-clang
544
545In the output, we find a failure in the very first test case ``float_convs``
546due to a segmentation fault. Similarly, all harness and libc tests will fail as
547well. At this point we have no clue where the actual bug lies, and need to start
548ruling out instructions. As such a good starting point is to utilize the debug
549options ``-d in_asm,cpu`` of QEMU to inspect the Hexagon instructions being run,
550alongside the CPU state. We additionally need a working version of the emulator
551to compare our buggy CPU state against, running
552
553::
554
555    meson configure -Dhexagon_idef_parser=false
556
557will disable the idef-parser for all instructions and fallback on manual
558tinycode generator overrides, or on helper function implementations. Recompiling
559gives us ``qemu-hexagon`` which passes all tests. If ``qemu-hexagon-buggy`` is
560our binary with the incorrect tinycode generators, we can compare the CPU state
561between the two versions
562
563::
564
565    ./qemu-hexagon-buggy -d in_asm,cpu float_convs &> out_buggy
566    ./qemu-hexagon       -d in_asm,cpu float_convs &> out_working
567
568Looking at ``diff -u out_buggy out_working`` shows us that the CPU state begins
569to diverge on line 141, with an incorrect value in the ``R1`` register
570
571::
572
573    @@ -138,7 +138,7 @@
574
575     General Purpose Registers = {
576       r0 = 0x4100f9c0
577    -  r1 = 0x00042108
578    +  r1 = 0x00000000
579       r2 = 0x00021084
580       r3 = 0x00000000
581       r4 = 0x00000000
582
583If we also look into ``out_buggy`` directly we can inspect the input assembly
584which the caused the incorrect CPU state, around line 141 we find
585
586::
587
588    116 |  ----------------
589    117 |  IN: _start_c
590    118 |  0x000210b0:  0xa09dc002	{	allocframe(R29,#0x10):raw }
591    ... |  ...
592    137 |  0x000210fc:  0x5a00c4aa	{	call PC+2388 }
593    138 |
594    139 |  General Purpose Registers = {
595    140 |    r0 = 0x4100fa70
596    141 |    r1 = 0x00042108
597    142 |    r2 = 0x00021084
598    143 |    r3 = 0x00000000
599
600Importantly, we see some Hexagon assembly followed by a dump of the CPU state,
601now the CPU state is actually dumped before the input assembly above is ran.
602As such, we are actually interested in the instructions ran before this.
603
604Scrolling up a bit, we find
605
606::
607
608    54 |  ----------------
609    55 |  IN: _start
610    56 |  0x00021088:  0x6a09c002	{	R2 = C9/pc }
611    57 |  0x0002108c:  0xbfe2ff82	{	R2 = add(R2,#0xfffffffc) }
612    58 |  0x00021090:  0x9182c001	{	R1 = memw(R2+#0x0) }
613    59 |  0x00021094:  0xf302c101	{	R1 = add(R2,R1) }
614    60 |  0x00021098:  0x7800c01e	{	R30 = #0x0 }
615    61 |  0x0002109c:  0x707dc000	{	R0 = R29 }
616    62 |  0x000210a0:  0x763dfe1d	{	R29 = and(R29,#0xfffffff0) }
617    63 |  0x000210a4:  0xa79dfdfe	{	memw(R29+#0xfffffff8) = R29 }
618    64 |  0x000210a8:  0xbffdff1d	{	R29 = add(R29,#0xfffffff8) }
619    65 |  0x000210ac:  0x5a00c002	{	call PC+4 }
620    66 |
621    67 |  General Purpose Registers = {
622    68 |    r0 = 0x00000000
623    69 |    r1 = 0x00000000
624    70 |    r2 = 0x00000000
625    71 |    r3 = 0x00000000
626
627Remember, the instructions on lines 56-65 are ran on the CPU state shown below
628instructions, and as the CPU state has not diverged at this point, we know the
629starting state is accurate. The bug must then lie within the instructions shown
630here. Next we may notice that ``R1`` is only touched by lines 57 and 58, that is
631by
632
633::
634
635    58 |  0x00021090:  0x9182c001	{	R1 = memw(R2+#0x0) }
636    59 |  0x00021094:  0xf302c101	{	R1 = add(R2,R1) }
637
638Therefore, we are either dealing with an correct load instruction
639``R1 = memw(R2+#0x0)`` or with an incorrect add ``R1 = add(R2,R1)``. At this
640point it might be easy enough to go directly to the emitted code for the
641instructions mentioned and look for bugs, but we could also run
642``./qemu-heaxgon -d op,in_asm float_conv`` where we find for the following
643tinycode for the Hexagon ``add`` instruction
644
645::
646
647   ---- 00021094
648   mov_i32 pkt_has_store_s1,$0x0
649   add_i32 tmp0,r2,r2
650   mov_i32 loc2,tmp0
651   mov_i32 new_r1,loc2
652   mov_i32 r1,new_r1
653
654Here we have finally located our bug ``add_i32 tmp0,r2,r2``.
655
656Limitations and Future Development
657----------------------------------
658
659The main limitation of the current parser is given by the syntax-driven nature
660of the Bison-generated parsers. This has the severe implication of only being
661able to generate code in the order of evaluation of the various rules, without,
662in any case, being able to backtrack and alter the generated code.
663
664An example limitation is highlighted by this statement of the input language:
665
666::
667
668   { (PsV==0xff) ? (PdV=0xff) : (PdV=0x00); }
669
670This ternary assignment, when written in this form requires us to emit some
671proper control flow statements, which emit a jump to the first or to the second
672code block, whose implementation is extremely convoluted, because when matching
673the ternary assignment, the code evaluating the two assignments will be already
674generated.
675
676Instead we pre-process that statement, making it become:
677
678::
679
680   { PdV = ((PsV==0xff)) ? 0xff : 0x00; }
681
682Which can be easily matched by the following parser rules:
683
684::
685
686   statement             | rvalue ';'
687
688   rvalue                : rvalue QMARK rvalue COLON rvalue
689                         | rvalue EQ rvalue
690                         | LPAR rvalue RPAR
691                         | assign_statement
692                         | IMM
693
694   assign_statement      : pred ASSIGN rvalue
695
696Another example that highlight the limitation of the flex/bison parser can be
697found even in the add operation we already saw:
698
699::
700
701   TCGv_i32 tmp_0 = tcg_temp_new_i32();
702   tcg_gen_add_i32(tmp_0, RsV, RtV);
703   tcg_gen_mov_i32(RdV, tmp_0);
704
705The fact that we cannot directly use ``RdV`` as the destination of the sum is a
706consequence of the syntax-driven nature of the parser. In fact when we parse the
707assignment, the ``rvalue`` token, representing the sum has already been reduced,
708and thus its code emitted and unchangeable. We rely on the fact that QEMU will
709optimize our code reducing the useless move operations and the relative
710temporaries.
711
712A possible improvement of the parser regards the support for vectorial
713instructions and floating point instructions, which will require the extension
714of the scanner, the parser, and a partial re-design of the type system, allowing
715to build the vectorial semantics over the available vectorial tinycode generator
716primitives.
717
718A more radical improvement will use the parser, not to generate directly the
719tinycode generator code, but to generate an intermediate representation like the
720LLVM IR, which in turn could be compiled using the clang TCG backend. That code
721could be furtherly optimized, overcoming the limitations of the syntax-driven
722parsing and could lead to a more optimized generated code.
723