ARM: fix thumb literal loads decoding
authorAmaury de la Vieuville <amaury.dlv@gmail.com>
Tue, 18 Jun 2013 08:03:06 +0000 (08:03 +0000)
committerAmaury de la Vieuville <amaury.dlv@gmail.com>
Tue, 18 Jun 2013 08:03:06 +0000 (08:03 +0000)
This fixes two previous issues:
- Negative offsets were not correctly disassembled
- The decoded opcodes were not the right one

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@184180 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/ARM/ARMInstrThumb2.td
lib/Target/ARM/Disassembler/ARMDisassembler.cpp
lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp
test/MC/Disassembler/ARM/thumb2.txt

index 8b114a8326485caea17cfada8181642f3d8d663c..da296dcd8a6422bb5f0c07df38490ac7067d2993 100644 (file)
@@ -959,6 +959,8 @@ multiclass T2I_ld<bit signed, bits<2> opcod, string opc,
     let Inst{19-16} = addr{16-13}; // Rn
     let Inst{15-12} = Rt;
     let Inst{11-0}  = addr{11-0};  // imm
+
+    let DecoderMethod = "DecodeT2LoadImm12";
   }
   def i8  : T2Ii8 <(outs target:$Rt), (ins t2addrmode_negimm8:$addr), iii,
                    opc, "\t$Rt, $addr",
@@ -979,6 +981,8 @@ multiclass T2I_ld<bit signed, bits<2> opcod, string opc,
     let Inst{9}     = addr{8};    // U
     let Inst{8} = 0; // The W bit.
     let Inst{7-0}   = addr{7-0};  // imm
+
+    let DecoderMethod = "DecodeT2LoadImm8";
   }
   def s   : T2Iso <(outs target:$Rt), (ins t2addrmode_so_reg:$addr), iis,
                    opc, ".w\t$Rt, $addr",
@@ -1019,6 +1023,8 @@ multiclass T2I_ld<bit signed, bits<2> opcod, string opc,
     bits<12> addr;
     let Inst{15-12} = Rt{3-0};
     let Inst{11-0}  = addr{11-0};
+
+    let DecoderMethod = "DecodeT2LoadLabel";
   }
 }
 
@@ -1228,15 +1234,15 @@ defm t2LDR   : T2I_ld<0, 0b10, "ldr", IIC_iLoad_i, IIC_iLoad_si, GPR,
 
 // Loads with zero extension
 defm t2LDRH  : T2I_ld<0, 0b01, "ldrh", IIC_iLoad_bh_i, IIC_iLoad_bh_si,
-                      rGPR, UnOpFrag<(zextloadi16 node:$Src)>>;
+                      GPR, UnOpFrag<(zextloadi16 node:$Src)>>;
 defm t2LDRB  : T2I_ld<0, 0b00, "ldrb", IIC_iLoad_bh_i, IIC_iLoad_bh_si,
-                      rGPR, UnOpFrag<(zextloadi8  node:$Src)>>;
+                      GPR, UnOpFrag<(zextloadi8  node:$Src)>>;
 
 // Loads with sign extension
 defm t2LDRSH : T2I_ld<1, 0b01, "ldrsh", IIC_iLoad_bh_i, IIC_iLoad_bh_si,
-                      rGPR, UnOpFrag<(sextloadi16 node:$Src)>>;
+                      GPR, UnOpFrag<(sextloadi16 node:$Src)>>;
 defm t2LDRSB : T2I_ld<1, 0b00, "ldrsb", IIC_iLoad_bh_i, IIC_iLoad_bh_si,
-                      rGPR, UnOpFrag<(sextloadi8  node:$Src)>>;
+                      GPR, UnOpFrag<(sextloadi8  node:$Src)>>;
 
 let mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1 in {
 // Load doubleword
@@ -1373,6 +1379,8 @@ class T2IldT<bit signed, bits<2> type, string opc, InstrItinClass ii>
   let Inst{11} = 1;
   let Inst{10-8} = 0b110; // PUW.
   let Inst{7-0} = addr{7-0};
+
+  let DecoderMethod = "DecodeT2LoadT";
 }
 
 def t2LDRT   : T2IldT<0, 0b10, "ldrt", IIC_iLoad_i>;
index 196fc32f48e05573b7c9b709dace8b2707b88c6c..39a5af9e60555c4b14a1a4beafb68298be7aa073 100644 (file)
@@ -347,6 +347,14 @@ static DecodeStatus DecodeT2AddrModeSOReg(MCInst &Inst, unsigned Val,
                                uint64_t Address, const void *Decoder);
 static DecodeStatus DecodeT2LoadShift(MCInst &Inst, unsigned Val,
                                uint64_t Address, const void *Decoder);
+static DecodeStatus DecodeT2LoadImm8(MCInst &Inst, unsigned Insn,
+                               uint64_t Address, const void* Decoder);
+static DecodeStatus DecodeT2LoadImm12(MCInst &Inst, unsigned Insn,
+                               uint64_t Address, const void* Decoder);
+static DecodeStatus DecodeT2LoadT(MCInst &Inst, unsigned Insn,
+                               uint64_t Address, const void* Decoder);
+static DecodeStatus DecodeT2LoadLabel(MCInst &Inst, unsigned Insn,
+                               uint64_t Address, const void* Decoder);
 static DecodeStatus DecodeT2Imm8S4(MCInst &Inst, unsigned Val,
                                uint64_t Address, const void *Decoder);
 static DecodeStatus DecodeT2AddrModeImm8s4(MCInst &Inst, unsigned Val,
@@ -3188,19 +3196,9 @@ static DecodeStatus DecodeT2LoadShift(MCInst &Inst, unsigned Insn,
                               uint64_t Address, const void *Decoder) {
   DecodeStatus S = MCDisassembler::Success;
 
-  switch (Inst.getOpcode()) {
-    case ARM::t2PLDs:
-    case ARM::t2PLDWs:
-    case ARM::t2PLIs:
-      break;
-    default: {
-      unsigned Rt = fieldFromInstruction(Insn, 12, 4);
-      if (!Check(S, DecoderGPRRegisterClass(Inst, Rt, Address, Decoder)))
-    return MCDisassembler::Fail;
-    }
-  }
-
+  unsigned Rt = fieldFromInstruction(Insn, 12, 4);
   unsigned Rn = fieldFromInstruction(Insn, 16, 4);
+
   if (Rn == 0xF) {
     switch (Inst.getOpcode()) {
       case ARM::t2LDRBs:
@@ -3215,19 +3213,32 @@ static DecodeStatus DecodeT2LoadShift(MCInst &Inst, unsigned Insn,
       case ARM::t2LDRSBs:
         Inst.setOpcode(ARM::t2LDRSBpci);
         break;
-      case ARM::t2PLDs:
+      case ARM::t2LDRs:
+        Inst.setOpcode(ARM::t2LDRpci);
+        break;
+      case ARM::t2PLDs: {
         Inst.setOpcode(ARM::t2PLDi12);
         Inst.addOperand(MCOperand::CreateReg(ARM::PC));
-        break;
+        int imm = fieldFromInstruction(Insn, 0, 12);
+        if (!fieldFromInstruction(Insn, 23, 1)) imm *= -1;
+        Inst.addOperand(MCOperand::CreateImm(imm));
+        return S;
+      }
       default:
         return MCDisassembler::Fail;
     }
 
-    int imm = fieldFromInstruction(Insn, 0, 12);
-    if (!fieldFromInstruction(Insn, 23, 1)) imm *= -1;
-    Inst.addOperand(MCOperand::CreateImm(imm));
+    return DecodeT2LoadLabel(Inst, Insn, Address, Decoder);
+  }
 
-    return S;
+  switch (Inst.getOpcode()) {
+    case ARM::t2PLDs:
+    case ARM::t2PLDWs:
+    case ARM::t2PLIs:
+      break;
+    default:
+      if (!Check(S, DecodeGPRRegisterClass(Inst, Rt, Address, Decoder)))
+        return MCDisassembler::Fail;
   }
 
   unsigned addrmode = fieldFromInstruction(Insn, 4, 2);
@@ -3239,6 +3250,154 @@ static DecodeStatus DecodeT2LoadShift(MCInst &Inst, unsigned Insn,
   return S;
 }
 
+static DecodeStatus DecodeT2LoadImm8(MCInst &Inst, unsigned Insn,
+                                uint64_t Address, const void* Decoder) {
+  DecodeStatus S = MCDisassembler::Success;
+
+  unsigned Rn = fieldFromInstruction(Insn, 16, 4);
+  unsigned Rt = fieldFromInstruction(Insn, 12, 4);
+  unsigned U = fieldFromInstruction(Insn, 9, 1);
+  unsigned imm = fieldFromInstruction(Insn, 0, 8);
+  imm |= (U << 8);
+  imm |= (Rn << 9);
+
+  if (Rn == 15) {
+    switch (Inst.getOpcode()) {
+    case ARM::t2LDRi8:
+      Inst.setOpcode(ARM::t2LDRpci);
+      break;
+    case ARM::t2LDRBi8:
+      Inst.setOpcode(ARM::t2LDRBpci);
+      break;
+    case ARM::t2LDRSBi8:
+      Inst.setOpcode(ARM::t2LDRSBpci);
+      break;
+    case ARM::t2LDRHi8:
+      Inst.setOpcode(ARM::t2LDRHpci);
+      break;
+    case ARM::t2LDRSHi8:
+      Inst.setOpcode(ARM::t2LDRSHpci);
+      break;
+    default:
+      return MCDisassembler::Fail;
+    }
+    return DecodeT2LoadLabel(Inst, Insn, Address, Decoder);
+  }
+
+  if (!Check(S, DecodeGPRRegisterClass(Inst, Rt, Address, Decoder)))
+    return MCDisassembler::Fail;
+  if (!Check(S, DecodeT2AddrModeImm8(Inst, imm, Address, Decoder)))
+    return MCDisassembler::Fail;
+  return S;
+}
+
+static DecodeStatus DecodeT2LoadImm12(MCInst &Inst, unsigned Insn,
+                                uint64_t Address, const void* Decoder) {
+  DecodeStatus S = MCDisassembler::Success;
+
+  unsigned Rn = fieldFromInstruction(Insn, 16, 4);
+  unsigned Rt = fieldFromInstruction(Insn, 12, 4);
+  unsigned imm = fieldFromInstruction(Insn, 0, 12);
+  imm |= (Rn << 13);
+
+  if (Rn == 15) {
+    switch (Inst.getOpcode()) {
+    case ARM::t2LDRi12:
+      Inst.setOpcode(ARM::t2LDRpci);
+      break;
+    case ARM::t2LDRHi12:
+      Inst.setOpcode(ARM::t2LDRHpci);
+      break;
+    case ARM::t2LDRSHi12:
+      Inst.setOpcode(ARM::t2LDRSHpci);
+      break;
+    case ARM::t2LDRBi12:
+      Inst.setOpcode(ARM::t2LDRBpci);
+      break;
+    case ARM::t2LDRSBi12:
+      Inst.setOpcode(ARM::t2LDRSBpci);
+      break;
+    default:
+      return MCDisassembler::Fail;
+    }
+    return DecodeT2LoadLabel(Inst, Insn, Address, Decoder);
+  }
+
+  if (!Check(S, DecodeGPRRegisterClass(Inst, Rt, Address, Decoder)))
+    return MCDisassembler::Fail;
+  if (!Check(S, DecodeT2AddrModeImm12(Inst, imm, Address, Decoder)))
+    return MCDisassembler::Fail;
+  return S;
+}
+
+static DecodeStatus DecodeT2LoadT(MCInst &Inst, unsigned Insn,
+                                uint64_t Address, const void* Decoder) {
+  DecodeStatus S = MCDisassembler::Success;
+
+  unsigned Rn = fieldFromInstruction(Insn, 16, 4);
+  unsigned Rt = fieldFromInstruction(Insn, 12, 4);
+  unsigned imm = fieldFromInstruction(Insn, 0, 8);
+  imm |= (Rn << 9);
+
+  if (Rn == 15) {
+    switch (Inst.getOpcode()) {
+    case ARM::t2LDRT:
+      Inst.setOpcode(ARM::t2LDRpci);
+      break;
+    case ARM::t2LDRBT:
+      Inst.setOpcode(ARM::t2LDRBpci);
+      break;
+    case ARM::t2LDRHT:
+      Inst.setOpcode(ARM::t2LDRHpci);
+      break;
+    case ARM::t2LDRSBT:
+      Inst.setOpcode(ARM::t2LDRSBpci);
+      break;
+    case ARM::t2LDRSHT:
+      Inst.setOpcode(ARM::t2LDRSHpci);
+      break;
+    default:
+      return MCDisassembler::Fail;
+    }
+    return DecodeT2LoadLabel(Inst, Insn, Address, Decoder);
+  }
+
+  if (!Check(S, DecoderGPRRegisterClass(Inst, Rt, Address, Decoder)))
+    return MCDisassembler::Fail;
+  if (!Check(S, DecodeT2AddrModeImm8(Inst, imm, Address, Decoder)))
+    return MCDisassembler::Fail;
+  return S;
+}
+
+static DecodeStatus DecodeT2LoadLabel(MCInst &Inst, unsigned Insn,
+                                uint64_t Address, const void* Decoder) {
+  DecodeStatus S = MCDisassembler::Success;
+
+  unsigned Rt = fieldFromInstruction(Insn, 12, 4);
+  unsigned U = fieldFromInstruction(Insn, 23, 1);
+  int imm = fieldFromInstruction(Insn, 0, 12);
+
+  // FIXME: detect and decode PLD properly
+  if (Inst.getOpcode() == ARM::t2LDRBpci && Rt == 15) {
+    Inst.setOpcode(ARM::t2PLDi12);
+    Inst.addOperand(MCOperand::CreateReg(ARM::PC));
+  } else {
+    if (!Check(S, DecodeGPRRegisterClass(Inst, Rt, Address, Decoder)))
+      return MCDisassembler::Fail;
+  }
+
+  if (!U) {
+    // Special case for #-0.
+    if (imm == 0)
+      imm = INT32_MIN;
+    else
+      imm = -imm;
+  }
+  Inst.addOperand(MCOperand::CreateImm(imm));
+
+  return S;
+}
+
 static DecodeStatus DecodeT2Imm8S4(MCInst &Inst, unsigned Val,
                            uint64_t Address, const void *Decoder) {
   if (Val == 0)
@@ -3353,6 +3512,34 @@ static DecodeStatus DecodeT2LdStPre(MCInst &Inst, unsigned Insn,
   addr |= Rn << 9;
   unsigned load = fieldFromInstruction(Insn, 20, 1);
 
+  if (Rn == 15) {
+    switch (Inst.getOpcode()) {
+    case ARM::t2LDR_PRE:
+    case ARM::t2LDR_POST:
+      Inst.setOpcode(ARM::t2LDRpci);
+      break;
+    case ARM::t2LDRB_PRE:
+    case ARM::t2LDRB_POST:
+      Inst.setOpcode(ARM::t2LDRBpci);
+      break;
+    case ARM::t2LDRH_PRE:
+    case ARM::t2LDRH_POST:
+      Inst.setOpcode(ARM::t2LDRHpci);
+      break;
+    case ARM::t2LDRSB_PRE:
+    case ARM::t2LDRSB_POST:
+      Inst.setOpcode(ARM::t2LDRSBpci);
+      break;
+    case ARM::t2LDRSH_PRE:
+    case ARM::t2LDRSH_POST:
+      Inst.setOpcode(ARM::t2LDRSHpci);
+      break;
+    default:
+      return MCDisassembler::Fail;
+    }
+    return DecodeT2LoadLabel(Inst, Insn, Address, Decoder);
+  }
+
   if (!load) {
     if (!Check(S, DecodeGPRRegisterClass(Inst, Rn, Address, Decoder)))
       return MCDisassembler::Fail;
index 0b3d266db7558c337466dfc8e19fcc2efbd988a5..0931e597d3d7618516ecafa65351ab07f53631ee 100644 (file)
@@ -315,15 +315,29 @@ void ARMInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
 void ARMInstPrinter::printThumbLdrLabelOperand(const MCInst *MI, unsigned OpNum,
                                                raw_ostream &O) {
   const MCOperand &MO1 = MI->getOperand(OpNum);
-  if (MO1.isExpr())
+  if (MO1.isExpr()) {
     O << *MO1.getExpr();
-  else if (MO1.isImm()) {
-    O << markup("<mem:") << "[pc, "
-      << markup("<imm:") << "#" << formatImm(MO1.getImm())
-      << markup(">]>", "]");
+    return;
   }
-  else
-    llvm_unreachable("Unknown LDR label operand?");
+
+  O << markup("<mem:") << "[pc, ";
+
+  int32_t OffImm = (int32_t)MO1.getImm();
+  bool isSub = OffImm < 0;
+
+  // Special value for #-0. All others are normal.
+  if (OffImm == INT32_MIN)
+    OffImm = 0;
+  if (isSub) {
+    O << markup("<imm:")
+      << "#-" << formatImm(-OffImm)
+      << markup(">");
+  } else {
+    O << markup("<imm:")
+      << "#" << formatImm(OffImm)
+      << markup(">");
+  }
+  O << "]" << markup(">");
 }
 
 // so_reg is a 4-operand unit corresponding to register forms of the A5.1
index a681e2a6f9fa3769f916e4f384924d0aacd32bc0..eb1e112d4f95c79134953589b9c16158fc0d2b40 100644 (file)
 0xd7 0xf8 0x01 0xf1
 
 
+#------------------------------------------------------------------------------
+# LDR(literal)
+#------------------------------------------------------------------------------
+# CHECK: ldr.w r4, [pc, #-0]
+# CHECK: ldr.w r2, [pc, #-40]
+# CHECK: ldr.w r1, [pc, #1024]
+0x5f 0xf8 0x00 0x40
+0x5f 0xf8 0x28 0x20
+0xdf 0xf8 0x00 0x14
+
+
 #------------------------------------------------------------------------------
 # LDR(register)
 #------------------------------------------------------------------------------
 0x1d 0xf8 0x04 0x39
 
 
+#------------------------------------------------------------------------------
+# LDRB(literal)
+#------------------------------------------------------------------------------
+# CHECK: ldrb.w r6, [pc, #-0]
+# CHECK: ldrb.w r10, [pc, #227]
+# CHECK: ldrb.w r5, [pc, #0]
+0x1f 0xf8 0x00 0x60
+0x9f 0xf8 0xe3 0xa0
+0x9f 0xf8 0x00 0x50
+
+
 #------------------------------------------------------------------------------
 # LDRBT
 #------------------------------------------------------------------------------
 # CHECK: ldrh.w r5, [r6, #33]
 # CHECK: ldrh.w r5, [r6, #257]
 # CHECK: ldrh.w lr, [r7, #257]
-# CHECK: ldrh.w r0, [pc, #-21]
 
 0x35 0xf8 0x04 0x5c
 0x35 0x8c
 0xb6 0xf8 0x21 0x50
 0xb6 0xf8 0x01 0x51
 0xb7 0xf8 0x01 0xe1
-0x3f 0xf8 0x15 0x00
 
 
 #------------------------------------------------------------------------------
 0x3d 0xf8 0x04 0x39
 
 
+#------------------------------------------------------------------------------
+# LDRH(literal)
+#------------------------------------------------------------------------------
+# CHECK: ldrh.w r7, [pc, #-0]
+# CHECK: ldrh.w r5, [pc, #121]
+# CHECK: ldrh.w r4, [pc, #0]
+0x3f 0xf8 0x00 0x70
+0xbf 0xf8 0x79 0x50
+0xbf 0xf8 0x00 0x40
+
+
 #------------------------------------------------------------------------------
 # LDRSB(immediate)
 #------------------------------------------------------------------------------
 0x1d 0xf9 0x04 0x39
 
 
+#------------------------------------------------------------------------------
+# LDRSB(literal)
+#------------------------------------------------------------------------------
+# CHECK: ldrsb.w r0, [pc, #-0]
+# CHECK: ldrsb.w r12, [pc, #80]
+# CHECK: ldrsb.w r3, [pc, #0]
+0x1f 0xf9 0x00 0x00
+0x9f 0xf9 0x50 0xc0
+0x9f 0xf9 0x00 0x30
+
+
 #------------------------------------------------------------------------------
 # LDRSBT
 #------------------------------------------------------------------------------
 0x3d 0xf9 0x04 0x39
 
 
+#------------------------------------------------------------------------------
+# LDRSH(literal)
+#------------------------------------------------------------------------------
+# CHECK: ldrsh.w r0, [pc, #-0]
+# CHECK: ldrsh.w r10, [pc, #-231]
+# CHECK: ldrsh.w r6, [pc, #0]
+0x3f 0xf9 0x00 0x00
+0x3f 0xf9 0xe7 0xa0
+0xbf 0xf9 0x00 0x60
+
+
 #------------------------------------------------------------------------------
 # LDRSHT
 #------------------------------------------------------------------------------