InlineAsm and allocation to wrong register for indirect access

Hi,

I am seeing a case, in a private port, of an inline asm with indirect
memory references being allocated invalid registers (i.e. registers that
cannot be used on loads).

For example, the inline asm constraint is correct:
call void asm sideeffect "MOV $$r0, $0\0AMOV $$r0, $1\0A",
"*m,*m,~{r0}"(i16* @a, i16* %b) #1, !srcloc !1

but then $0 and $1 are allocated to registers that cannot be used as a
memory base pointer.

I am having trouble finding where this decision is made. Is InlineAsm
going through the normal register allocation process or does it have its
own specialized algorithm?

Any pointers to how registers are allocated in an InlineAsm would be
helpful.

Kind regards,

Hi,

I'm not sure where this decision is done but it's possible that there's no constraint-specific selection of register classes for memory operands at the moment in which case it probably uses ${Target}RegisterInfo::getPointerRegClass() without checking the constraint code. I had a similar problem with constraint-specific offset ranges a year or so ago and found that all memory constraints were hardcoded to be 'm' regardless of the constraint in the inline assembly statement.

Here's a couple things to look for that might help you find the right code: If you search for getFlagWordForMem() you'll find the code that passes the constraint id (Constraint_m, Constraint_ZC, etc.) into SelectionDAG's ISD::INLINEASM node and https://reviews.llvm.org/rL275786 made the constraint available to the TargetOpcode::INLINEASM instruction. Also, register constraints pick the register class (and sometimes the register too) in ${Target}TargetLowering::getRegForInlineAsmConstraint().

Hope that helps

Thanks Daniel,

I found the problem to be on our SelectInlineAsmMemoryOperand which was
not returning the correct operand. Now, if I implement it similarly to
PPC by returning a COPY_TO_REGCLASS of the operand, I get the correct
operand but with the strange offset.

So a load from an operand to r0: mov r0, %0, where %0 has 'm' constraint
is transformed into mov r0, @r4+12. r4 is the correct choice for a load
but I have no idea where `+12` comes from.

Do you know how to find where this offset could be added? The IR doesn't
show the operand show it's impossible to tell from a straightforward
debug dump.

From: Paulo Matos [pmatos@linki.tools]
Sent: 22 July 2016 19:52
To: Daniel Sanders; llvm-dev@lists.llvm.org
Subject: Re: [llvm-dev] InlineAsm and allocation to wrong register for indirect access

> Hi,
>
> I'm not sure where this decision is done but it's possible that
> there's no constraint-specific selection of register classes for
> memory operands at the moment in which case it probably uses
> ${Target}RegisterInfo::getPointerRegClass() without checking the
> constraint code. I had a similar problem with constraint-specific
> offset ranges a year or so ago and found that all memory constraints
> were hardcoded to be 'm' regardless of the constraint in the inline
> assembly statement.
>

Thanks Daniel,

I found the problem to be on our SelectInlineAsmMemoryOperand which was
not returning the correct operand. Now, if I implement it similarly to
PPC by returning a COPY_TO_REGCLASS of the operand, I get the correct
operand but with the strange offset.

So a load from an operand to r0: mov r0, %0, where %0 has 'm' constraint
is transformed into mov r0, @r4+12. r4 is the correct choice for a load
but I have no idea where `+12` comes from.

Do you know how to find where this offset could be added? The IR doesn't
show the operand show it's impossible to tell from a straightforward
debug dump.

--
Paulo Matos

One place Mips does it is in SelectInlineAsmMemoryOperand() (the second operand we push to OutOps is an offset) but if you're doing things the same way as PowerPC then it won't be that since it only pushes the base to OutOps.

It might be introduced when the compiler eliminates the frameindex placeholders. If that's the case you then you should be able to trace the offset back to a <frameindex> in the -print-after-all output. Simon fixed this problem for Mips in https://reviews.llvm.org/rL275786 when he made ${Target}RegisterInfo::eliminateFI() (it's called eliminateFrameIndex() on PowerPC) enforce the correct limit on the offsets for Constraint_ZC.