ARM: fix thumb literal loads decoding

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
This commit is contained in:
Amaury de la Vieuville 2013-06-18 08:03:06 +00:00
parent cea0032f73
commit ce046b98ed
4 changed files with 293 additions and 31 deletions

View 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{19-16} = addr{16-13}; // Rn
let Inst{15-12} = Rt; let Inst{15-12} = Rt;
let Inst{11-0} = addr{11-0}; // imm let Inst{11-0} = addr{11-0}; // imm
let DecoderMethod = "DecodeT2LoadImm12";
} }
def i8 : T2Ii8 <(outs target:$Rt), (ins t2addrmode_negimm8:$addr), iii, def i8 : T2Ii8 <(outs target:$Rt), (ins t2addrmode_negimm8:$addr), iii,
opc, "\t$Rt, $addr", 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{9} = addr{8}; // U
let Inst{8} = 0; // The W bit. let Inst{8} = 0; // The W bit.
let Inst{7-0} = addr{7-0}; // imm let Inst{7-0} = addr{7-0}; // imm
let DecoderMethod = "DecodeT2LoadImm8";
} }
def s : T2Iso <(outs target:$Rt), (ins t2addrmode_so_reg:$addr), iis, def s : T2Iso <(outs target:$Rt), (ins t2addrmode_so_reg:$addr), iis,
opc, ".w\t$Rt, $addr", opc, ".w\t$Rt, $addr",
@ -1019,6 +1023,8 @@ multiclass T2I_ld<bit signed, bits<2> opcod, string opc,
bits<12> addr; bits<12> addr;
let Inst{15-12} = Rt{3-0}; let Inst{15-12} = Rt{3-0};
let Inst{11-0} = addr{11-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 // Loads with zero extension
defm t2LDRH : T2I_ld<0, 0b01, "ldrh", IIC_iLoad_bh_i, IIC_iLoad_bh_si, 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 // Loads with sign extension
defm t2LDRSH : T2I_ld<1, 0b01, "ldrsh", IIC_iLoad_bh_i, IIC_iLoad_bh_si, 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 { let mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1 in {
// Load doubleword // Load doubleword
@ -1373,6 +1379,8 @@ class T2IldT<bit signed, bits<2> type, string opc, InstrItinClass ii>
let Inst{11} = 1; let Inst{11} = 1;
let Inst{10-8} = 0b110; // PUW. let Inst{10-8} = 0b110; // PUW.
let Inst{7-0} = addr{7-0}; 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>;

View File

@ -347,6 +347,14 @@ static DecodeStatus DecodeT2AddrModeSOReg(MCInst &Inst, unsigned Val,
uint64_t Address, const void *Decoder); uint64_t Address, const void *Decoder);
static DecodeStatus DecodeT2LoadShift(MCInst &Inst, unsigned Val, static DecodeStatus DecodeT2LoadShift(MCInst &Inst, unsigned Val,
uint64_t Address, const void *Decoder); 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, static DecodeStatus DecodeT2Imm8S4(MCInst &Inst, unsigned Val,
uint64_t Address, const void *Decoder); uint64_t Address, const void *Decoder);
static DecodeStatus DecodeT2AddrModeImm8s4(MCInst &Inst, unsigned Val, static DecodeStatus DecodeT2AddrModeImm8s4(MCInst &Inst, unsigned Val,
@ -3188,19 +3196,9 @@ static DecodeStatus DecodeT2LoadShift(MCInst &Inst, unsigned Insn,
uint64_t Address, const void *Decoder) { uint64_t Address, const void *Decoder) {
DecodeStatus S = MCDisassembler::Success; DecodeStatus S = MCDisassembler::Success;
switch (Inst.getOpcode()) { unsigned Rt = fieldFromInstruction(Insn, 12, 4);
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 Rn = fieldFromInstruction(Insn, 16, 4); unsigned Rn = fieldFromInstruction(Insn, 16, 4);
if (Rn == 0xF) { if (Rn == 0xF) {
switch (Inst.getOpcode()) { switch (Inst.getOpcode()) {
case ARM::t2LDRBs: case ARM::t2LDRBs:
@ -3215,19 +3213,32 @@ static DecodeStatus DecodeT2LoadShift(MCInst &Inst, unsigned Insn,
case ARM::t2LDRSBs: case ARM::t2LDRSBs:
Inst.setOpcode(ARM::t2LDRSBpci); Inst.setOpcode(ARM::t2LDRSBpci);
break; break;
case ARM::t2PLDs: case ARM::t2LDRs:
Inst.setOpcode(ARM::t2LDRpci);
break;
case ARM::t2PLDs: {
Inst.setOpcode(ARM::t2PLDi12); Inst.setOpcode(ARM::t2PLDi12);
Inst.addOperand(MCOperand::CreateReg(ARM::PC)); 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: default:
return MCDisassembler::Fail; return MCDisassembler::Fail;
} }
int imm = fieldFromInstruction(Insn, 0, 12); return DecodeT2LoadLabel(Inst, Insn, Address, Decoder);
if (!fieldFromInstruction(Insn, 23, 1)) imm *= -1; }
Inst.addOperand(MCOperand::CreateImm(imm));
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, static DecodeStatus DecodeT2Imm8S4(MCInst &Inst, unsigned Val,
uint64_t Address, const void *Decoder) { uint64_t Address, const void *Decoder) {
if (Val == 0) if (Val == 0)
@ -3353,6 +3512,34 @@ static DecodeStatus DecodeT2LdStPre(MCInst &Inst, unsigned Insn,
addr |= Rn << 9; addr |= Rn << 9;
unsigned load = fieldFromInstruction(Insn, 20, 1); 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 (!load) {
if (!Check(S, DecodeGPRRegisterClass(Inst, Rn, Address, Decoder))) if (!Check(S, DecodeGPRRegisterClass(Inst, Rn, Address, Decoder)))
return MCDisassembler::Fail; return MCDisassembler::Fail;

View File

@ -315,15 +315,29 @@ void ARMInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
void ARMInstPrinter::printThumbLdrLabelOperand(const MCInst *MI, unsigned OpNum, void ARMInstPrinter::printThumbLdrLabelOperand(const MCInst *MI, unsigned OpNum,
raw_ostream &O) { raw_ostream &O) {
const MCOperand &MO1 = MI->getOperand(OpNum); const MCOperand &MO1 = MI->getOperand(OpNum);
if (MO1.isExpr()) if (MO1.isExpr()) {
O << *MO1.getExpr(); O << *MO1.getExpr();
else if (MO1.isImm()) { return;
O << markup("<mem:") << "[pc, "
<< markup("<imm:") << "#" << formatImm(MO1.getImm())
<< markup(">]>", "]");
} }
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

View File

@ -552,6 +552,17 @@
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)
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
@ -630,6 +641,17 @@
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
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
@ -699,14 +721,12 @@
# CHECK: ldrh.w r5, [r6, #33] # CHECK: ldrh.w r5, [r6, #33]
# CHECK: ldrh.w r5, [r6, #257] # CHECK: ldrh.w r5, [r6, #257]
# CHECK: ldrh.w lr, [r7, #257] # CHECK: ldrh.w lr, [r7, #257]
# CHECK: ldrh.w r0, [pc, #-21]
0x35 0xf8 0x04 0x5c 0x35 0xf8 0x04 0x5c
0x35 0x8c 0x35 0x8c
0xb6 0xf8 0x21 0x50 0xb6 0xf8 0x21 0x50
0xb6 0xf8 0x01 0x51 0xb6 0xf8 0x01 0x51
0xb7 0xf8 0x01 0xe1 0xb7 0xf8 0x01 0xe1
0x3f 0xf8 0x15 0x00
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
@ -739,6 +759,17 @@
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)
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
@ -785,6 +816,17 @@
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
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
@ -846,6 +888,17 @@
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
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------