qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] qemu vs gcc4


From: Paul Brook
Subject: Re: [Qemu-devel] qemu vs gcc4
Date: Tue, 31 Oct 2006 19:02:21 +0000
User-agent: KMail/1.9.5

On Tuesday 31 October 2006 16:53, Rob Landley wrote:
> On Monday 23 October 2006 2:37 pm, Paul Brook wrote:
> > > > Better to just teach qemu how to generate code.
> > > > In fact I've already done most of the infrastructure (and a fair
> > > > amount of the legwork) for this. The only major missing function is
> > > > code to do softmmu load/store ops.
> > > > https://nowt.dyndns.org/
>
> I looked at the big diff between that and mainline, and couldn't make heads
> nor tails of it in the half-hour I spent on it.  I also looked at the svn
> history, but there's apparently a year and change of it.
>
> I don't suppose there's a design document somewhere?  Or could you quickly
> explain "old one did this, new one does this, the code path diverges here,
> start reading at this point and expect this and this to happen, and if you
> go read this unrelated documentation to get up to speed it might help..."

Not really.

The basic principle is very similar. Host code is decomposed into an 
intermediate form consisting of simple operations, then native code is 
generated from those operations.

In the existing dyngen implementation most operands to ops are implicit, with 
only a few ops taking explicit arguments. The principle with the new system 
is that all operands are explicit.

The intermediate representation used by the code generator resembles an 
imaginary machine. This machine has various different instructions (qops), 
and a nominally infinite register file (qregs). Each qop takes zero or more 
arguments, each of which may be an input or output.

In addition to dynamically allocated qregs there are a fixed set of qregs that 
map onto the guest CPU state. This is to simplify code generation.

Each qreg has a particular type (32/64 bit, integer or float). It's up to you 
ro make sure the argument types match those expected by th qop. It's 
generally fairly obvious from the name. eg. add32 adds I32 values, addf64 
adds F64 values, etc. The exception is that I64 values can be used in place 
of I32. The upper 64-bit of outputs are undefined in this case, and teh value 
must be explicitly extended before the full 64 bits are used.

The old dyngen ops are actually implemented as a special case qops.

As an example take the arm instruction

  add, r0, r1, r2, lsl #2

This is equivalent to the C expression

 r0 = r1 + (r2 << 2)

The old dyngen translate.c would do:

  gen_op_movl_T1_r2()
  gen_op_shll_T1_im(2)
  gen_op_movl_T0_r1();
  gen_op_addl(); /* does T0 = T0 + T1 */
  gen_op_movl_r0_T0

When fully converted to the new system this would become:

  int tmp = gen_new_qreg(); /* Allocate a temporary reg.  */
  /* gen_im32 is a helper that allocates a new qreg and
     initializes it to an immediate value.  */
  gen_op_add32(tmp, QREG_R2, gen_im32(2));
  gen_op_add32(QREG_R0, QREG_R1, tmp);

One of the changes I've made to target-arm/translate.c is to replace all uses 
of T2 with new pseudo-regs. IN many cases I've left the code structure as it 
was (using the global T0/T1 temporaries), but replaced the dyngen ops with 
the equivalent qops. eg. movl and andl now generate mov32 and and32 qops.

The standard qops are defined in qops.def. A target can also define additional 
qops in qop-target.def. The target specific qops are to simplify 
implementation the i386 static flag propagation pass. the expand_op_* 
routines.

For operations that are too complicated to be expressed as qops there is a 
mechanism for calling helper functions. The m68k target uses this for 
division and a couple of other things.

The implementation make fairly heavy use of the C preprocessor to generate 
code from .def files. There's also a small shell script that pulls the 
definiteions of the helper routines out of qop-helper.c

The debug dumps can be quite useful. In particular -d in_asm,op will dump the 
input asm and the resulting OPs.

For converting targets you can probably ignore most of the translate-all and 
host-*/ changes. These implement generating code from the qops. This works by 
the host defining a set of "hard" qregs that correspond to host CPU 
registers, and constraints for the operands of each qop. Then we do register 
allocation and spilling to satisfy those constraints. The qops can then be 
assembled directly into binary code.

There is also mechanisms for implementing floating point and 64-bit arithmetic 
even if the target doesn't support this natively. The target code doesn't 
need to worry about this, it just generates 64-bit/fp qops and they will be 
decomposed as neccessary.

Paul




reply via email to

[Prev in Thread] Current Thread [Next in Thread]