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:
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.
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).