Instr Description Problem of MCore Backend

Hi, all:

Now I’m working on writing a backend for Moto MCore, but I don’t know how to describe some instructions.

First, I’ve already written MCoreRegisterInfo.td like these:

class MCoreReg<bits<4> num, string name> : Register {

let Namespace = “MCore”;

field bits<4> Num = num;

}

def R0 : MCoreReg< 0, “R0”>, DwarfRegNum<[ 0]>;

def R15 : MCoreReg<15, “R15”>, DwarfRegNum<[15]>;

Then, I wrote MCoreInstrFormats.td:

class MCoreInst<dag outs, dag ins, string asmstr, list pattern> : Instruction {

field bits<16> Inst;

let Namespace = “MCore”;

dag OutOperandList = outs;

dag InOperandList = ins;

let AsmString = asmstr;

let Pattern = pattern;

}

// Base Plus Index Addressing Mode
class MABase<dag outs, dag ins, string asmstr, list pattern>
: MCoreInst<outs, ins, asmstr, pattern> {
bits<2> subOp;
bits<4> Rx;

let Inst{15-6}= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
let Inst{5-4} = subOp;
let Inst{3-0} = Rx;
}

// Load/Store Register Quadrant Mode
class QuadR<bits<2> subOpVal, dag outs, dag ins, string asmstr,
list pattern> : MABase<outs, ins, asmstr, pattern> {

let subOp = subOpVal;
}

// Load/Store Multiple Register Mode
class MultR<bits<2> subOpVal, dag outs, dag ins, string asmstr,
list pattern> : MABase<outs, ins, asmstr, pattern> {

let subOp = subOpVal;
}

Finally, I don’t know how to describe following instructions in MCoreInstrInfo.td, because of its variable ins/outs. Or what other files should I use to finish this description?

// LDQ, STQ, LDM and STM are Mapping Error

// Load/Store Register Quadrant Mode

def LDQ : QuadR<0x0, // FIXME p81

(outs GPRs:$Rx), (ins GPRs:R4, GPRs:R5, GPRs:R6, GPRs:R7),

“ldq R4-R7, ($Rx)”, []>;

def STQ : QuadR<0x1,

(outs GPRs:R4, GPRs:R5, GPRs:R6, GPRs:R7), (ins GPRs:$Rx),

“stq R4-R7, ($Rx)”, []>;

// Load/Store Multiple Register Mode

def LDM : MultR<0x2, // FIXME p80

(outs GPRs:R0), (ins GPRs:$Rf),

“ldm $Rf-R15, (R0)”, []>;

def STM : MultR<0x3, // FIXME p109

(outs GPRs:$Rf), (ins GPRs:R0),

“stm $Rf-R15, (R0)”, []>;

Info below comes from MCore Programmers Reference Manual:

LDQ - Load Register Quadrant from Memory
Operation:
Destination registers ← memory;
Assembler Syntax:
ldq r4–r7,(rx)
Description:
The ldq instruction is used to load four registers (R4–R7) from memory.
Register X points to the location of the first transfer. Registers are loaded in
increasing significance from ascending memory locations. If register X is specified to be R4,
R5, R6, or R7, the instruction form is considered invalid, and the results are undefined.
For valid instruction forms, register X is not affected or updated.
Condition Code:
Unaffected

Instruction Fields:
Register X — Specifies the base address for the transfers. Register X should not
specify R4, R5, R6, or R7.

LDM - Load Multiple Registers from Memory

Operation:
Destination Registers ← Memory
Assembler Syntax:
ldm rf–r15,(r0)
Description:
The ldm instruction is used to load a contiguous range of registers from the stack.
Register 0 (R0) serves as the base address pointer for this form. Registers

Rf–R15 are loaded in increasing significance from ascending memory locations. Rf

may not specify R0 or R15; these instruction forms are considered illegal, although

they are not guaranteed to be detected by hardware. For valid instruction forms,
register 0 (R0) is not affected or updated.

Condition Code:

Unaffected

Instruction Fields:
Register First field — Specifies the first register to be transferred. Only R1–R14 should be specified.

STM - Store Multiple Registers to Memory
Operation:
Memory ← Source Registers
Assembler Syntax:
stm rf–r15,(r0)
Description:
Store multiple registers to memory. The stm instruction is used to transfer
a contiguous range of registers to the stack. Register 0 (R0) serves as the base
address pointer for this form. Registers Rf –R15 are stored in increasing significance
to ascending memory locations. Register 0 (R0) is not affected/updated. Rf may not
specify R0 or R15; these instruction forms are considered illegal, although they are
not guaranteed to be detected by hardware.

Condition Code:

Instruction Fields: same to LDM

STQ - Store Register Quadrant to Memory
Operation:
Memory ← Source Registers
Assembler Syntax:
stq r4–r7,(rx)
Description:
Store register quadrant to memory. The stq instruction is used to transfer
the contents of four registers (R4–R7) to memory. Register X points to the location
of the first transfer. Registers are stored in increasing significance to ascending
memory locations. Register X is not affected or updated. If register X is part of the
quadrant being transferred, the value stored for this register is undefined.
Condition Code:
Instruction Fields: same to LDQ

Hello

Finally, I don't know how to describe following instructions in
MCoreInstrInfo.td, because of its variable ins/outs. Or what other files
should I use to finish this description?

Do you need the isel support for them? If yes, then you should custom
isel them. iirc ARM and SystemZ backends have similar instructions,
while only the first one supports full isel for them. In short: you
should recognize the consecutive loads / stores and turn them into
load/store multiple.

If you just need the have assembler support, then you don't need to
specify the exact operands there (for "Q" instructions), since they
are fixed. Just provide the list of used / clobbered instructions.

Hi,

I have another puzzle.

In SPARC, load / store instructions form as below:

def MEMri : Operand {
let PrintMethod = “printMemOperand”;
let MIOperandInfo = (ops IntRegs, i32imm);
}

def ADDRri : ComplexPattern<i32, 2, “SelectADDRri”, [frameindex], []>;

def LDSBri : F3_2<3, 0bxxxxx,
(outs IntRegs:$dst),
(ins MEMri:$addr),
“ldsb [$addr], $dst”,
[(set IntRegs:$dst, (sextloadi8 ADDRri:$addr))]>;

def STBri : F3_2<3, 0bxxxx,
(outs), (ins MEMri:$addr, IntRegs:$src),
“stb $src, [$addr]”,
[(truncstorei8 IntRegs:$src, ADDRri:$addr)]>;

I means that in Sparc, the memory address in ld/st instruction is one operand, but in MCore, ld.b, which means load byte, forms as “ld.b Rz, (Rx, Disp)”. It means that move MEM[Rx + unsigned Imm4 << 1] to Rz. Disp is obtained by taking the Imm4 field, scaling by the size of the load, and zero-extending.

def disp : Operand {
let PrintMethod = “printZExtConstOperand<4>”;
// I knew it’s wrong code, I need to shift left by {0, 1, 2} here,
// and then zero-extend.
// 0 for word, 1 for byte, and 2 for halfword.
}

def LDB : MARc4<0xa,
(outs GPRs:$Rz), (ins GPRs:$Rx, disp:$Imm4),
“ld.b $Rz, ($Rx, $Imm4)”,
// how do I use $Imm4 to form a $Disp by shifting left once?
[(set GPRs:$Rz, (loadi8 (add GPRs:$Rx, uimm4:$Imm4)))]>;
// and how do I use ComplexPattern to form a memory address?

STB means MEM[Rx + unsigned Imm4 << 1] ← Rz

def STB : MARc4<0xb,
(outs), (ins GPRs:$Rz, disp:$Imm4. GPRs:$Rx),
“st.b $Rz, ($Rx, $Imm4)”,
[(truncstorei8 GPRs:$Rz, (add GPRs:$Rx, uimm4:$Imm4))]>;
// how to deal with uimm4? I have no idea to construct it as a calculated memory address.

In MCore, Memory access to unsigned byte-sized data is directly supported through the ld.b(load byte) and st.b (store byte) instructions. Signed byte-sized access requires a sextb (sign extension) instruction after the ld.b. That’s why I use loadi8 instead of zextloadi8 in Sparc.

Thanks a lot!

Hello

Finally, I don’t know how to describe following instructions in
MCoreInstrInfo.td, because of its variable ins/outs. Or what other files
should I use to finish this description?

Do you need the isel support for them? If yes, then you should custom
isel them. iirc ARM and SystemZ backends have similar instructions,
while only the first one supports full isel for them. In short: you
should recognize the consecutive loads / stores and turn them into
load/store multiple.

Yes, I would implement whole back-end to assembly code printing.

If you just need the have assembler support, then you don’t need to
specify the exact operands there (for “Q” instructions), since they
are fixed. Just provide the list of used / clobbered instructions.

Yeah, It’s a good idea!