question on inline assembly and long long values
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
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 =3Dasdf();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,9I 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
Quoted 3 lines · Kumar Gala
I'm having a similar need (for a different purpose), this post might be useful:
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
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:
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
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
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,9I 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]>
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
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_icbibit).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.
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
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]>
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