Specifying different registers in inline asm

Richard Earnshaw (foss) Richard.Earnshaw@arm.com
Wed Nov 19 10:18:23 GMT 2025


On 19/11/2025 08:03, jh--- via Gcc-help wrote:
> Le 2025-11-18 18:10, Segher Boessenkool a écrit :
>> Hi!
>>
>> On Tue, Nov 18, 2025 at 06:01:33PM +0100, jh@clesse.com wrote:
>>> Le 2025-11-18 17:43, Segher Boessenkool a écrit :
>>> > On Tue, Nov 18, 2025 at 11:22:40AM +0100, jh--- via Gcc-help wrote:
>>> > > I am sorry if the answer is trivial, but I couldn't find it.
>>> > > I need to access a specific instruction on ARM, so I used an inline
>>> > > asm
>>> > > block to do it.
>>> > > My problem is that the instruction (LDRBT) reads a byte in a
>>> > > register from
>>> > > an address, but the address is written back to its register as well,
>>> > > so the
>>> >
>>> > If an operand is both read and written, you should inform the compiler
>>> > of that fact.  Typically by marking it as "+" (i.e. read/write) output
>>> > constraint.
>>> I tried marking the address parameter with a "+", but since it's not an
>>> lvalue (I call the macro with &buf[cnt]), it did not work.
>>
>> The first copy it into a variable that *is* writable?  This is required
>> for correctness, since your asm *does* modify the reg!
> I'm not sure about this situation, for me there are two sides on this matter: a practical one and a theoretical one.
> On the practical side, the instruction does a write back to the register, but with the same value (because omission of the offset is equal to 0 in this instance), so the register does not change value.
> On a theoretical side, I would like to tell the compiler that the register is clobbered, that I don't care about the value anymore, but that if the compiler needs the value, it cannot rely on the fact that the register still contains it. I think it is not possible to specify clobbers for input values, but it makes sense to be able to use a non-lvalue here, so I don't want to specify it as an output. Is this doable?
> 
>>> > > destination and the address register should be different (as helpfully
>>> > > mentioned by the assembler: "destination register same as write-back
>>> > > base").
>>> > > The code generator produces "LDRBT R3, [R3]" which is not correct.
>>> > > I would like to specify that I want two distinct registers for %0
>>> > > and %1 (my
>>> > > code is LDRBT %0, [%1]), but I did not find how.
>>> >
>>> > If you want literally what you ask for (but read above), what you want
>>> > is an "earlyclobber".  Written as "&", see the manual.
>>> >
>>> Thank you very much, it is so obviously described, once you know where to
>>> look.
>>
>> As always :-)
>>
>> One thing you can try is "read everything".  I've been trying to do that
>> forever now, and am still not done, but making some progress I hope ;-)
> Nah, the real method is to "read everything an infinite number of times", because on each pass you understand something that you have read before, but which did not click into place. But as everyone knows eternity is very long, especially towards the end.
> 
>>> > > Could you please tell me what the situation is here (I could make a
>>> > > work-around by moving the result to another register and using the
>>> > > clobber
>>> > > list, but that's inefficient on several scales)?
>>> > > Also, more generally, is this not an issue that could be considered
>>> > > being
>>> > > addressed, maybe by adding to the asm constraints (if it is not yet
>>> > > the
>>> > > case) or by adding it to the documentation (as an example)?
>>> >
>>> > It is a pretty common problem, and that is why it has been handled since
>>> > decades already :-)
>>> We---ell you know, sometimes (most of the times) you think you have the most
>>> important problem in the world and it's not the case.
>>> Also it IS documented, and I don't really know how it could be any more
>>> obvious (except maybe as part of a 'cookbook'. Or using AI as RAG, but who
>>> wants to do that?).
>>>
>>> > Segher
>>> PS.: someone beat you to the answer, and I am grateful to both of you, but
>>> sorry I wasted the time of two person, what did I do wrong that you did not
>>> know that someone already answered?
>>
>> I read emails in the order they come in.  I don't always read hundreds
>> or more of messages ahead before I reply to something, that just doesn't
>> scale.
>>
>> Did Xi answer before me?  I think our answers just crossed even, a very
>> common thing :-)
> Anyway thanks a lot.
> JH

Well you could write:

  int dummy;
  int result;
  asm ("ldrbt\t%0, [%1]" : "=r"(result), "=r"(dummy) : "1"(addr));  

which describes the behaviour more precisely.  The "1" tells the compiler that addr and dummy must use the same register, but addr will remain unchanged (so must be copied if it will be used again).

Or, if you don't mind addr being direclty clobbered, you can write:

  int result;
  asm ("ldrbt\t%0, [%1]" : "=r"(result), "+r"(addr));  

telling the compiler that addr is modified as an inout value.

R.


More information about the Gcc-help mailing list