I’m attempting to implement codegen support for the AVR ST/LD family of instructions.
The binary encoding is not particularly consistent – take a look at this table of variants of LD, along with their machine code representation:
load 8 bits from pointer register X into general purpose Rd
ld Rd, X 1001 000d dddd 1100
ld Rd, X+ 1001 000d dddd 1101
(load with postincrement)
ld Rd, -X 1001 000d dddd 1110
(load with predecrement)
ld Rd, Y 1000 000d dddd 1000
ld Rd, Y+ 1001 000d dddd 1001
ld Rd, -Y 1001 000d dddd 1010
ld Rd, Z 1000 000d dddd 0000
ld Rd, Z+ 1001 000d dddd 0001
ld Rd, -Z 1001 000d dddd 0010
^
Note this one inconsistent bit
One way to solve this solution would be to to describe them in InstrInfo.td as seperate instructions. Note that R27R26 is a pointer register defined in AVRRegisterInfo.td, and ‘X’ is an alias for this.
let Uses = [R27R26],
canFoldAsLoad = 1,
isReMaterializable = 1 in
def LDRdX : FSTLDPtrReg<0b0,
(outs GPR8:$reg),
(ins),
"ld\t$reg, X",
[(set GPR8:$reg, (load R27R26))]>;
def LDRdY : FSTLDPtrReg<0b0,
// ...
When I do this, however, I get errors that the pointer register is an invalid operand type.
Another solution might be to have a generic ‘LD’ pseudo instruction, which is later lowered into one of the 9 variants, which each have the correct encoding. This is a messy, hacky solution, which also bloats the code a fair bit more.
One last solution is to ‘make up a pattern’ for the inconsistent bit that fits.
It is:
Inconsistent bit = (postinc OR predec) OR IsPtrXReg
Where ‘postinc’ and ‘predec’ is 1 if the respective mode is used, and 0 otherwise, and IsPtrXReg is 1 if the pointer register is X.
I have tried to assign this bit using this expression with macros in AVRInstrInfo.td, but I couldn’t get it to compile (!or is not defined, and I don’t think macros will solve this situation regardless).