Improve encoding support for BLX with immediat eoperands, and fix a BLX decoding...
[oota-llvm.git] / lib / Target / ARM / Disassembler / ARMDisassembler.cpp
index db35c1891c0396fd0b4fc27f5b3fb220574b7e5a..c3ad2907c94a2c0983f26faeb1c4d1c611d8fb93 100644 (file)
 #include "llvm/MC/MCInst.h"
 #include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCContext.h"
-#include "llvm/Target/TargetRegistry.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/MemoryObject.h"
 #include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/TargetRegistry.h"
 #include "llvm/Support/raw_ostream.h"
 
 // Pull DecodeStatus and its enum values into the global namespace.
@@ -69,8 +69,6 @@ static DecodeStatus DecodeCCOutOperand(llvm::MCInst &Inst, unsigned Val,
                                uint64_t Address, const void *Decoder);
 static DecodeStatus DecodeSOImmOperand(llvm::MCInst &Inst, unsigned Val,
                                uint64_t Address, const void *Decoder);
-static DecodeStatus DecodeBLTargetOperand(llvm::MCInst &Inst, unsigned Val,
-                               uint64_t Address, const void *Decoder);
 static DecodeStatus DecodeRegListOperand(llvm::MCInst &Inst, unsigned Val,
                                uint64_t Address, const void *Decoder);
 static DecodeStatus DecodeSPRRegListOperand(llvm::MCInst &Inst, unsigned Val,
@@ -103,6 +101,8 @@ static DecodeStatus DecodeSMLAInstruction(llvm::MCInst &Inst, unsigned Insn,
                                uint64_t Address, const void *Decoder);
 static DecodeStatus DecodeCPSInstruction(llvm::MCInst &Inst, unsigned Insn,
                                uint64_t Address, const void *Decoder);
+static DecodeStatus DecodeT2CPSInstruction(llvm::MCInst &Inst, unsigned Insn,
+                               uint64_t Address, const void *Decoder);
 static DecodeStatus DecodeAddrModeImm12Operand(llvm::MCInst &Inst, unsigned Val,
                                uint64_t Address, const void *Decoder);
 static DecodeStatus DecodeAddrMode5Operand(llvm::MCInst &Inst, unsigned Val,
@@ -155,6 +155,10 @@ static DecodeStatus DecodeDoubleRegLoad(llvm::MCInst &Inst, unsigned Insn,
                                uint64_t Address, const void *Decoder);
 static DecodeStatus DecodeDoubleRegStore(llvm::MCInst &Inst, unsigned Insn,
                                uint64_t Address, const void *Decoder);
+static DecodeStatus DecodeLDRPreImm(llvm::MCInst &Inst, unsigned Insn,
+                               uint64_t Address, const void *Decoder);
+static DecodeStatus DecodeLDRPreReg(llvm::MCInst &Inst, unsigned Insn,
+                               uint64_t Address, const void *Decoder);
 static DecodeStatus DecodeSTRPreImm(llvm::MCInst &Inst, unsigned Insn,
                                uint64_t Address, const void *Decoder);
 static DecodeStatus DecodeSTRPreReg(llvm::MCInst &Inst, unsigned Insn,
@@ -180,7 +184,6 @@ static DecodeStatus DecodeVMOVSRR(llvm::MCInst &Inst, unsigned Insn,
 static DecodeStatus DecodeVMOVRRS(llvm::MCInst &Inst, unsigned Insn,
                                uint64_t Address, const void *Decoder);
 
-
 static DecodeStatus DecodeThumbAddSpecialReg(llvm::MCInst &Inst, uint16_t Insn,
                                uint64_t Address, const void *Decoder);
 static DecodeStatus DecodeThumbBROperand(llvm::MCInst &Inst, unsigned Val,
@@ -227,6 +230,10 @@ static DecodeStatus DecodeThumbBCCTargetOperand(llvm::MCInst &Inst,unsigned Val,
                                 uint64_t Address, const void *Decoder);
 static DecodeStatus DecodeThumbBLTargetOperand(llvm::MCInst &Inst, unsigned Val,
                                 uint64_t Address, const void *Decoder);
+static DecodeStatus DecodeITCond(llvm::MCInst &Inst, unsigned Val,
+                                uint64_t Address, const void *Decoder);
+static DecodeStatus DecodeITMask(llvm::MCInst &Inst, unsigned Val,
+                                uint64_t Address, const void *Decoder);
 
 #include "ARMGenDisassemblerTables.inc"
 #include "ARMGenInstrInfo.inc"
@@ -257,8 +264,10 @@ DecodeStatus ARMDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
   uint8_t bytes[4];
 
   // We want to read exactly 4 bytes of data.
-  if (Region.readBytes(Address, 4, (uint8_t*)bytes, NULL) == -1)
+  if (Region.readBytes(Address, 4, (uint8_t*)bytes, NULL) == -1) {
+    Size = 0;
     return Fail;
+  }
 
   // Encoded as a small-endian 32-bit word in the stream.
   uint32_t insn = (bytes[3] << 24) |
@@ -324,6 +333,7 @@ DecodeStatus ARMDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
 
   MI.clear();
 
+  Size = 0;
   return Fail;
 }
 
@@ -371,6 +381,8 @@ void ThumbDisassembler::AddThumbPredicate(MCInst &MI) const {
   unsigned CC;
   if (!ITBlock.empty()) {
     CC = ITBlock.back();
+    if (CC == 0xF)
+      CC = ARMCC::AL;
     ITBlock.pop_back();
   } else
     CC = ARMCC::AL;
@@ -414,7 +426,8 @@ void ThumbDisassembler::UpdateThumbVFPPredicate(MCInst &MI) const {
 
   const MCOperandInfo *OpInfo = ARMInsts[MI.getOpcode()].OpInfo;
   MCInst::iterator I = MI.begin();
-  for (unsigned i = 0, e = MI.size(); i < e; ++i, ++I) {
+  unsigned short NumOps = ARMInsts[MI.getOpcode()].NumOperands;
+  for (unsigned i = 0; i < NumOps; ++i, ++I) {
     if (OpInfo[i].isPredicate() ) {
       I->setImm(CC);
       ++I;
@@ -434,8 +447,10 @@ DecodeStatus ThumbDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
   uint8_t bytes[4];
 
   // We want to read exactly 2 bytes of data.
-  if (Region.readBytes(Address, 2, (uint8_t*)bytes, NULL) == -1)
+  if (Region.readBytes(Address, 2, (uint8_t*)bytes, NULL) == -1) {
+    Size = 0;
     return Fail;
+  }
 
   uint16_t insn16 = (bytes[1] << 8) | bytes[0];
   DecodeStatus result = decodeThumbInstruction16(MI, insn16, Address, this);
@@ -484,8 +499,10 @@ DecodeStatus ThumbDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
   }
 
   // We want to read exactly 4 bytes of data.
-  if (Region.readBytes(Address, 4, (uint8_t*)bytes, NULL) == -1)
+  if (Region.readBytes(Address, 4, (uint8_t*)bytes, NULL) == -1) {
+    Size = 0;
     return Fail;
+  }
 
   uint32_t insn32 = (bytes[3] <<  8) |
                     (bytes[2] <<  0) |
@@ -560,6 +577,7 @@ DecodeStatus ThumbDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
     }
   }
 
+  Size = 0;
   return Fail;
 }
 
@@ -746,13 +764,6 @@ static DecodeStatus DecodeSOImmOperand(llvm::MCInst &Inst, unsigned Val,
   return Success;
 }
 
-static DecodeStatus DecodeBLTargetOperand(llvm::MCInst &Inst, unsigned Val,
-                               uint64_t Address, const void *Decoder) {
-  Val <<= 2;
-  Inst.addOperand(MCOperand::CreateImm(SignExtend32<26>(Val)));
-  return Success;
-}
-
 static DecodeStatus DecodeSORegImmOperand(llvm::MCInst &Inst, unsigned Val,
                                uint64_t Address, const void *Decoder) {
   DecodeStatus S = Success;
@@ -1039,8 +1050,6 @@ DecodeAddrMode2IdxInstruction(llvm::MCInst &Inst, unsigned Insn,
     case ARM::LDR_POST_REG:
     case ARM::LDRB_POST_IMM:
     case ARM::LDRB_POST_REG:
-    case ARM::LDR_PRE:
-    case ARM::LDRB_PRE:
     case ARM::LDRBT_POST_REG:
     case ARM::LDRBT_POST_IMM:
     case ARM::LDRT_POST_REG:
@@ -1392,6 +1401,47 @@ static DecodeStatus DecodeCPSInstruction(llvm::MCInst &Inst, unsigned Insn,
   return S;
 }
 
+static DecodeStatus DecodeT2CPSInstruction(llvm::MCInst &Inst, unsigned Insn,
+                                 uint64_t Address, const void *Decoder) {
+  unsigned imod = fieldFromInstruction32(Insn, 9, 2);
+  unsigned M = fieldFromInstruction32(Insn, 8, 1);
+  unsigned iflags = fieldFromInstruction32(Insn, 5, 3);
+  unsigned mode = fieldFromInstruction32(Insn, 0, 5);
+
+  DecodeStatus S = Success;
+
+  // imod == '01' --> UNPREDICTABLE
+  // NOTE: Even though this is technically UNPREDICTABLE, we choose to
+  // return failure here.  The '01' imod value is unprintable, so there's
+  // nothing useful we could do even if we returned UNPREDICTABLE.
+
+  if (imod == 1) CHECK(S, Fail);
+
+  if (imod && M) {
+    Inst.setOpcode(ARM::t2CPS3p);
+    Inst.addOperand(MCOperand::CreateImm(imod));
+    Inst.addOperand(MCOperand::CreateImm(iflags));
+    Inst.addOperand(MCOperand::CreateImm(mode));
+  } else if (imod && !M) {
+    Inst.setOpcode(ARM::t2CPS2p);
+    Inst.addOperand(MCOperand::CreateImm(imod));
+    Inst.addOperand(MCOperand::CreateImm(iflags));
+    if (mode) CHECK(S, Unpredictable);
+  } else if (!imod && M) {
+    Inst.setOpcode(ARM::t2CPS1p);
+    Inst.addOperand(MCOperand::CreateImm(mode));
+    if (iflags) CHECK(S, Unpredictable);
+  } else {
+    // imod == '00' && M == '0' --> UNPREDICTABLE
+    Inst.setOpcode(ARM::t2CPS1p);
+    Inst.addOperand(MCOperand::CreateImm(mode));
+    CHECK(S, Unpredictable);
+  }
+
+  return S;
+}
+
+
 static DecodeStatus DecodeSMLAInstruction(llvm::MCInst &Inst, unsigned Insn,
                                  uint64_t Address, const void *Decoder) {
   DecodeStatus S = Success;
@@ -2261,12 +2311,15 @@ static DecodeStatus DecodeThumbAddSpecialReg(llvm::MCInst &Inst, uint16_t Insn,
 
   CHECK(S, DecodetGPRRegisterClass(Inst, dst, Address, Decoder));
 
-  if (Inst.getOpcode() == ARM::tADR)
-    Inst.addOperand(MCOperand::CreateReg(ARM::PC));
-  else if (Inst.getOpcode() == ARM::tADDrSPi)
-    Inst.addOperand(MCOperand::CreateReg(ARM::SP));
-  else
-    return Fail;
+  switch(Inst.getOpcode()) {
+    default:
+      return Fail;
+    case ARM::tADR:
+      break; // tADR does not explicitly represent the PC as an operand.
+    case ARM::tADDrSPi:
+      Inst.addOperand(MCOperand::CreateReg(ARM::SP));
+      break;
+  }
 
   Inst.addOperand(MCOperand::CreateImm(imm));
   return S;
@@ -2350,9 +2403,15 @@ static DecodeStatus DecodeT2LoadShift(llvm::MCInst &Inst, unsigned Insn,
                               uint64_t Address, const void *Decoder) {
   DecodeStatus S = Success;
 
-  if (Inst.getOpcode() != ARM::t2PLDs) {
-    unsigned Rt = fieldFromInstruction32(Insn, 12, 4);
-    CHECK(S, DecodeGPRRegisterClass(Inst, Rt, Address, Decoder));
+  switch (Inst.getOpcode()) {
+    case ARM::t2PLDs:
+    case ARM::t2PLDWs:
+    case ARM::t2PLIs:
+      break;
+    default: {
+      unsigned Rt = fieldFromInstruction32(Insn, 12, 4);
+      CHECK(S, DecodeGPRRegisterClass(Inst, Rt, Address, Decoder));
+    }
   }
 
   unsigned Rn = fieldFromInstruction32(Insn, 16, 4);
@@ -2486,8 +2545,8 @@ static DecodeStatus DecodeThumbAddSPReg(llvm::MCInst &Inst, uint16_t Insn,
     Rdm |= fieldFromInstruction16(Insn, 7, 1) << 3;
 
     CHECK(S, DecodeGPRRegisterClass(Inst, Rdm, Address, Decoder));
-    Inst.addOperand(MCOperand::CreateReg(ARM::SP));
     CHECK(S, DecodeGPRRegisterClass(Inst, Rdm, Address, Decoder));
+    Inst.addOperand(MCOperand::CreateReg(ARM::SP));
   } else if (Inst.getOpcode() == ARM::tADDspr) {
     unsigned Rm = fieldFromInstruction16(Insn, 3, 4);
 
@@ -2690,6 +2749,51 @@ static DecodeStatus DecodeDoubleRegStore(llvm::MCInst &Inst, unsigned Insn,
   return S;
 }
 
+static DecodeStatus DecodeLDRPreImm(llvm::MCInst &Inst, unsigned Insn,
+                            uint64_t Address, const void *Decoder) {
+  DecodeStatus S = Success;
+
+  unsigned Rn = fieldFromInstruction32(Insn, 16, 4);
+  unsigned Rt = fieldFromInstruction32(Insn, 12, 4);
+  unsigned imm = fieldFromInstruction32(Insn, 0, 12);
+  imm |= fieldFromInstruction32(Insn, 16, 4) << 13;
+  imm |= fieldFromInstruction32(Insn, 23, 1) << 12;
+  unsigned pred = fieldFromInstruction32(Insn, 28, 4);
+
+  if (Rn == 0xF || Rn == Rt) CHECK(S, Unpredictable);
+
+  CHECK(S, DecodeGPRRegisterClass(Inst, Rt, Address, Decoder));
+  CHECK(S, DecodeGPRRegisterClass(Inst, Rn, Address, Decoder));
+  CHECK(S, DecodeAddrModeImm12Operand(Inst, imm, Address, Decoder));
+  CHECK(S, DecodePredicateOperand(Inst, pred, Address, Decoder));
+
+  return S;
+}
+
+static DecodeStatus DecodeLDRPreReg(llvm::MCInst &Inst, unsigned Insn,
+                            uint64_t Address, const void *Decoder) {
+  DecodeStatus S = Success;
+
+  unsigned Rn = fieldFromInstruction32(Insn, 16, 4);
+  unsigned Rt = fieldFromInstruction32(Insn, 12, 4);
+  unsigned imm = fieldFromInstruction32(Insn, 0, 12);
+  imm |= fieldFromInstruction32(Insn, 16, 4) << 13;
+  imm |= fieldFromInstruction32(Insn, 23, 1) << 12;
+  unsigned pred = fieldFromInstruction32(Insn, 28, 4);
+  unsigned Rm = fieldFromInstruction32(Insn, 0, 4);
+
+  if (Rn == 0xF || Rn == Rt) CHECK(S, Unpredictable);
+  if (Rm == 0xF) CHECK(S, Unpredictable);
+
+  CHECK(S, DecodeGPRRegisterClass(Inst, Rt, Address, Decoder));
+  CHECK(S, DecodeGPRRegisterClass(Inst, Rn, Address, Decoder));
+  CHECK(S, DecodeSORegMemOperand(Inst, imm, Address, Decoder));
+  CHECK(S, DecodePredicateOperand(Inst, pred, Address, Decoder));
+
+  return S;
+}
+
+
 static DecodeStatus DecodeSTRPreImm(llvm::MCInst &Inst, unsigned Insn,
                             uint64_t Address, const void *Decoder) {
   DecodeStatus S = Success;
@@ -3240,3 +3344,27 @@ static DecodeStatus DecodeVMOVRRS(llvm::MCInst &Inst, unsigned Insn,
 
   return S;
 }
+
+static DecodeStatus DecodeITCond(llvm::MCInst &Inst, unsigned Cond,
+                                 uint64_t Address, const void *Decoder) {
+  DecodeStatus S = Success;
+  if (Cond == 0xF) {
+    Cond = 0xE;
+    CHECK(S, Unpredictable);
+  }
+
+  Inst.addOperand(MCOperand::CreateImm(Cond));
+  return S;
+}
+
+static DecodeStatus DecodeITMask(llvm::MCInst &Inst, unsigned Mask,
+                                 uint64_t Address, const void *Decoder) {
+  DecodeStatus S = Success;
+  if (Mask == 0) {
+    Mask = 0x8;
+    CHECK(S, Unpredictable);
+  }
+  Inst.addOperand(MCOperand::CreateImm(Mask));
+  return S;
+}
+