summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAmaury de la Vieuville <amaury.dlv@gmail.com>2013-06-08 13:38:52 +0000
committerAmaury de la Vieuville <amaury.dlv@gmail.com>2013-06-08 13:38:52 +0000
commit46e136c952e0242308db2682ba2ec4020cdcd006 (patch)
tree2b5ba5013c74cf75cd6e961468e27072e8e7f494 /lib
parentc64835b0c57913b11abd648b76913390e62af8d6 (diff)
downloadllvm-46e136c952e0242308db2682ba2ec4020cdcd006.tar.gz
llvm-46e136c952e0242308db2682ba2ec4020cdcd006.tar.bz2
llvm-46e136c952e0242308db2682ba2ec4020cdcd006.tar.xz
ARM: fix CPS decoding when ambiguous with QADD
Handle the case when the disassembler table can't tell the difference between some encodings of QADD and CPS. Add some necessary safe guards in CPS decoding as well. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@183610 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/Target/ARM/ARMInstrInfo.td2
-rw-r--r--lib/Target/ARM/Disassembler/ARMDisassembler.cpp32
2 files changed, 34 insertions, 0 deletions
diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td
index 2ea01f9378..310c3819d9 100644
--- a/lib/Target/ARM/ARMInstrInfo.td
+++ b/lib/Target/ARM/ARMInstrInfo.td
@@ -3279,9 +3279,11 @@ class AAI<bits<8> op27_20, bits<8> op11_4, string opc,
// Saturating add/subtract
+let DecoderMethod = "DecodeQADDInstruction" in
def QADD : AAI<0b00010000, 0b00000101, "qadd",
[(set GPRnopc:$Rd, (int_arm_qadd GPRnopc:$Rm, GPRnopc:$Rn))],
(ins GPRnopc:$Rm, GPRnopc:$Rn), "\t$Rd, $Rm, $Rn">;
+
def QSUB : AAI<0b00010010, 0b00000101, "qsub",
[(set GPRnopc:$Rd, (int_arm_qsub GPRnopc:$Rm, GPRnopc:$Rn))],
(ins GPRnopc:$Rm, GPRnopc:$Rn), "\t$Rd, $Rm, $Rn">;
diff --git a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
index 0b93f91054..bb0fc9b371 100644
--- a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
+++ b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
@@ -359,6 +359,8 @@ static DecodeStatus DecodeThumbAddSPReg(MCInst &Inst, uint16_t Insn,
uint64_t Address, const void *Decoder);
static DecodeStatus DecodeThumbCPS(MCInst &Inst, uint16_t Insn,
uint64_t Address, const void *Decoder);
+static DecodeStatus DecodeQADDInstruction(MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder);
static DecodeStatus DecodeThumbBLXOffset(MCInst &Inst, unsigned Insn,
uint64_t Address, const void *Decoder);
static DecodeStatus DecodeT2AddrModeImm12(MCInst &Inst, unsigned Val,
@@ -1733,6 +1735,29 @@ static DecodeStatus DecodeRFEInstruction(MCInst &Inst, unsigned Insn,
return S;
}
+static DecodeStatus DecodeQADDInstruction(MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ DecodeStatus S = MCDisassembler::Success;
+
+ unsigned Rd = fieldFromInstruction(Insn, 12, 4);
+ unsigned Rm = fieldFromInstruction(Insn, 0, 4);
+ unsigned Rn = fieldFromInstruction(Insn, 16, 4);
+ unsigned pred = fieldFromInstruction(Insn, 28, 4);
+
+ if (pred == 0xF)
+ return DecodeCPSInstruction(Inst, Insn, Address, Decoder);
+
+ if (!Check(S, DecodeGPRnopcRegisterClass(Inst, Rd, Address, Decoder)))
+ return MCDisassembler::Fail;
+ if (!Check(S, DecodeGPRnopcRegisterClass(Inst, Rm, Address, Decoder)))
+ return MCDisassembler::Fail;
+ if (!Check(S, DecodeGPRnopcRegisterClass(Inst, Rn, Address, Decoder)))
+ return MCDisassembler::Fail;
+ if (!Check(S, DecodePredicateOperand(Inst, pred, Address, Decoder)))
+ return MCDisassembler::Fail;
+ return S;
+}
+
static DecodeStatus DecodeMemMultipleWritebackInstruction(MCInst &Inst,
unsigned Insn,
uint64_t Address, const void *Decoder) {
@@ -1827,6 +1852,13 @@ static DecodeStatus DecodeCPSInstruction(MCInst &Inst, unsigned Insn,
DecodeStatus S = MCDisassembler::Success;
+ // This decoder is called from multiple location that do not check
+ // the full encoding is valid before they do.
+ if (fieldFromInstruction(Insn, 5, 1) != 0 ||
+ fieldFromInstruction(Insn, 16, 1) != 0 ||
+ fieldFromInstruction(Insn, 20, 8) != 0x10)
+ return MCDisassembler::Fail;
+
// 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