Subject: Re: PowerPC assembler question

From: Benjamin Herrenschmidt <[email-masked]>
Date: Tue, 11 Jun 2013 07:43:12 +1000

On Mon, 2013-06-10 at 21:14 +1000, Erik de Castro Lopo wrote:
> Benjamin Herrenschmidt wrote:
> 
> > No, this loads a 32-bit value (16-bit would be lhz).
> 
> My understanding so far (which may be wrong) is that it loads a
> 32 bit value but it loads it from a memory location that needs
> to be within +/- 32k of the instriction doing the load.

No, within that distance of the base register. IE. The offset field is
the one that is 16-bit (it's encoded in the instruction).

> The reason I think this is because when this generated code is
> compiled I get the error:
> 
>     /tmp/ghc2806_0/ghc2806_1.s:51766:0:
>        Error: operand out of range (0x000000000000adf8 is not between
>        0xffffffffffff8000 and 0x0000000000007fff)
> 
> which suggests a 16 bit offset.
>  
> Btw, this is code generated by the Glasgow Haskell Compiler (GHC). The
> GHC bug is here:
> 
>     http://hackage.haskell.org/trac/ghc/ticket/7830
> 
> 
> > Note: It's more readable if you use the register names, ie:
> > 
> > 	lwz	%r30, .label - (1b)(%r31)
> > 
> > The form of lwz is
> > 
> > 	lwz	dest_reg, offset(address_reg)
> > 
> > So it will load a 32-bit value from memory at the address contained in
> > r31 offset by ".label - 1b" which is itself the difference between
> > two labels, "label", and the first "1:" label before the instruction
> > 
> > (gcc supports numeric labels that can be referenced with the suffix "b"
> > for backward and "f" for forward which are handy for small
> > displacements)
> 
> Ahh, that would be +/- 32k!

Yes. If you need more, then you can use a different form such as lwzx
which takes two registers for the address and adds them (beware that
the instruction is of the form rA||0 which means that if the "offset"
register is r0 it will use the value "0" instead.

> > So for example if 1: was the base of the structure and .label a field
> > in the structure, it would load the 32-bit value of that field for the
> > structure instance starting at %r31.
> > 
> > In this case, this looks more like some kind of position-independent
> > code though.
> 
> That would definitely make sense.
> 
> Is there something I could replace this above lwz instruction with
> that would work for PIC with offsets greater than +/- 32k?

As I said above, you'd have to load another register with the offset
and use that, which would be something like 3 instructions instead of
one (and a register spill).

If the offset can be known at "generation" time (it should since it's
label differences but it depends how the compiler works), you might be
able to pick the most efficient instruction based on the value of
the offset.

Cheers,
Ben.