All of lore.kernel.org
 help / color / mirror / Atom feed
* PowerPC assembler question
@ 2013-06-09 23:01 Erik de Castro Lopo
  2013-06-09 23:21 ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 8+ messages in thread
From: Erik de Castro Lopo @ 2013-06-09 23:01 UTC (permalink / raw)
  To: linuxppc-dev

Hi all,

I'm trying to fix a problem in the PowerPC backend of the Glasgow
Haskell Compiler (GHC) and have a problem with the following
instruction form:

    lwz     30, .label - (1b)(31)

Reading the documentation I could find, I have figured out that this
loads a 16 bit value into register 30. How it calculates that 16 bit
value has got me somewhat flumoxed.

Anybody care to explain?

Cheers,
Erik
-- 
----------------------------------------------------------------------
Erik de Castro Lopo
http://www.mega-nerd.com/

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: PowerPC assembler question
  2013-06-09 23:01 PowerPC assembler question Erik de Castro Lopo
@ 2013-06-09 23:21 ` Benjamin Herrenschmidt
  2013-06-10 11:14   ` Erik de Castro Lopo
  0 siblings, 1 reply; 8+ messages in thread
From: Benjamin Herrenschmidt @ 2013-06-09 23:21 UTC (permalink / raw)
  To: Erik de Castro Lopo; +Cc: linuxppc-dev

On Mon, 2013-06-10 at 09:01 +1000, Erik de Castro Lopo wrote:
> Hi all,
> 
> I'm trying to fix a problem in the PowerPC backend of the Glasgow
> Haskell Compiler (GHC) and have a problem with the following
> instruction form:
> 
>     lwz     30, .label - (1b)(31)
> 
> Reading the documentation I could find, I have figured out that this
> loads a 16 bit value into register 30. How it calculates that 16 bit
> value has got me somewhat flumoxed.
> 
> Anybody care to explain?

No, this loads a 32-bit value (16-bit would be lhz).

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)

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.

Cheers,
Ben.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: PowerPC assembler question
  2013-06-09 23:21 ` Benjamin Herrenschmidt
@ 2013-06-10 11:14   ` Erik de Castro Lopo
  2013-06-10 12:41     ` David Laight
  2013-06-10 21:43     ` Benjamin Herrenschmidt
  0 siblings, 2 replies; 8+ messages in thread
From: Erik de Castro Lopo @ 2013-06-10 11:14 UTC (permalink / raw)
  To: linuxppc-dev

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.

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!

> 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?

Cheers,
Erik
-- 
----------------------------------------------------------------------
Erik de Castro Lopo
http://www.mega-nerd.com/

^ permalink raw reply	[flat|nested] 8+ messages in thread

* RE: PowerPC assembler question
  2013-06-10 11:14   ` Erik de Castro Lopo
@ 2013-06-10 12:41     ` David Laight
  2013-06-16  6:30       ` Erik de Castro Lopo
  2013-06-10 21:43     ` Benjamin Herrenschmidt
  1 sibling, 1 reply; 8+ messages in thread
From: David Laight @ 2013-06-10 12:41 UTC (permalink / raw)
  To: linuxppc-dev

> > 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
...
> Is there something I could replace this above lwz instruction with
> that would work for PIC with offsets greater than +/- 32k?

With a scratch register there are some two instruction sequences.
Reusing the destination register something like:
	addis	%r30,%r31,hi(.label - 1b)
	lwzx	%r30,lo(.label - 1b)(%r30)
(Not sure of the hi()/lo() functions for ppc!)
It is even possible that there are some macros for the
assembler that will do this automatically - %r1 might
even be reserved for the purpose (as it is on MIPS).

	David

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: PowerPC assembler question
  2013-06-10 11:14   ` Erik de Castro Lopo
  2013-06-10 12:41     ` David Laight
@ 2013-06-10 21:43     ` Benjamin Herrenschmidt
  1 sibling, 0 replies; 8+ messages in thread
From: Benjamin Herrenschmidt @ 2013-06-10 21:43 UTC (permalink / raw)
  To: linuxppc-dev

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.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: PowerPC assembler question
  2013-06-10 12:41     ` David Laight
@ 2013-06-16  6:30       ` Erik de Castro Lopo
  2013-06-17  2:55         ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 8+ messages in thread
From: Erik de Castro Lopo @ 2013-06-16  6:30 UTC (permalink / raw)
  To: linuxppc-dev


Been busy, but I'm back looking at this.

David Laight wrote:

> With a scratch register there are some two instruction sequences.
> Reusing the destination register something like:
>
> 	addis	%r30,%r31,hi(.label - 1b)
> 	lwzx	%r30,lo(.label - 1b)(%r30)
>

I've managed to convert that into something gcc understands:

	addis	30, 31, (.label-(1b))@ha
	lwz	30, (.label-(1b))@l(30)

The "@l" is the equivalent of lo() and "@ha" is the sign extending
verions of hi(). Unfortunately, this code segfaults on executiion.
I suspect that is because I have used the LWZ instruction instead
of LWZX suggested by David.

Unfortunately gcc doesn't accept LWZX which I found documented
here:

     http://pds.twi.tudelft.nl/vakken/in101/labcourse/instruction-set/lwzx.html

and seems to have LX as a synonym, but that instruction only seems
to work on registers, not on addresses as we have here.

I'm actually beginning to have a better understanding of the code
and I've pulled out these snippets code code into a small assember
program I'm compiling with gcc and running under gdb.

Cheers,
Erik
-- 
----------------------------------------------------------------------
Erik de Castro Lopo
http://www.mega-nerd.com/

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: PowerPC assembler question
  2013-06-16  6:30       ` Erik de Castro Lopo
@ 2013-06-17  2:55         ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 8+ messages in thread
From: Benjamin Herrenschmidt @ 2013-06-17  2:55 UTC (permalink / raw)
  To: linuxppc-dev

On Sun, 2013-06-16 at 16:30 +1000, Erik de Castro Lopo wrote:
> Been busy, but I'm back looking at this.
> 
> David Laight wrote:
> 
> > With a scratch register there are some two instruction sequences.
> > Reusing the destination register something like:
> >
> > 	addis	%r30,%r31,hi(.label - 1b)
> > 	lwzx	%r30,lo(.label - 1b)(%r30)
> >
> 
> I've managed to convert that into something gcc understands:
> 
> 	addis	30, 31, (.label-(1b))@ha
> 	lwz	30, (.label-(1b))@l(30)
> 
> The "@l" is the equivalent of lo() and "@ha" is the sign extending
> verions of hi(). Unfortunately, this code segfaults on executiion.
> I suspect that is because I have used the LWZ instruction instead
> of LWZX suggested by David.

No, lwz is the right instruction. The above should work, tried
stepping it in something like gdb to see waht exactly is going on ?

lwzx is a form that takes only registers (adds two registers to make
the address to load from). lwz takes a register and an immediate offset.

Cheers,
Ben.


> Unfortunately gcc doesn't accept LWZX which I found documented
> here:
> 
>      http://pds.twi.tudelft.nl/vakken/in101/labcourse/instruction-set/lwzx.html
> 
> and seems to have LX as a synonym, but that instruction only seems
> to work on registers, not on addresses as we have here.
> 
> I'm actually beginning to have a better understanding of the code
> and I've pulled out these snippets code code into a small assember
> program I'm compiling with gcc and running under gdb.
> 
> Cheers,
> Erik

^ permalink raw reply	[flat|nested] 8+ messages in thread

* PowerPC assembler question
@ 2013-06-09 23:01 Erik de Castro Lopo
  0 siblings, 0 replies; 8+ messages in thread
From: Erik de Castro Lopo @ 2013-06-09 23:01 UTC (permalink / raw)
  To: linuxppc-dev

Hi all,

I'm trying to fix a problem in the PowerPC backend of the Glasgow
Haskell Compiler (GHC) and have a problem with the following
instruction form:

    lwz     30, .label - (1b)(31)

Reading the documentation I could find, I have figured out that this
loads a 16 bit value into register 30. How it calculates that 16 bit
value has got me somewhat flumoxed.

Anybody care to explain?

Cheers,
Erik
-- 
----------------------------------------------------------------------
Erik de Castro Lopo
http://www.mega-nerd.com/

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2013-06-17  2:56 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-06-09 23:01 PowerPC assembler question Erik de Castro Lopo
2013-06-09 23:21 ` Benjamin Herrenschmidt
2013-06-10 11:14   ` Erik de Castro Lopo
2013-06-10 12:41     ` David Laight
2013-06-16  6:30       ` Erik de Castro Lopo
2013-06-17  2:55         ` Benjamin Herrenschmidt
2013-06-10 21:43     ` Benjamin Herrenschmidt
  -- strict thread matches above, loose matches on Subject: below --
2013-06-09 23:01 Erik de Castro Lopo

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.