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 @@ -460,6 +460,8 @@ let Inst{15 - 13} = 0b110; let Inst{12} = f; let Inst{11 - 0} = k; + + let DecoderMethod = "decodeFBRk"; } //===----------------------------------------------------------------------===// 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 @@ -123,6 +123,9 @@ static DecodeStatus decodeMemri(MCInst &Inst, unsigned Insn, uint64_t Address, const MCDisassembler *Decoder); +static DecodeStatus decodeFBRk(MCInst &Inst, unsigned Insn, uint64_t Address, + const MCDisassembler *Decoder); + static DecodeStatus decodeLoadStore(MCInst &Inst, unsigned Insn, uint64_t Address, const MCDisassembler *Decoder); @@ -265,6 +268,25 @@ return MCDisassembler::Success; } +static DecodeStatus decodeFBRk(MCInst &Inst, unsigned Insn, uint64_t Address, + const MCDisassembler *Decoder) { + // Decode the opcode. + switch (Insn & 0xf000) { + case 0xc000: + Inst.setOpcode(AVR::RJMPk); + break; + case 0xd000: + Inst.setOpcode(AVR::RCALLk); + break; + default: // Unknown relative branch instruction. + return MCDisassembler::Fail; + } + // Decode the relative offset. + int16_t Offset = ((int16_t)((Insn & 0xfff) << 4)) >> 3; + Inst.addOperand(MCOperand::createImm(Offset)); + return MCDisassembler::Success; +} + static DecodeStatus decodeLoadStore(MCInst &Inst, unsigned Insn, uint64_t Address, const MCDisassembler *Decoder) { @@ -275,7 +297,7 @@ if ((Insn & 0xf000) == 0x8000) { unsigned RegBase = (Insn & 0x8) ? AVR::R29R28 : AVR::R31R30; unsigned Offset = Insn & 7; // We need not consider offset > 7. - if ((Insn & 0x200) == 0) { // Decode LDD. + if ((Insn & 0x200) == 0) { // Decode LDD. Inst.setOpcode(AVR::LDDRdPtrQ); Inst.addOperand(MCOperand::createReg(RegVal)); Inst.addOperand(MCOperand::createReg(RegBase)); diff --git a/llvm/test/MC/AVR/inst-rcall.s b/llvm/test/MC/AVR/inst-rcall.s --- a/llvm/test/MC/AVR/inst-rcall.s +++ b/llvm/test/MC/AVR/inst-rcall.s @@ -1,4 +1,6 @@ ; RUN: llvm-mc -triple avr -show-encoding < %s | FileCheck %s +; RUN: llvm-mc -filetype=obj -triple avr < %s \ +; RUN: | llvm-objdump -d - | FileCheck --check-prefix=INST %s foo: @@ -7,6 +9,7 @@ rcall .-8 rcall .+12 rcall .+46 + .short 0xdfea ; CHECK: rcall .Ltmp0+0 ; encoding: [A,0b1101AAAA] ; CHECK: ; fixup A - offset: 0, value: .Ltmp0+0, kind: fixup_13_pcrel @@ -17,3 +20,8 @@ ; CHECK: rcall .Ltmp3+46 ; encoding: [A,0b1101AAAA] ; CHECK: ; fixup A - offset: 0, value: .Ltmp3+46, kind: fixup_13_pcrel +; INST: rcall .+0 +; INST: rcall .+0 +; INST: rcall .+0 +; INST: rcall .+0 +; INST: rcall .-44 diff --git a/llvm/test/MC/AVR/inst-rjmp.s b/llvm/test/MC/AVR/inst-rjmp.s --- a/llvm/test/MC/AVR/inst-rjmp.s +++ b/llvm/test/MC/AVR/inst-rjmp.s @@ -16,6 +16,7 @@ rjmp .-6 x: rjmp x + .short 0xc00f ; CHECK: rjmp .Ltmp0+2 ; encoding: [A,0b1100AAAA] ; CHECK: ; fixup A - offset: 0, value: .Ltmp0+2, kind: fixup_13_pcrel @@ -45,3 +46,4 @@ ; INST: rjmp .+0 ; INST: rjmp .+0 ; INST: rjmp .+0 +; INST: rjmp .+30