Skip to contentSkip to conversation

question on inline assembly and long long values

DISCUSSION Chris Friesen 4 participants 11 messages Apr 6, 2005 – Apr 7, 2005

lore
Share & tools
lore
#0 lore raw

I want to retrieve the msr (which is 64-bits) on a 970 when running in 32-bit mode. I have the following bit of code that seems to work, but when looking at the code it always seems to use a suboptimal register for the low word, and then it ends up having to copy it to the right register to create a long long register pair.

static inline unsigned long long get_msr()

{
	union {
		struct {
			unsigned long low;
			unsigned long high;
		} words;
		unsigned long long val;
	} val;
        asm volatile( \
                "mfmsr  %0               \n\t" \
                "rldicl %1,%0,32,32       \n\t" \
                "rldicl %0,%0,0,32        \n\t" \
                : "=r" (val.words.low), "=r" (val.words.high));
	return val.val;
}

Using this code, the optimised assembly output of

	unsigned long long a = asdf();
	unsigned long long b = asdf();

is

	mfmsr  5
	rldicl 0,5,32,32
	rldicl 5,5,0,32
	mr 6,0
	mfmsr  7
	rldicl 9,7,32,32
	rldicl 7,7,0,32
	mr 8,9

I figure it should have been able to use registers 6/8 in the first place, and save the extra moves.

Is there any way to help gcc optimise this?

Chris

#1 lore raw

I'm having a similar need (for a different purpose), this post might be=20=

useful:

http://gcc.gnu.org/ml/gcc/2005-04/msg00283.html

- kumar

Quoted 2 lines · Chris Friesen

I want to retrieve the msr (which is 64-bits) on a 970 when running in 32-bit mode.=A0 I have the following bit of code that seems to work, =

but

Quoted 9 lines

when looking at the code it always seems to use a suboptimal register for the low word, and then it ends up having to copy it to the right register to create a long long register pair.

static inline unsigned long long get_msr()
{
=A0=A0=A0=A0=A0=A0=A0 union {
=A0=A0=A0=A0=A0=A0=A0 =A0=A0=A0=A0=A0=A0=A0 struct { =A0=A0=A0=A0=A0=A0=A0 =A0=A0=A0=A0=A0=A0=A0 =A0=A0=A0=A0=A0=A0=A0 =

unsigned long low;

Quoted 1 line

=A0=A0=A0=A0=A0=A0=A0 =A0=A0=A0=A0=A0=A0=A0 =A0=A0=A0=A0=A0=A0=A0 =

unsigned long high;

Quoted 5 lines

=A0=A0=A0=A0=A0=A0=A0 =A0=A0=A0=A0=A0=A0=A0 } words; =A0=A0=A0=A0=A0=A0=A0 =A0=A0=A0=A0=A0=A0=A0 unsigned long long val; =A0=A0=A0=A0=A0=A0=A0 } val;
=A0=A0=A0=A0=A0=A0=A0=A0 asm volatile( \
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 "mfmsr=A0 =

%0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 \n\t" \

Quoted 1 line

=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 "rldicl =

%1,%0,32,32=A0=A0=A0=A0=A0=A0 \n\t" \

Quoted 1 line

=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 "rldicl =

%0,%0,0,32=A0=A0=A0=A0=A0=A0=A0 \n\t" \

Quoted 1 line

=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 : "=3Dr" =

(val.words.low), "=3Dr" (val.words.high));

Quoted 31 lines

=A0=A0=A0=A0=A0=A0=A0 return val.val;
}

Using this code, the optimised assembly output of

=A0=A0=A0=A0=A0=A0=A0 unsigned long long a =3D asdf();
=A0=A0=A0=A0=A0=A0=A0 unsigned long long b =3D asdf();

is

=A0=A0=A0=A0=A0=A0=A0 mfmsr=A0 5
=A0=A0=A0=A0=A0=A0=A0 rldicl 0,5,32,32
=A0=A0=A0=A0=A0=A0=A0 rldicl 5,5,0,32
=A0=A0=A0=A0=A0=A0=A0 mr 6,0
=A0=A0=A0=A0=A0=A0=A0 mfmsr=A0 7
=A0=A0=A0=A0=A0=A0=A0 rldicl 9,7,32,32
=A0=A0=A0=A0=A0=A0=A0 rldicl 7,7,0,32
=A0=A0=A0=A0=A0=A0=A0 mr 8,9

I figure it should have been able to use registers 6/8 in the first place, and save the extra moves.

Is there any way to help gcc optimise this?

Chris
_______________________________________________
Linuxppc-dev mailing list
[email protected]
https://ozlabs.org/mailman/listinfo/linuxppc-dev

#2 lore raw
Quoted 3 lines · Kumar Gala

I'm having a similar need (for a different purpose), this post might be useful:

http://gcc.gnu.org/ml/gcc/2005-04/msg00283.html

Sweet! My new code is now shorter *and* more efficient:

static inline unsigned long long getmsr()

{
	unsigned long long val;
        asm volatile( \
                "mfmsr  %L0               \n\t" \
                "rldicl %0,%L0,32,32       \n\t" \
                "rldicl %L0,%L0,0,32        \n\t" \
                : "=r" (val));
	return val;
}

This results in

unsigned long long a = asdf3();
unsigned long long b = asdf3();

being compiled to

	mfmsr  6
	rldicl 5,6,32,32
	rldicl 6,6,0,32
	
	mfmsr  8
	rldicl 7,8,32,32
	rldicl 8,8,0,32

Which is about as good as it gets...

Thanks!

Chris

#3 lore raw
Quoted 26 lines · Chris Friesen
Quoted 4 lines · Kumar Gala

I'm having a similar need (for a different purpose), this post might be useful:

http://gcc.gnu.org/ml/gcc/2005-04/msg00283.html

Sweet! My new code is now shorter *and* more efficient:

static inline unsigned long long getmsr()

{
	unsigned long long val;
        asm volatile( \
                "mfmsr  %L0               \n\t" \
                "rldicl %0,%L0,32,32       \n\t" \
                "rldicl %L0,%L0,0,32        \n\t" \
                : "=r" (val));
	return val;
}

This results in

unsigned long long a = asdf3();
unsigned long long b = asdf3();

being compiled to

Quoted 7 lines
	mfmsr  6
	rldicl 5,6,32,32
	rldicl 6,6,0,32
	
	mfmsr  8
	rldicl 7,8,32,32
	rldicl 8,8,0,32

If you are running in 32 bit mode, you don't need to clear the upper half of %L0. The architecture is designed so that pure 32 bit code runs unmodified despite the fact that you can access the upper 32 bits using 64 bit instructions.

Regards,
Gabriel

#4 lore raw
Quoted 13 lines · Gabriel Paubert
Quoted 10 lines · Chris Friesen

static inline unsigned long long getmsr()

{
	unsigned long long val;
       asm volatile( \
               "mfmsr  %L0               \n\t" \
               "rldicl %0,%L0,32,32       \n\t" \
               "rldicl %L0,%L0,0,32        \n\t" \
               : "=r" (val));
	return val;
}
Quoted 2 lines

If you are running in 32 bit mode, you don't need
to clear the upper half of %L0.

Thanks for the tip. That cuts out another instruction.

Chris

#5 lore raw
In reply to Chris Friesen
Quoted 7 lines · Chris Friesen

I want to retrieve the msr (which is 64-bits) on a 970 when running in 32-bit mode. I have the following bit of code that seems to work, but when looking at the code it always seems to use a suboptimal register for the low word, and then it ends up having to copy it to the right register to create a long long register pair.

static inline unsigned long long get_msr()

Quoted 15 lines
{
	union {
		struct {
			unsigned long low;
			unsigned long high;
		} words;
		unsigned long long val;
	} val;
         asm volatile( \
                 "mfmsr  %0               \n\t" \
                 "rldicl %1,%0,32,32       \n\t" \
                 "rldicl %0,%0,0,32        \n\t" \
                 : "=r" (val.words.low), "=r" (val.words.high));
	return val.val;
}

Is this in kernel mode ? Why are you doing that ?

Quoted 27 lines

Using this code, the optimised assembly output of

	unsigned long long a = asdf();
	unsigned long long b = asdf();

is

	mfmsr  5
	rldicl 0,5,32,32
	rldicl 5,5,0,32
	mr 6,0
	mfmsr  7
	rldicl 9,7,32,32
	rldicl 7,7,0,32
	mr 8,9

I figure it should have been able to use registers 6/8 in the first place, and save the extra moves.

Is there any way to help gcc optimise this?

Chris
_______________________________________________
Linuxppc-dev mailing list
[email protected]
https://ozlabs.org/mailman/listinfo/linuxppc-dev

Signature · 1 line
Benjamin Herrenschmidt <[email protected]>
#6 lore raw
Quoted 5 lines · Benjamin Herrenschmidt
Quoted 1 line · Chris Friesen

I want to retrieve the msr (which is 64-bits) on a 970 when running in 32-bit mode.

Is this in kernel mode ? Why are you doing that ?

Yes it is.

We wanted to manipulate the high word of the msr on the 970, from C code, while running in 32-bit mode. I'll be doing something similar to get at the high word of HID1 (to enable the en_icbi bit).

Is there some other way to do this?

Chris

#7 lore raw
Quoted 8 lines · Chris Friesen
Quoted 6 lines · Benjamin Herrenschmidt
Quoted 2 lines · Chris Friesen

I want to retrieve the msr (which is 64-bits) on a 970 when running in 32-bit mode.

Is this in kernel mode ? Why are you doing that ?

Quoted 7 lines

Yes it is.

We wanted to manipulate the high word of the msr on the 970, from C code, while running in 32-bit mode. I'll be doing something similar to get at the high word of HID1 (to enable the en_icbi bit).

Is there some other way to do this?

But the kernel code always runs in 64 bits mode... or are you trying to pass that down to userland ? In the later case, your optimisations are pretty much nothing compared to the cost of a syscall

Ben.

#8 lore raw
Quoted 1 line · Benjamin Herrenschmidt

But the kernel code always runs in 64 bits mode...

The ppc kernel (not ppc64) runs in 64-bit mode? An unsigned long long fits in a single register in C code?

Yeah, the optimisations really don't matter much...the ugly resulting code just bothered me.

Chris

#9 lore raw
Quoted 6 lines · Chris Friesen
Quoted 1 line · Benjamin Herrenschmidt

But the kernel code always runs in 64 bits mode...

The ppc kernel (not ppc64) runs in 64-bit mode? An unsigned long long fits in a single register in C code?

Ah no, it doesn't, but then, be careful to have interrupts off when you do that are the interrupt handler won't save the high half of the registers between the mtmsrd and your "splitting" of it.

Quoted 4 lines

Yeah, the optimisations really don't matter much...the ugly resulting code just bothered me.

Chris

Signature · 1 line
Benjamin Herrenschmidt <[email protected]>
#10 lore raw
Quoted 9 lines · Benjamin Herrenschmidt
Quoted 4 lines · Chris Friesen
Quoted 1 line · Benjamin Herrenschmidt

But the kernel code always runs in 64 bits mode...

The ppc kernel (not ppc64) runs in 64-bit mode? An unsigned long long fits in a single register in C code?

Ah no, it doesn't, but then, be careful to have interrupts off when you do that are the interrupt handler won't save the high half of the registers between the mtmsrd and your "splitting" of it.

Right. All this stuff is running with interrupts off.

Chris