summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Target/ARM/ARMInstrThumb2.td16
-rw-r--r--lib/Target/ARM/Disassembler/ARMDisassembler.cpp223
-rw-r--r--lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp28
-rw-r--r--test/MC/Disassembler/ARM/thumb2.txt57
4 files changed, 293 insertions, 31 deletions
diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td
index 8b114a8326..da296dcd8a 100644
--- a/lib/Target/ARM/ARMInstrThumb2.td
+++ b/lib/Target/ARM/ARMInstrThumb2.td
@@ -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>;
diff --git a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
index 196fc32f48..39a5af9e60 100644
--- a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
+++ b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
@@ -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;
diff --git a/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp b/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp
index 0b3d266db7..0931e597d3 100644
--- a/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp
+++ b/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp
@@ -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
diff --git a/test/MC/Disassembler/ARM/thumb2.txt b/test/MC/Disassembler/ARM/thumb2.txt
index a681e2a6f9..eb1e112d4f 100644
--- a/test/MC/Disassembler/ARM/thumb2.txt
+++ b/test/MC/Disassembler/ARM/thumb2.txt
@@ -553,6 +553,17 @@
#------------------------------------------------------------------------------
+# 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)
#------------------------------------------------------------------------------
# CHECK: ldr.w r1, [r8, r1]
@@ -631,6 +642,17 @@
#------------------------------------------------------------------------------
+# 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: ldrbt r1, [r2]
@@ -699,14 +721,12 @@
# 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
#------------------------------------------------------------------------------
@@ -740,6 +760,17 @@
#------------------------------------------------------------------------------
+# 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)
#------------------------------------------------------------------------------
# CHECK: ldrsb r5, [r5, #-4]
@@ -786,6 +817,17 @@
#------------------------------------------------------------------------------
+# 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
#------------------------------------------------------------------------------
# CHECK: ldrsbt r1, [r2]
@@ -847,6 +889,17 @@
#------------------------------------------------------------------------------
+# 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
#------------------------------------------------------------------------------
# CHECK: ldrsht r1, [r2]