Basic Jump indirect

Hallo,

I am trying to build a backend for a simple 16-bit CPU with a very small instruction set of only 24 instructions called PROL16 is used to teach CPU architecture and chip design.

I am using Fraser Cormack and Pierre-Andre Saulais LEG CPU (https://github.com/frasercrmck/llvm-leg) as starting point.

I do struggle with the concept of indirect loads and jumps where the address to jump has to be save in an register first.

So my jump looks like this:

jump r3

where register r3 is containing the address to jump to.

When I change the InstrInfo.td from a direct jump like this:

let isTerminator = 1, isBranch = 1, isBarrier = 1 in {
def B : InstLEG<(outs), (ins b_target:$dst),
“b $dst”, [(br bb:$dst)]> {
bits<24> dst;
let Inst{31-28} = 0b0000;
let Inst{27-24} = 0b1010;
let Inst{23-0} = dst;
}
}

to register based like:

def SDT_LEGJmpLink : SDTypeProfile<0, 1, [SDTCisVT<0, iPTR>]>;
def LEGJmpLink : SDNode<“LEG::B”,SDT_LEGJmpLink,
[SDNPHasChain, SDNPOutGlue, SDNPOptInGlue,
SDNPVariadic]>;

let isTerminator = 1, isBranch = 1, isBarrier = 1 in {
def B : InstLEG<(outs), (ins GRRegs:$Ra, variable_ops),
“JUMP”, [(LEGJmpLink GRRegs:$Ra)]> {
bits<24> dst;
let Inst{31-28} = 0b0000;
let Inst{27-24} = 0b1010;
//let Inst{23-0} = dst;
}
}

def : Pat<(LEGJmpLink (i32 tglobaladdr:$dst)),
(B tglobaladdr:$dst)>;
def : Pat<(LEGJmpLink (i32 texternalsym:$dst)),
(B texternalsym:$dst)>;

This is used in CPU0, MIPS and LEG for call.

When I translate my test IR code LLVM is unable to match the Branch.

LLVM ERROR: Cannot select: 0x9f32948: ch = br 0x9f32504, 0x9f328ac [ORD=13] [ID=20]
In function: _Z17test_add_overflowv

I clearly do not understand how the concept for loading an address to a register works in LLVM.

For some insights I would be very thankful.

BR

Georg

In order to have a value in a register, it needs to have a type that the given register can contain. The b_target from your first definition is likely not of any type that can end up in a register. The patterns you defined later only work for tglobaladdr and texternalsym, neither of which represents a target of a typical branch in the IR. If your target only supports indirect branches, you'd need to "legalize" all branches from "br bb:$block" to something like "brind (blockaddress $block)".

If you want the instruction selection to assign a value to a register, that value must already exist in the program. Basic blocks are not referred to via their addresses, so in order to obtain an address of a basic block you need to insert code that will generate it. Branches to global addresses are, by definition, branches where the target is already given as an address. The pattern matching only matches the expression tree (well, a piece of a DAG, to be precise) to a given instruction definition and it will generate a register if it matches an instruction that expects an operand in a register. (Strictly speaking, a register which can hold that type of a value: addresses may be of type i32 or i64, and so the instruction's input register must be from a register class associated with i32 or i64 respectively).

-Krzysztof