Re: [RFA][2/5] New port: Cell BE SPU (valops.c fix)

Ulrich Weigand
2006-12-06T16:29:41Z

Daniel Jacobowitz wrote:

> On Tue, Nov 28, 2006 at 12:23:34AM +0100, Ulrich Weigand wrote:
> > However, I still think there's something fundamentally broken in the
> > way value_assign calls VALUE_TO_REGISTER. As the documentation says,
> > that gdbarch functions is supposed to "convert a data value of type
> > TYPE to register number REG's raw format". Calling the conversion
> > function with a type that does not actually denote the type of the
> > register contents, but some subfield, must break all other implementations
> > of that routine as well ...
>
> Except that I suspect there are no other implementations of
> VALUE_TO_REGISTER which offer any subfields. It was usually used for
> things like registers which can only hold a float by converting it to
> double, and those floating point registers generally can't hold
> arbitrary structs or arrays.
>
> There might be some trouble on i386 though... I think you'd need
> extraordinary bad luck to trigger it. A field of a struct spread
> across multiple registers.
>
> These three hooks are simply not very clearly defined.

Here's an overview of what register_to_value / value_to_register
are currently being used for on various platforms:

arch float reg float values type of
only only conversion
alpha Y N special
i387 (*) Y Y float
i386 N N multi-reg
ia64 Y Y float
m68k Y Y float
mips Y Y multi-reg
rs6000 Y Y float
s390 Y N offset
spu N N offset

(*) on amd64 and i386

The default code extracts a value from a register using a certain set
of assumptions: the bits making up the value are the same for values
in registers as in memory, and there is well-defined way to *find*
which bits of the register(s) make up that value.

Depending on which of those assumptions is violated, different
platforms use r_t_v / v_t_r for different purposes:

- On some platforms, the bits in the register are the same as in
memory, they're just not at the default location:

* For multi-register values, the value is not formed by registers
concatenated like X, X+1, X+2, ...
-> This is the case for 8-byte float values on mips, and for
certain multi-register values on i386. ("multi-reg")

* For single-register values of size smaller than register size,
the bits are not at the default offset
-> This is the case for 4-byte values in s390 float registers,
and for all values < 16 bytes on spu. ("offset")

- On some platforms, the bits making up the value are themselves
different, i.e. a real conversion needs to take place:

* Floating point values may need to be converted into a different
floating point number format
-> E.g. on i387, ia64, m68k, rs6000 ("float")

* There's a particular special case on the alpha, where 4-byte
integer values may reside in floating point registers, but still
undergo a conversion as if to a different floating point format
(however, that conversion is fully reversible, so when the value
is stored back to memory, we still get the same integer).

Independently, we have the question of how to handle sub-types of
values in registers. This may happen if the value residing in the
register is of aggregate type (struct / bitfield / array). The
compiler is free to allocate such values into registers, and may
generally do so if the size of the aggregate equals the size of
an integral type that would otherwise be allowed to reside in the
register in question.

If this happens to a register under r_t_v / v_t_r conversion, the
current implementation is broken, since v_t_r may be called with
a different base type than r_t_v.

This is not an issue for those platforms that only ever accept
floating-point types in their r_t_v / v_t_r routines, since those
do not have sub-types. However, it remains a problem, at least
in principle, for alpha, i386, s390, and spu.

Jim's suggestion was to allow the r_t_v / v_t_r routines to set
and access the value's offset and bitfield information. This
would enable both s390 and spu to encode the non-standard offset
in r_t_v, and otherwise use the default methods.

However, for i386 and alpha this still would not work, since
there's simply not enough information available. Let's assume
we have an value of aggregate 8-byte type composed of two 4-byte
subfields of type "int". Such a value could reside in a float
register on alpha, or the %eax/%edx register pair on i386.

Now, when accessing one sub-field of this value via type "int",
the target routine needs enough information to distinguish it
from the case where you simply have a plain "int" in a register.

You could attempt to recognize that using the offset field.
And in fact, on i386 it may happen to work after all, because
the platform is little-endian and there is no difference between
accessing the element at offset 0 in the pair %eax/%edx, and
just plain accessing an "int" in %eax. It would definitely
break on a platform that swaps multi-register values (like mips
floating point registers), and still allows types with sub-fields.

On alpha, it doesn't work at all; accessing the value at offset
0 in the 8-byte struct needs completely different code than
accessing a simple "int" in the same register, and there is no
way how v_t_r can distinguish the two cases.

The patch I proposed to remember the type of the value residing
in the register would allow all the above cases to work without
changes to architecture code, and would in fact work correctly
with any conceivable implementation of the current r_t_v / v_t_r
interface. However, it does have the disadvantage of requiring
an additional field in struct value. (Maybe we can make up that
loss -- do we actually still require VALUE_ADDRESS for register
values?)

Any suggestions?

Bye,
Ulrich

--
Dr. Ulrich Weigand
GNU Toolchain for Linux on System z and Cell BE
Ulrich.Weigand@de.ibm.com