more than 10 operands in `asm'

Richard Earnshaw rearnsha@arm.com
Wed Nov 4 03:10:00 GMT 1998


> Hope this isn't a FAQ...
> 
> I suppose we've all seen the "more than 10 operands in `asm'" error
> message from time to time.
> 
> How about upping the limit from 10 to something more reasonable?
> 
> On Alpha we have 32 each of integer and float registers.  On ARM we
> can run out with a single instruction!:
> 
>      U32 a,b,c,d,e,f,g,h,i, *p;
> 
>      asm ( "ldmia %0!, { %2,%3,%4,%5,%6,%7,%8,%9,%10 }"
>          : "=r"(p)
>          : "0"(p), "r"(a), "r"(b), "r"(c), "r"(d), "r"(e), "r"(f), "r"(g)
>            , "r"(h), "r"(i)
>          : "memory"
>          );
> 
> A limit of 10 often restricts inline ASM to trivial snippets of code,
> especially as in & out registers get counted twice.  The patch is
> probably a one-liner somewhere.
> 

This would rarely be a good idea, particularly on an ARM.  If you try to 
pass this many arguments to an ASM, all in registers, it is almost certain 
to cause the compiler to fail since it won't be able to work out how to 
marshall the arguments in the way that is necessary.  Further, if there 
are any other variables in your function, they would all get forced out 
into the stack if they happened to be live across the asm (since you have 
used all the available registers for your asm).  You will almost certainly 
get better overall code by breaking the instruction down into asms that do 
smaller amounts of work.  If that can't be done for some reason, you would 
probably be better off coding it as a separate function and doing it 
entirely in assembler.

I guess the limit of 10 operands is pretty arbitrary, but it should be 
taken as an indication that if you want to violate it, you are probably 
not doing things the best way.

Now to some ARM specific reasons why this would be a bad thing.

1) Load/store multiple instructions push arguments sequentially by 
register number, so your above example almost certainly wouldn't give you 
what you would expect.  By way of example, if you write:

	stmfd sp!, {r1, r0, r4, r2, r3}

your stack will be

	+-----------+
	|    r4     |
	+-----------+
	|    r3     |
	+-----------+
	|    r2     |
	+-----------+
	|    r1     |
	+-----------+
	|    r0     | <---- New value of sp points here
	+-----------+

So in practice, it is rarely possible to use ldm/stm from an ASM on the 
ARM, because it is not possible to control the register allocation.  Note 
this is still the case internally to the compiler which is why load/store 
multiple instructions don't get used in generated code as often as they 
might.

Note, gas will emit a warning if you try to assemble an ldm/stm with 
out-of-order registers.

2) Using long ldm/stm sequences can push up the interrupt latency; this 
might not be an issue unless you are in an RTOS enviornment.

3) Your example uses ldmia, but your arguments are coded as though you 
intended stmia (I guess this is just a typo).

Richard.




More information about the Gcc-bugs mailing list