Discussion:
arm inline assembly constraint for coprocessor registers
John Breitenbach
2009-04-08 20:47:28 UTC
Permalink
In the following inline assembly code, my input parameters need to be
prefixed with "c" rather than "r".
I.e. "c0" can be considered an alias for r0, and "c1" for r1, etc. I
found several instances of inline assembly
in the linux kernel which punted when it came to this - assuming that
the function doesn't get inlined, and they
hard-code c0 and c1 in cases similar to the one below.

I've found current documentation on arm-specific constraints, which
don't mention coprocessor registers,
and I tried "c" as below, hoping that it would work. The "mrc"
instruction syntax requires "c" registers for its
source operands, although they are actually the regular registers.

Any advice?

unsigned foo( unsigned a, unsigned b)
{
int rc;
__asm__( "mrc p6,0,%0,%1,%2,5": "=r"(rc): "c"(a),"c"(b));
return( rc);
}

if not inlined, this needs to assemble as "mrc p6,0,r0,c0,c1,5", but I
really don't want to hard-code c0 and c1"
Ian Lance Taylor
2009-04-09 00:14:07 UTC
Permalink
Post by John Breitenbach
In the following inline assembly code, my input parameters need to be
prefixed with "c" rather than "r".
I.e. "c0" can be considered an alias for r0, and "c1" for r1, etc. I
found several instances of inline assembly
in the linux kernel which punted when it came to this - assuming that
the function doesn't get inlined, and they
hard-code c0 and c1 in cases similar to the one below.
I've found current documentation on arm-specific constraints, which
don't mention coprocessor registers,
and I tried "c" as below, hoping that it would work. The "mrc"
instruction syntax requires "c" registers for its
source operands, although they are actually the regular registers.
Any advice?
unsigned foo( unsigned a, unsigned b)
{
int rc;
__asm__( "mrc p6,0,%0,%1,%2,5": "=r"(rc): "c"(a),"c"(b));
return( rc);
}
if not inlined, this needs to assemble as "mrc p6,0,r0,c0,c1,5", but I
really don't want to hard-code c0 and c1"
The "c" constraint means the condition code register. That's not what
you want.

You seem to want to ask gcc to allocate a and b to coprocessor
registers. That doesn't make much sense. gcc doesn't know anything
about the coprocessor registers and it won't allocate values to them.

If you use an "r" constraint, then gcc will arrange for a and b to be
loaded into some general register. If these really are the same as the
coprocessor registers in your mrc instruction--if storing, e.g., a into
r8 means that mrc will access it as cr8--then just write

__asm__( "mrc p6,0,%0,c%1,c%2,5": "=r"(rc): "r"(a), "r"(b));

This will produce cr8, which I think is what gas expects.

Otherwise, I don't know what you want to do.

Ian
Richard Earnshaw
2009-04-09 09:30:40 UTC
Permalink
Post by Ian Lance Taylor
Post by John Breitenbach
In the following inline assembly code, my input parameters need to be
prefixed with "c" rather than "r".
I.e. "c0" can be considered an alias for r0, and "c1" for r1, etc. I
found several instances of inline assembly
in the linux kernel which punted when it came to this - assuming that
the function doesn't get inlined, and they
hard-code c0 and c1 in cases similar to the one below.
I've found current documentation on arm-specific constraints, which
don't mention coprocessor registers,
and I tried "c" as below, hoping that it would work. The "mrc"
instruction syntax requires "c" registers for its
source operands, although they are actually the regular registers.
Any advice?
unsigned foo( unsigned a, unsigned b)
{
int rc;
__asm__( "mrc p6,0,%0,%1,%2,5": "=r"(rc): "c"(a),"c"(b));
return( rc);
}
if not inlined, this needs to assemble as "mrc p6,0,r0,c0,c1,5", but I
really don't want to hard-code c0 and c1"
The "c" constraint means the condition code register. That's not what
you want.
You seem to want to ask gcc to allocate a and b to coprocessor
registers. That doesn't make much sense. gcc doesn't know anything
about the coprocessor registers and it won't allocate values to them.
If you use an "r" constraint, then gcc will arrange for a and b to be
loaded into some general register. If these really are the same as the
coprocessor registers in your mrc instruction--if storing, e.g., a into
r8 means that mrc will access it as cr8--then just write
__asm__( "mrc p6,0,%0,c%1,c%2,5": "=r"(rc): "r"(a), "r"(b));
This will produce cr8, which I think is what gas expects.
Otherwise, I don't know what you want to do.
It certainly isn't that...

Co-processor registers are distinct from the core registers. The only
co-processors that GCC knows about are:
The VFP/Neon from ARM.
Intel's Wireless MMX extensions
Cirrus' Maverick extensions
(and legacy FPA)

In other cases GCC has no knowledge of any additional registers you
might have, and there's no way, short of modifying the compiler, to
describe them to the compiler. Without that information, the compiler's
register allocator cannot deal with them.

So your only option here is to hard-code the register numbers into your
instruction mnemonics, or port GCC to support your co-processor (be
warned, that's a non-trivial task).

R.

Loading...