ARM: fix CPS decoding when ambiguous with QADD
authorAmaury de la Vieuville <amaury.dlv@gmail.com>
Sat, 8 Jun 2013 13:38:52 +0000 (13:38 +0000)
committerAmaury de la Vieuville <amaury.dlv@gmail.com>
Sat, 8 Jun 2013 13:38:52 +0000 (13:38 +0000)
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

lib/Target/ARM/ARMInstrInfo.td
lib/Target/ARM/Disassembler/ARMDisassembler.cpp
test/MC/Disassembler/ARM/basic-arm-instructions.txt
test/MC/Disassembler/ARM/invalid-CPS-arm.txt [new file with mode: 0644]

index 2ea01f9378bba2875446a8d11ceeeac7b3dc7712..310c3819d9cc9dad6f4d6b0dac3015abccce6e15 100644 (file)
@@ -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">;
index 0b93f9105476e74aa3a226096881bf42e8ccea9e..bb0fc9b371e343efa2d69d6f99e04a9b8d092e02 100644 (file)
@@ -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
index 92cfe6862ed7724a7bc2c081e9852df3357c4412..ae4172b07059a749be1388cc377d7cf785f9f8e8 100644 (file)
 # CHECK: cpsie  aif
 # CHECK: cps  #15
 # CHECK: cpsid  if, #10
+# CHECK: cpsid  af, #17
+# CHECK: cpsie  f, #26
 
 0xc0 0x01 0x08 0xf1
 0x0f 0x00 0x02 0xf1
 0xca 0x00 0x0e 0xf1
+0x51 0x01 0x0e 0xf1
+0x5a 0x00 0x0a 0xf1
 
 
 #------------------------------------------------------------------------------
diff --git a/test/MC/Disassembler/ARM/invalid-CPS-arm.txt b/test/MC/Disassembler/ARM/invalid-CPS-arm.txt
new file mode 100644 (file)
index 0000000..e447eb6
--- /dev/null
@@ -0,0 +1,9 @@
+# CPS: various encodings that are ambiguous with other instructions
+
+# RUN: echo "0x9f 0xff 0x4e 0xf1" | llvm-mc -triple=armv7 -disassemble 2>&1 | FileCheck %s
+# RUN: echo "0x80 0x80 0x2c 0xf1" | llvm-mc -triple=armv7 -disassemble 2>&1 | FileCheck %s
+# RUN: echo "0xce 0x3f 0x28 0xf1" | llvm-mc -triple=armv7 -disassemble 2>&1 | FileCheck %s
+# RUN: echo "0x80 0x00 0x20 0xf1" | llvm-mc -triple=armv7 -disassemble 2>&1 | FileCheck %s
+# RUN: echo "0xa0 0x00 0x00 0xf1" | llvm-mc -triple=armv7 -disassemble 2>&1 | FileCheck %s
+
+# CHECK: invalid instruction encoding