Generate Register Indirect mode instruction

Hi All,

I am new to llvm backend. I am trying out few examples to understand backend codegen. I have ported llvm LEG @ https://github.com/frasercrmck/llvm-leg to llvm 3.9 successfully.

Currently, the LEG instructions are RISC load-store type instruction. I want to generate some instructions for register indirect mode, like following:

IR:

@a = local_unnamed_addr global i32 0, align 4
@b = local_unnamed_addr global i32 0, align 4
@c = local_unnamed_addr global i32 0, align 4

; Function Attrs: norecurse nounwind
define void @foo() {
entry:
%0 = load i32, i32* @a, align 4
%1 = load i32, i32* @b, align 4
%add = add nsw i32 %1, %0
store i32 %add, i32* @c, align 4
ret void
}

Expected assembly instructions:

MOV R0, #A // R0 pointing to address of A

MOV R1, #B // R1 pointing to address of B

ADD *R0, *R1 // Adding both memory operands

MOV #C, *R0 // Moving result to address of C

How should i define such mov and add instruction in my .td files? How will ISD::LOAD be seleted in ISelDAGtoDAG in select() function? I want to start with simple .td definitions and would later like to encapsulate them in multiclass once basic example works.

Can someone please help how to achieve this?

Regards,

Alex

Alex,

So, you are trying to do direct mem to mem add?

Like: ADD A, B, C

-Ryan

Hi Ryan,

Somewhat yes. But the memory locations should be pointed by registers. Essentially, load the address of memory location onto the registers and then use them to point to memory location.

Regards,
Alex

Could you eliminate the load in the DAG and propagate the address to the add? Have you tried this, I’m curious.

Then in table gen, just match the add appropriately.

-Ryan

Hi Ryan,

Do you mean something like this -

@a = local_unnamed_addr global i32 0, align 4
@b = local_unnamed_addr global i32 0, align 4
@c = local_unnamed_addr global i32 0, align 4

; Function Attrs: norecurse nounwind
define void @foo() {
entry:
%add = add nsw i32 @a, @b

store i32 %add, i32* @c, align 4
ret void
}

If yes, should this be done at IR level or SelectionDAG? Any side effect of doing it at IR level?

But above seems memory to memory without involving registers to point to memory locations, which doesn’t match the addressing mode of my target.

Thanks.

Regards,
Alex

You probably want to look at the x86 backend; it has a lot of instructions which involve both computation and memory. Take the following IR, a variant of your example:

define void @foo(i32 *%a, i32 *%b, i32 *%c) {
entry:
   %0 = load i32, i32* %a, align 4
   %1 = load i32, i32* %b, align 4
   %add = add nsw i32 %1, %0
   store i32 %add, i32* %c, align 4
   ret void
}

The x86 backend generates the following:

         movl (%rsi), %eax
         addl (%rdi), %eax
         movl %eax, (%rdx)
         retq

Note in particular the memory operand embedded into the addition.

The way the LLVM x86 backend models this is just to pattern match it during instruction selection: it matches a pattern like (add r, (load addr)) to a single instruction.

-Eli

You probably want to look at the x86 backend; it has a lot of instructions which involve both computation and memory. Take the following IR, a variant of your example:

define void @foo(i32 *%a, i32 %b, i32 %c) {
entry:
%0 = load i32, i32
%a, align 4
%1 = load i32, i32
%b, align 4

%add = add nsw i32 %1, %0
store i32 %add, i32* %c, align 4
ret void
}

The x86 backend generates the following:

movl (%rsi), %eax
addl (%rdi), %eax
movl %eax, (%rdx)
retq

Note in particular the memory operand embedded into the addition.

The way the LLVM x86 backend models this is just to pattern match it during instruction selection: it matches a pattern like (add r, (load addr)) to a single instruction.

Thanks Eli. I will have a look into it. However, the above x86 code loads the content of the memory location into eax register and adds that register with another memory location.

My target loads the address of the memory locations in the registers for both the operands and then uses add operation on the registers in an indirect way. How do I specify that in .td files so that it matches in ISelDAGToDAG select() function? Any small example?

Thanks for example code :slight_smile:

Regards,
Alex

He’s trying to load the memory address of the pointer. The (add r, (load addr)) is what we use for direct memory.

I think you’ll probably have to do a post iSel MI pass.

Oh, you mean the result goes into memory, not a register? So, something like the following:

define void @foo(i32 *%a) {
entry:
   %0 = load i32, i32* %a, align 4
   %add = add i32 %0, 3
   store i32 %add, i32* %a, align 4
   ret void
}

On x86, this gets turned into:

         addl $3, (%rdi)
         retq

From X86InstrArithmetic.td:

// BinOpMI8_RMW - Instructions like "add [mem], imm8".
class BinOpMI8_RMW<string mnemonic, X86TypeInfo typeinfo,
                    SDPatternOperator opnode, Format f>
   : BinOpMI8<mnemonic, typeinfo, f,
              [(store (opnode (load addr:$dst),
                              typeinfo.Imm8Operator:$src), addr:$dst),
               (implicit EFLAGS)]>;

-Eli

Yes the result goes into memory. But the address of that destination memory location also needs to be loaded first into a register.

Thanks.

Regards,
Alex

Your architecture has a single instruction for the following operation? define void @foo(i32 %a, i32%b) { entry: %l1 = load i32*, i32** %a, align 4 %l2 = load i32, i32* %l1, align 4 %l3 = load i32*, i32** %b, align 4 %l4 = load i32, i32* %l3, align 4 %add = add i32 %l2, %l4 store i32 %add, i32* %l1, align 4 ret void } In theory, it should be possible to match this, at least using C++ code. There isn’t any other architecture like that in LLVM, though, so I’m not sure how that would work out in practice. -Eli

If I understand correctly:

%v1 = load i32, i32* %a
%v2 = load i32, i32* %b
%v3 = add i32 %v1, %v2
store i32 %v3, i32* %c

maps to (using invented mnemonics):

ASSIGN R0, %a
ASSIGN R1, %b
ASSIGN R2, %c
ADD *R2, *R0, *R1

I.e. pattern
   (store %c, (add (load %a), (load %b)))
becomes
   (ADD (ASSIGN R2, %c), (ASSIGN R0, %a), (ASSIGN R1, %b))

-Krzysztof

If I understand correctly:

%v1 = load i32, i32* %a
%v2 = load i32, i32* %b
%v3 = add i32 %v1, %v2
store i32 %v3, i32* %c

maps to (using invented mnemonics):

ASSIGN R0, %a
ASSIGN R1, %b
ASSIGN R2, %c
ADD *R2, *R0, *R1

I.e. pattern
(store %c, (add (load %a), (load %b)))
becomes
(ADD (ASSIGN R2, %c), (ASSIGN R0, %a), (ASSIGN R1, %b))

Yes. Exactly.

Regards,
Alex

Gentle Ping !!

I would appreciate any help on this. I want to generate following as described by Krzysztof :

%v1 = load i32, i32* %a
%v2 = load i32, i32* %b
%v3 = add i32 %v1, %v2
store i32 %v3, i32* %c

maps to (using invented mnemonics):

ASSIGN R0, %a
ASSIGN R1, %b
ASSIGN R2, %c
ADD *R2, *R0, *R1

Thanks.

Regards,
Alex

I was under the impression his answer was correct from your reply, no?

Hi Ryan,

Yes. But I am unable to think where in the code will it go? Will it be in a .td file where I define a pattern and during InstructionSelection, the pattern matches and emits the code automatically? Or do I need to write a pass for it?

I am new to llvm backend and trying to figure out things. Any help will be a great deal.

Thanks.

Regards,
Alex

XXXInstrInfo.td (table gen instruction information where XXX is your target)

Match automatically.