[AVR] Fix incorrect decoding of RJMP and RCALL
authorBen Shi <powerman1st@163.com>
Sat, 7 Jan 2023 06:33:24 +0000 (14:33 +0800)
committerBen Shi <powerman1st@163.com>
Sat, 7 Jan 2023 15:26:40 +0000 (23:26 +0800)
This patch fixes the inaccurate decoding of the offset operand of
the RCALL & RJMP instructions.

Reviewed By: aykevl, MaskRay

Differential Revision: https://reviews.llvm.org/D140815

llvm/lib/Target/AVR/AVRInstrFormats.td
llvm/lib/Target/AVR/Disassembler/AVRDisassembler.cpp
llvm/test/MC/AVR/inst-rcall.s
llvm/test/MC/AVR/inst-rjmp.s

index dd8da70..96b48a5 100644 (file)
@@ -460,6 +460,8 @@ class FBRk<bit f, dag outs, dag ins, string asmstr, list<dag> pattern>
   let Inst{15 - 13} = 0b110;
   let Inst{12} = f;
   let Inst{11 - 0} = k;
+
+  let DecoderMethod = "decodeFBRk";
 }
 
 //===----------------------------------------------------------------------===//
index d873459..7674d9e 100644 (file)
@@ -123,6 +123,9 @@ static DecodeStatus decodeFMUL2RdRr(MCInst &Inst, unsigned Insn,
 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 @@ static DecodeStatus decodeMemri(MCInst &Inst, unsigned Insn, uint64_t Address,
   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 @@ static DecodeStatus decodeLoadStore(MCInst &Inst, unsigned Insn,
   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));
index 84a7343..4e75620 100644 (file)
@@ -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 @@ foo:
   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 @@ foo:
 ; 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
index 22d9f2f..472d654 100644 (file)
@@ -16,6 +16,7 @@ end:
   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 @@ x:
 ; INST: rjmp   .+0
 ; INST: rjmp   .+0
 ; INST: rjmp   .+0
+; INST: rjmp   .+30