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 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",
   }
   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 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",
   }
   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};
     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,
 
 // 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,
 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,
 
 // 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,
 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
 
 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 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>;
 }
 
 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);
                                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,
 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;
 
                               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);
   unsigned Rn = fieldFromInstruction(Insn, 16, 4);
+
   if (Rn == 0xF) {
     switch (Inst.getOpcode()) {
       case ARM::t2LDRBs:
   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::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));
         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;
     }
 
       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);
   }
 
   unsigned addrmode = fieldFromInstruction(Insn, 4, 2);
@@ -3239,6 +3250,154 @@ static DecodeStatus DecodeT2LoadShift(MCInst &Inst, unsigned Insn,
   return S;
 }
 
   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)
 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);
 
   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;
   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);
 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();
     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
 }
 
 // so_reg is a 4-operand unit corresponding to register forms of the A5.1
index a681e2a6f9fa3769f916e4f384924d0aacd32bc0..eb1e112d4f95c79134953589b9c16158fc0d2b40 100644 (file)
 0xd7 0xf8 0x01 0xf1
 
 
 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)
 #------------------------------------------------------------------------------
 #------------------------------------------------------------------------------
 # LDR(register)
 #------------------------------------------------------------------------------
 0x1d 0xf8 0x04 0x39
 
 
 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
 #------------------------------------------------------------------------------
 #------------------------------------------------------------------------------
 # LDRBT
 #------------------------------------------------------------------------------
 # CHECK: ldrh.w r5, [r6, #33]
 # CHECK: ldrh.w r5, [r6, #257]
 # CHECK: ldrh.w lr, [r7, #257]
 # 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
 
 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
 
 
 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)
 #------------------------------------------------------------------------------
 #------------------------------------------------------------------------------
 # LDRSB(immediate)
 #------------------------------------------------------------------------------
 0x1d 0xf9 0x04 0x39
 
 
 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
 #------------------------------------------------------------------------------
 #------------------------------------------------------------------------------
 # LDRSBT
 #------------------------------------------------------------------------------
 0x3d 0xf9 0x04 0x39
 
 
 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
 #------------------------------------------------------------------------------
 #------------------------------------------------------------------------------
 # LDRSHT
 #------------------------------------------------------------------------------