diff --git a/llvm/lib/Target/ARM/ARMInstrInfo.td b/llvm/lib/Target/ARM/ARMInstrInfo.td index 2ea01f9378bb..310c3819d9cc 100644 --- a/llvm/lib/Target/ARM/ARMInstrInfo.td +++ b/llvm/lib/Target/ARM/ARMInstrInfo.td @@ -3279,9 +3279,11 @@ class AAI 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/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp index 0b93f9105476..bb0fc9b371e3 100644 --- a/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp +++ b/llvm/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 diff --git a/llvm/test/MC/Disassembler/ARM/basic-arm-instructions.txt b/llvm/test/MC/Disassembler/ARM/basic-arm-instructions.txt index 92cfe6862ed7..ae4172b07059 100644 --- a/llvm/test/MC/Disassembler/ARM/basic-arm-instructions.txt +++ b/llvm/test/MC/Disassembler/ARM/basic-arm-instructions.txt @@ -454,10 +454,14 @@ # 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/llvm/test/MC/Disassembler/ARM/invalid-CPS-arm.txt b/llvm/test/MC/Disassembler/ARM/invalid-CPS-arm.txt new file mode 100644 index 000000000000..e447eb68dd9c --- /dev/null +++ b/llvm/test/MC/Disassembler/ARM/invalid-CPS-arm.txt @@ -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