diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td index 2693f329045..5448ee3457d 100644 --- a/lib/Target/ARM/ARMInstrThumb2.td +++ b/lib/Target/ARM/ARMInstrThumb2.td @@ -1024,17 +1024,19 @@ multiclass T2I_ld opcod, string opc, def pci : T2Ipc <(outs target:$Rt), (ins t2ldrlabel:$addr), iii, opc, ".w\t$Rt, $addr", [(set target:$Rt, (opnode (ARMWrapper tconstpool:$addr)))]> { - bits<4> Rt; - bits<13> addr; let isReMaterializable = 1; let Inst{31-27} = 0b11111; let Inst{26-25} = 0b00; let Inst{24} = signed; - let Inst{23} = addr{12}; // add = (U == '1') let Inst{22-21} = opcod; let Inst{20} = 1; // load let Inst{19-16} = 0b1111; // Rn + + bits<4> Rt; let Inst{15-12} = Rt{3-0}; + + bits<13> addr; + let Inst{23} = addr{12}; // add = (U == '1') let Inst{11-0} = addr{11-0}; let DecoderMethod = "DecodeT2LoadLabel"; @@ -1564,16 +1566,17 @@ multiclass T2Ipl write, bits<1> instr, string opc> { Sched<[WritePreLd]> { let Inst{31-25} = 0b1111100; let Inst{24} = instr; + let Inst{23} = 1; let Inst{22} = 0; let Inst{21} = write; let Inst{20} = 1; let Inst{15-12} = 0b1111; bits<17> addr; - let addr{12} = 1; // add = TRUE let Inst{19-16} = addr{16-13}; // Rn - let Inst{23} = addr{12}; // U let Inst{11-0} = addr{11-0}; // imm12 + + let DecoderMethod = "DecodeT2LoadImm12"; } def i8 : T2Ii8<(outs), (ins t2addrmode_negimm8:$addr), IIC_Preload, opc, @@ -1592,6 +1595,8 @@ multiclass T2Ipl write, bits<1> instr, string opc> { bits<13> addr; let Inst{19-16} = addr{12-9}; // Rn let Inst{7-0} = addr{7-0}; // imm8 + + let DecoderMethod = "DecodeT2LoadImm8"; } def s : T2Iso<(outs), (ins t2addrmode_so_reg:$addr), IIC_Preload, opc, @@ -1605,7 +1610,7 @@ multiclass T2Ipl write, bits<1> instr, string opc> { let Inst{21} = write; let Inst{20} = 1; let Inst{15-12} = 0b1111; - let Inst{11-6} = 0000000; + let Inst{11-6} = 0b000000; bits<10> addr; let Inst{19-16} = addr{9-6}; // Rn @@ -1614,10 +1619,28 @@ multiclass T2Ipl write, bits<1> instr, string opc> { let DecoderMethod = "DecodeT2LoadShift"; } - // FIXME: We should have a separate 'pci' variant here. As-is we represent - // it via the i12 variant, which it's related to, but that means we can - // represent negative immediates, which aren't legal for anything except - // the 'pci' case (Rn == 15). + + // pci variant is very similar to i12, but supports negative offsets + // from the PC. + def pci : T2Iso<(outs), (ins t2ldrlabel:$addr), IIC_Preload, opc, + "\t$addr", + [(ARMPreload (ARMWrapper tconstpool:$addr), + (i32 write), (i32 instr))]>, + Sched<[WritePreLd]> { + let Inst{31-25} = 0b1111100; + let Inst{24} = instr; + let Inst{22} = 0; + let Inst{21} = write; + let Inst{20} = 1; + let Inst{19-16} = 0b1111; + let Inst{15-12} = 0b1111; + + bits<13> addr; + let Inst{23} = addr{12}; // add = (U == '1') + let Inst{11-0} = addr{11-0}; // imm12 + + let DecoderMethod = "DecodeT2LoadLabel"; + } } defm t2PLD : T2Ipl<0, 0, "pld">, Requires<[IsThumb2]>; diff --git a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp index 39a5af9e605..186bc9c0ea4 100644 --- a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp +++ b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp @@ -3199,38 +3199,51 @@ static DecodeStatus DecodeT2LoadShift(MCInst &Inst, unsigned Insn, unsigned Rt = fieldFromInstruction(Insn, 12, 4); unsigned Rn = fieldFromInstruction(Insn, 16, 4); - if (Rn == 0xF) { + if (Rn == 15) { switch (Inst.getOpcode()) { - case ARM::t2LDRBs: - Inst.setOpcode(ARM::t2LDRBpci); - break; - case ARM::t2LDRHs: - Inst.setOpcode(ARM::t2LDRHpci); - break; - case ARM::t2LDRSHs: - Inst.setOpcode(ARM::t2LDRSHpci); - break; - case ARM::t2LDRSBs: - Inst.setOpcode(ARM::t2LDRSBpci); - break; - case ARM::t2LDRs: - Inst.setOpcode(ARM::t2LDRpci); - break; - case ARM::t2PLDs: { - Inst.setOpcode(ARM::t2PLDi12); - Inst.addOperand(MCOperand::CreateReg(ARM::PC)); - int imm = fieldFromInstruction(Insn, 0, 12); - if (!fieldFromInstruction(Insn, 23, 1)) imm *= -1; - Inst.addOperand(MCOperand::CreateImm(imm)); - return S; - } - default: - return MCDisassembler::Fail; + case ARM::t2LDRBs: + Inst.setOpcode(ARM::t2LDRBpci); + break; + case ARM::t2LDRHs: + Inst.setOpcode(ARM::t2LDRHpci); + break; + case ARM::t2LDRSHs: + Inst.setOpcode(ARM::t2LDRSHpci); + break; + case ARM::t2LDRSBs: + Inst.setOpcode(ARM::t2LDRSBpci); + break; + case ARM::t2LDRs: + Inst.setOpcode(ARM::t2LDRpci); + break; + case ARM::t2PLDs: + Inst.setOpcode(ARM::t2PLDpci); + break; + case ARM::t2PLIs: + Inst.setOpcode(ARM::t2PLIpci); + break; + default: + return MCDisassembler::Fail; } return DecodeT2LoadLabel(Inst, Insn, Address, Decoder); } + if (Rt == 15) { + switch (Inst.getOpcode()) { + case ARM::t2LDRSHs: + return MCDisassembler::Fail; + case ARM::t2LDRHs: + // FIXME: this instruction is only available with MP extensions, + // this should be checked first but we don't have access to the + // feature bits here. + Inst.setOpcode(ARM::t2PLDWs); + break; + default: + break; + } + } + switch (Inst.getOpcode()) { case ARM::t2PLDs: case ARM::t2PLDWs: @@ -3278,14 +3291,36 @@ static DecodeStatus DecodeT2LoadImm8(MCInst &Inst, unsigned Insn, case ARM::t2LDRSHi8: Inst.setOpcode(ARM::t2LDRSHpci); break; + case ARM::t2PLDi8: + Inst.setOpcode(ARM::t2PLDpci); + break; + case ARM::t2PLIi8: + Inst.setOpcode(ARM::t2PLIpci); + break; default: return MCDisassembler::Fail; } return DecodeT2LoadLabel(Inst, Insn, Address, Decoder); } - if (!Check(S, DecodeGPRRegisterClass(Inst, Rt, Address, Decoder))) - return MCDisassembler::Fail; + if (Rt == 15) { + switch (Inst.getOpcode()) { + case ARM::t2LDRSHi8: + return MCDisassembler::Fail; + default: + break; + } + } + + switch (Inst.getOpcode()) { + case ARM::t2PLDi8: + case ARM::t2PLIi8: + break; + default: + if (!Check(S, DecodeGPRRegisterClass(Inst, Rt, Address, Decoder))) + return MCDisassembler::Fail; + } + if (!Check(S, DecodeT2AddrModeImm8(Inst, imm, Address, Decoder))) return MCDisassembler::Fail; return S; @@ -3317,14 +3352,39 @@ static DecodeStatus DecodeT2LoadImm12(MCInst &Inst, unsigned Insn, case ARM::t2LDRSBi12: Inst.setOpcode(ARM::t2LDRSBpci); break; + case ARM::t2PLDi12: + Inst.setOpcode(ARM::t2PLDpci); + break; + case ARM::t2PLIi12: + Inst.setOpcode(ARM::t2PLIpci); + break; default: return MCDisassembler::Fail; } return DecodeT2LoadLabel(Inst, Insn, Address, Decoder); } - if (!Check(S, DecodeGPRRegisterClass(Inst, Rt, Address, Decoder))) - return MCDisassembler::Fail; + if (Rt == 15) { + switch (Inst.getOpcode()) { + case ARM::t2LDRSHi12: + return MCDisassembler::Fail; + case ARM::t2LDRHi12: + Inst.setOpcode(ARM::t2PLDi12); + break; + default: + break; + } + } + + switch (Inst.getOpcode()) { + case ARM::t2PLDi12: + case ARM::t2PLIi12: + break; + default: + if (!Check(S, DecodeGPRRegisterClass(Inst, Rt, Address, Decoder))) + return MCDisassembler::Fail; + } + if (!Check(S, DecodeT2AddrModeImm12(Inst, imm, Address, Decoder))) return MCDisassembler::Fail; return S; @@ -3377,11 +3437,27 @@ static DecodeStatus DecodeT2LoadLabel(MCInst &Inst, unsigned Insn, 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 (Rt == 15) { + switch (Inst.getOpcode()) { + case ARM::t2LDRBpci: + case ARM::t2LDRHpci: + Inst.setOpcode(ARM::t2PLDpci); + break; + case ARM::t2LDRSBpci: + Inst.setOpcode(ARM::t2PLIpci); + break; + case ARM::t2LDRSHpci: + return MCDisassembler::Fail; + default: + break; + } + } + + switch(Inst.getOpcode()) { + case ARM::t2PLDpci: + case ARM::t2PLIpci: + break; + default: if (!Check(S, DecodeGPRRegisterClass(Inst, Rt, Address, Decoder))) return MCDisassembler::Fail; } @@ -3528,7 +3604,10 @@ static DecodeStatus DecodeT2LdStPre(MCInst &Inst, unsigned Insn, break; case ARM::t2LDRSB_PRE: case ARM::t2LDRSB_POST: - Inst.setOpcode(ARM::t2LDRSBpci); + if (Rt == 15) + Inst.setOpcode(ARM::t2PLIpci); + else + Inst.setOpcode(ARM::t2LDRSBpci); break; case ARM::t2LDRSH_PRE: case ARM::t2LDRSH_POST: diff --git a/test/MC/Disassembler/ARM/invalid-LDR-thumb.txt b/test/MC/Disassembler/ARM/invalid-LDR-thumb.txt new file mode 100644 index 00000000000..5786a34c11a --- /dev/null +++ b/test/MC/Disassembler/ARM/invalid-LDR-thumb.txt @@ -0,0 +1,10 @@ +# invalid LDRSHs Rt=PC +# RUN: echo "0x30 0xf9 0x00 0xf0" | llvm-mc -triple=thumbv7 -disassemble 2>&1 | FileCheck %s + +# invalid LDRSHi8 Rt=PC +# RUN: echo "0x30 0xf9 0x00 0xfc" | llvm-mc -triple=thumbv7 -disassemble 2>&1 | FileCheck %s + +# invalid LDRSHi12 Rt=PC +# RUN: echo "0xb0 0xf9 0x00 0xf0" | llvm-mc -triple=thumbv7 -disassemble 2>&1 | FileCheck %s + +# CHECK: invalid instruction encoding diff --git a/test/MC/Disassembler/ARM/thumb2.txt b/test/MC/Disassembler/ARM/thumb2.txt index 482cca8bbc2..b2c6fb88fcf 100644 --- a/test/MC/Disassembler/ARM/thumb2.txt +++ b/test/MC/Disassembler/ARM/thumb2.txt @@ -1303,6 +1303,17 @@ 0x1d 0xf8 0x12 0xf0 0x1d 0xf8 0x02 0xf0 +#------------------------------------------------------------------------------ +# PLD(literal) +#------------------------------------------------------------------------------ +# CHECK: pld [pc, #-0] +# CHECK: pld [pc, #455] +# CHECK: pld [pc, #0] + +0x1f 0xf8 0x00 0xf0 +0x9f 0xf8 0xc7 0xf1 +0x9f 0xf8 0x00 0xf0 + #------------------------------------------------------------------------------ # PLI(immediate) #------------------------------------------------------------------------------ @@ -1335,6 +1346,17 @@ 0x1d 0xf9 0x12 0xf0 0x1d 0xf9 0x02 0xf0 +#------------------------------------------------------------------------------ +# PLI(literal) +#------------------------------------------------------------------------------ +# CHECK: pli [pc, #-0] +# CHECK: pli [pc, #-328] +# CHECK: pli [pc, #0] + +0x1f 0xf9 0x00 0xf0 +0x1f 0xf9 0x48 0xf1 +0x9f 0xf9 0x00 0xf0 + #------------------------------------------------------------------------------ # QADD/QADD16/QADD8