diff --git a/llvm/lib/Target/AVR/AVRInstrFormats.td b/llvm/lib/Target/AVR/AVRInstrFormats.td --- a/llvm/lib/Target/AVR/AVRInstrFormats.td +++ b/llvm/lib/Target/AVR/AVRInstrFormats.td @@ -179,7 +179,8 @@ // r = src/dst register // // Note that the bit labelled 'i' above does not follow a simple pattern, -// so there exists a post encoder method to set it manually. +// so there exists a post encoder method to set it manually. Also a specified +// decoder method is needed. //===---------------------------------------------------------------------===// class FSTLD mode, dag outs, dag ins, string asmstr, list pattern> : AVRInst16 { @@ -200,6 +201,7 @@ let Inst{3 - 2} = ptrreg{1 - 0}; let Inst{1 - 0} = mode{1 - 0}; + let DecoderMethod = "decodeLoadStore"; let PostEncoderMethod = "loadStorePostEncoder"; } diff --git a/llvm/lib/Target/AVR/AVRInstrInfo.td b/llvm/lib/Target/AVR/AVRInstrInfo.td --- a/llvm/lib/Target/AVR/AVRInstrInfo.td +++ b/llvm/lib/Target/AVR/AVRInstrInfo.td @@ -177,6 +177,7 @@ let PrintMethod = "printMemri"; let EncoderMethod = "encodeMemri"; + let DecoderMethod = "decodeMemri"; let ParserMatchClass = MemriAsmOperand; } diff --git a/llvm/lib/Target/AVR/Disassembler/AVRDisassembler.cpp b/llvm/lib/Target/AVR/Disassembler/AVRDisassembler.cpp --- a/llvm/lib/Target/AVR/Disassembler/AVRDisassembler.cpp +++ b/llvm/lib/Target/AVR/Disassembler/AVRDisassembler.cpp @@ -128,6 +128,13 @@ uint64_t Address, const MCDisassembler *Decoder); +static DecodeStatus decodeMemri(MCInst &Inst, unsigned Insn, uint64_t Address, + const MCDisassembler *Decoder); + +static DecodeStatus decodeLoadStore(MCInst &Inst, unsigned Insn, + uint64_t Address, + const MCDisassembler *Decoder); + #include "AVRGenDisassemblerTables.inc" static DecodeStatus decodeFIOARr(MCInst &Inst, unsigned Insn, uint64_t Address, @@ -249,6 +256,49 @@ return MCDisassembler::Success; } +static DecodeStatus decodeMemri(MCInst &Inst, unsigned Insn, uint64_t Address, + const MCDisassembler *Decoder) { + // As in the EncoderMethod `AVRMCCodeEmitter::encodeMemri`, the memory + // address is encoded into 7-bit, in which bits 0-5 are the immediate offset, + // and the bit-6 is the pointer register bit (Z=0, Y=1). + if (Insn > 127) + return MCDisassembler::Fail; + + // Append the base register operand. + Inst.addOperand( + MCOperand::createReg((Insn & 0x40) ? AVR::R29R28 : AVR::R31R30)); + // Append the immediate offset operand. + Inst.addOperand(MCOperand::createImm(Insn & 0x3f)); + + return MCDisassembler::Success; +} + +static DecodeStatus decodeLoadStore(MCInst &Inst, unsigned Insn, + uint64_t Address, + const MCDisassembler *Decoder) { + // Decode LDD/STD with offset less than 8. + if ((Insn & 0xf000) == 0x8000) { + unsigned RegVal = GPRDecoderTable[(Insn >> 4) & 0x1f]; + unsigned RegBase = (Insn & 0x8) ? AVR::R29R28 : AVR::R31R30; + unsigned Offset = Insn & 7; // We need not consider offset > 7. + if ((Insn & 0x200) == 0) { // Decode LDD. + Inst.setOpcode(AVR::LDDRdPtrQ); + Inst.addOperand(MCOperand::createReg(RegVal)); + Inst.addOperand(MCOperand::createReg(RegBase)); + Inst.addOperand(MCOperand::createImm(Offset)); + } else { // Decode STD. + Inst.setOpcode(AVR::STDPtrQRr); + Inst.addOperand(MCOperand::createReg(RegBase)); + Inst.addOperand(MCOperand::createImm(Offset)); + Inst.addOperand(MCOperand::createReg(RegVal)); + } + return MCDisassembler::Success; + } + + // TODO: Decode ST/LD with postinc/predec properly. + return MCDisassembler::Fail; +} + static DecodeStatus readInstruction16(ArrayRef Bytes, uint64_t Address, uint64_t &Size, uint32_t &Insn) { if (Bytes.size() < 2) { diff --git a/llvm/test/MC/AVR/inst-ldd.s b/llvm/test/MC/AVR/inst-ldd.s --- a/llvm/test/MC/AVR/inst-ldd.s +++ b/llvm/test/MC/AVR/inst-ldd.s @@ -1,5 +1,6 @@ ; RUN: llvm-mc -triple avr -mattr=sram -show-encoding < %s | FileCheck %s - +; RUN: llvm-mc -filetype=obj -triple avr -mattr=sram < %s \ +; RUN: | llvm-objdump -d --mattr=sram - | FileCheck --check-prefix=INST %s foo: ldd r2, Y+2 @@ -18,3 +19,8 @@ ; CHECK: ldd r9, Z+foo ; encoding: [0x90'A',0x80'A'] ; CHECK: ; fixup A - offset: 0, value: +foo, kind: fixup_6 + +; INST: ldd r2, Y+2 +; INST: ldd r0, Y+0 +; INST: ldd r9, Z+12 +; INST: ldd r7, Z+30 diff --git a/llvm/test/MC/AVR/inst-std.s b/llvm/test/MC/AVR/inst-std.s --- a/llvm/test/MC/AVR/inst-std.s +++ b/llvm/test/MC/AVR/inst-std.s @@ -1,5 +1,6 @@ ; RUN: llvm-mc -triple avr -mattr=sram -show-encoding < %s | FileCheck %s - +; RUN: llvm-mc -filetype=obj -triple avr -mattr=sram < %s \ +; RUN: | llvm-objdump -d --mattr=sram - | FileCheck --check-prefix=INST %s foo: @@ -20,3 +21,7 @@ ; CHECK: std Y+foo, r9 ; encoding: [0x98'A',0x82'A'] ; CHECK: ; fixup A - offset: 0, value: +foo, kind: fixup_6 +; INST: std Y+2, r2 +; INST: std Y+0, r0 +; INST: std Z+12, r9 +; INST: std Z+30, r7