[clang] dd4d093 - [ARM] Add initial support for Custom Datapath Extension (CDE)
Mikhail Maltsev via cfe-commits
cfe-commits at lists.llvm.org
Mon Feb 17 07:39:28 PST 2020
Author: Mikhail Maltsev
Date: 2020-02-17T15:39:16Z
New Revision: dd4d09376209cdc5615097a5be92105f55d06f5d
URL: https://github.com/llvm/llvm-project/commit/dd4d09376209cdc5615097a5be92105f55d06f5d
DIFF: https://github.com/llvm/llvm-project/commit/dd4d09376209cdc5615097a5be92105f55d06f5d.diff
LOG: [ARM] Add initial support for Custom Datapath Extension (CDE)
Summary:
This patch adds assembly-level support for a new Arm M-profile
architecture extension, Custom Datapath Extension (CDE).
A brief description of the extension is available at
https://developer.arm.com/architectures/instruction-sets/custom-instructions
The latest specification for CDE is currently a beta release and is
available at
https://static.docs.arm.com/ddi0607/aa/DDI0607A_a_armv8m_arm_supplement_cde.pdf
CDE allows chip vendors to add custom CPU instructions. The CDE
instructions re-use the same encoding space as existing coprocessor
instructions (such as MRC, MCR, CDP etc.). Each coprocessor in range
cp0-cp7 can be configured as either general purpose (GCP) or custom
datapath (CDEv1). This configuration is defined by the CPU vendor and
is provided to LLVM using 8 subtarget features: cdecp0 ... cdecp7.
The semantics of CDE instructions are implementation-defined, but the
instructions are guaranteed to be pure (that is, they are stateless,
they do not access memory or any registers except their explicit
inputs/outputs).
CDE requires the CPU to support at least Armv8.0-M mainline
architecture. CDE includes 3 sets of instructions:
* Instructions that operate on general purpose registers and NZCV
flags
* Instructions that operate on the S or D register file (require
either FP or MVE extension)
* Instructions that operate on the Q register file, require MVE
The user-facing names that can be specified on the command line are
the same as the 8 subtarget feature names. For example:
$ clang -target arm-none-none-eabi -march=armv8m.main+cdecp0+cdecp3
tells the compiler that the coprocessors 0 and 3 are configured as
CDEv1 and the remaining coprocessors are configured as GCP (which is
the default).
Reviewers: simon_tatham, ostannard, dmgreen, eli.friedman
Reviewed By: simon_tatham
Subscribers: kristof.beyls, hiraditya, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D74044
Added:
clang/test/Driver/arm-cde.c
llvm/lib/Target/ARM/ARMInstrCDE.td
llvm/test/MC/ARM/cde-fp-vec.s
llvm/test/MC/ARM/cde-integer.s
llvm/test/MC/ARM/cde-vec-pred.s
llvm/test/MC/Disassembler/ARM/cde-fp-vec.txt
llvm/test/MC/Disassembler/ARM/cde-integer.txt
llvm/test/MC/Disassembler/ARM/cde-vec-pred.txt
Modified:
llvm/include/llvm/Support/ARMTargetParser.def
llvm/include/llvm/Support/ARMTargetParser.h
llvm/lib/Target/ARM/ARM.td
llvm/lib/Target/ARM/ARMInstrInfo.td
llvm/lib/Target/ARM/ARMPredicates.td
llvm/lib/Target/ARM/ARMRegisterInfo.td
llvm/lib/Target/ARM/ARMSubtarget.h
llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp
llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.h
Removed:
################################################################################
diff --git a/clang/test/Driver/arm-cde.c b/clang/test/Driver/arm-cde.c
new file mode 100644
index 000000000000..696bee46cc34
--- /dev/null
+++ b/clang/test/Driver/arm-cde.c
@@ -0,0 +1,24 @@
+// RUN: %clang -target arm-none-none-eabi -march=armv8m.main %s -### -c 2>&1 | FileCheck %s --check-prefix=CHECK-NOCDE
+// CHECK-NOCDE: "-triple" "thumbv8m.main-none-none-eabi"
+// CHECK-NOCDE-NOT: "-target-feature" "+cdecp0"
+// CHECK-NOCDE-NOT: "-target-feature" "+cdecp1"
+// CHECK-NOCDE-NOT: "-target-feature" "+cdecp2"
+// CHECK-NOCDE-NOT: "-target-feature" "+cdecp3"
+// CHECK-NOCDE-NOT: "-target-feature" "+cdecp4"
+// CHECK-NOCDE-NOT: "-target-feature" "+cdecp5"
+// CHECK-NOCDE-NOT: "-target-feature" "+cdecp6"
+// CHECK-NOCDE-NOT: "-target-feature" "+cdecp7"
+
+// RUN: %clang -target arm-none-none-eabi -march=armv8m.main+cdecp0+cdecp3 %s -### -c 2>&1 | FileCheck %s --check-prefix=CHECK-CDE1
+// CHECK-CDE1: "-triple" "thumbv8m.main-none-none-eabi"
+// CHECK-CDE1-DAG: "-target-feature" "+cdecp0"
+// CHECK-CDE1-DAG: "-target-feature" "+cdecp3"
+
+// RUN: %clang -target arm-none-none-eabi -march=armv8m.main+cdecp0+cdecp3 %s -### -c 2>&1 | FileCheck %s --check-prefix=CHECK-CDE2
+// CHECK-CDE2: "-triple" "thumbv8m.main-none-none-eabi"
+// CHECK-CDE2-NOT: "-target-feature" "+cdecp1"
+// CHECK-CDE2-NOT: "-target-feature" "+cdecp2"
+// CHECK-CDE2-NOT: "-target-feature" "+cdecp4"
+// CHECK-CDE2-NOT: "-target-feature" "+cdecp5"
+// CHECK-CDE2-NOT: "-target-feature" "+cdecp6"
+// CHECK-CDE2-NOT: "-target-feature" "+cdecp7"
diff --git a/llvm/include/llvm/Support/ARMTargetParser.def b/llvm/include/llvm/Support/ARMTargetParser.def
index 7f03d9a1320a..c3d8c894db85 100644
--- a/llvm/include/llvm/Support/ARMTargetParser.def
+++ b/llvm/include/llvm/Support/ARMTargetParser.def
@@ -166,6 +166,14 @@ ARM_ARCH_EXT_NAME("xscale", ARM::AEK_XSCALE, nullptr, nullptr)
ARM_ARCH_EXT_NAME("fp16fml", ARM::AEK_FP16FML, "+fp16fml", "-fp16fml")
ARM_ARCH_EXT_NAME("sb", ARM::AEK_SB, "+sb", "-sb")
ARM_ARCH_EXT_NAME("lob", ARM::AEK_LOB, "+lob", "-lob")
+ARM_ARCH_EXT_NAME("cdecp0", ARM::AEK_CDECP0, "+cdecp0", "-cdecp0")
+ARM_ARCH_EXT_NAME("cdecp1", ARM::AEK_CDECP1, "+cdecp1", "-cdecp1")
+ARM_ARCH_EXT_NAME("cdecp2", ARM::AEK_CDECP2, "+cdecp2", "-cdecp2")
+ARM_ARCH_EXT_NAME("cdecp3", ARM::AEK_CDECP3, "+cdecp3", "-cdecp3")
+ARM_ARCH_EXT_NAME("cdecp4", ARM::AEK_CDECP4, "+cdecp4", "-cdecp4")
+ARM_ARCH_EXT_NAME("cdecp5", ARM::AEK_CDECP5, "+cdecp5", "-cdecp5")
+ARM_ARCH_EXT_NAME("cdecp6", ARM::AEK_CDECP6, "+cdecp6", "-cdecp6")
+ARM_ARCH_EXT_NAME("cdecp7", ARM::AEK_CDECP7, "+cdecp7", "-cdecp7")
#undef ARM_ARCH_EXT_NAME
#ifndef ARM_HW_DIV_NAME
diff --git a/llvm/include/llvm/Support/ARMTargetParser.h b/llvm/include/llvm/Support/ARMTargetParser.h
index 25f3409bc2d6..6f7a11f2eaba 100644
--- a/llvm/include/llvm/Support/ARMTargetParser.h
+++ b/llvm/include/llvm/Support/ARMTargetParser.h
@@ -46,6 +46,15 @@ enum ArchExtKind : uint64_t {
AEK_SB = 1 << 17,
AEK_FP_DP = 1 << 18,
AEK_LOB = 1 << 19,
+ AEK_CDECP0 = 1 << 20,
+ AEK_CDECP1 = 1 << 21,
+ AEK_CDECP2 = 1 << 22,
+ AEK_CDECP3 = 1 << 23,
+ AEK_CDECP4 = 1 << 24,
+ AEK_CDECP5 = 1 << 25,
+ AEK_CDECP6 = 1 << 26,
+ AEK_CDECP7 = 1 << 27,
+
// Unsupported extensions.
AEK_OS = 1ULL << 59,
AEK_IWMMXT = 1ULL << 60,
diff --git a/llvm/lib/Target/ARM/ARM.td b/llvm/lib/Target/ARM/ARM.td
index 380eaa863689..6427ebf22efe 100644
--- a/llvm/lib/Target/ARM/ARM.td
+++ b/llvm/lib/Target/ARM/ARM.td
@@ -536,6 +536,16 @@ def HasMVEFloatOps : SubtargetFeature<
"Support M-Class Vector Extension with integer and floating ops",
[HasMVEIntegerOps, FeatureFPARMv8_D16_SP, FeatureFullFP16]>;
+def HasCDEOps : SubtargetFeature<"cde", "HasCDEOps", "true",
+ "Support CDE instructions",
+ [HasV8MMainlineOps]>;
+
+foreach i = {0-7} in
+ def FeatureCoprocCDE#i : SubtargetFeature<"cdecp"#i,
+ "CoprocCDE["#i#"]", "true",
+ "Coprocessor "#i#" ISA is CDEv1",
+ [HasCDEOps]>;
+
//===----------------------------------------------------------------------===//
// ARM Processor subtarget features.
//
diff --git a/llvm/lib/Target/ARM/ARMInstrCDE.td b/llvm/lib/Target/ARM/ARMInstrCDE.td
new file mode 100644
index 000000000000..4e73ea819473
--- /dev/null
+++ b/llvm/lib/Target/ARM/ARMInstrCDE.td
@@ -0,0 +1,503 @@
+// Immediate operand of arbitrary bit width
+class BitWidthImmOperand<int width>
+ : ImmAsmOperand<0, !add(!shl(1, width), -1)> {
+ let Name = "Imm"#width#"b";
+}
+
+class BitWidthImm<int width>
+ : Operand<i32>,
+ ImmLeaf<i32, "{ return Imm >= 0 && Imm < (1 << "#width#"); }"> {
+ let ParserMatchClass = BitWidthImmOperand<width>;
+}
+
+def CDEDualRegOp : RegisterOperand<GPRPairnosp, "printGPRPairOperand">;
+
+// Used by VCX3 FP
+def imm_3b : BitWidthImm<3>;
+
+// Used by VCX3 vector
+def imm_4b : BitWidthImm<4>;
+
+// Used by VCX2 FP and CX3
+def imm_6b : BitWidthImm<6>;
+
+// Used by VCX2 vector
+def imm_7b : BitWidthImm<7>;
+
+// Used by CX2
+def imm_9b : BitWidthImm<9>;
+
+// Used by VCX1 FP
+def imm_11b : BitWidthImm<11>;
+
+// Used by VCX1 vector
+def imm_12b : BitWidthImm<12>;
+
+// Used by CX1
+def imm_13b : BitWidthImm<13>;
+
+// Base class for all CDE instructions
+class CDE_Instr<bit acc, dag oops, dag iops, string asm, string cstr>
+ : Thumb2XI<oops, !con((ins p_imm:$coproc), iops),
+ AddrModeNone, /*sz=*/4, NoItinerary,
+ asm, cstr, /*pattern=*/[]>,
+ Sched<[]> {
+ bits<3> coproc;
+
+ let Inst{31-29} = 0b111; // 15:13
+ let Inst{28} = acc;
+ let Inst{27-26} = 0b11;
+ let Inst{11} = 0b0;
+ let Inst{10-8} = coproc{2-0};
+
+ let isPredicable = 0;
+ let DecoderNamespace = "Thumb2CDE";
+}
+
+// Base class for CX* CDE instructions
+class CDE_GPR_Instr<bit dual, bit acc, dag oops, dag iops,
+ string asm, string cstr>
+ : CDE_Instr<acc, oops, iops, asm, cstr>,
+ Requires<[HasCDE]> {
+
+ let Inst{25-24} = 0b10;
+ let Inst{6} = dual;
+ let isPredicable = acc;
+}
+
+// Set of registers used by the CDE instructions.
+class CDE_RegisterOperands {
+ dag Rd;
+ dag Rd_src;
+ dag Rn;
+ dag Rm;
+}
+
+// CX* CDE instruction parameter set
+class CX_Params {
+ dag Oops; // Output operands for CX* instructions
+ dag Iops1; // Input operands for CX1* instructions
+ dag Iops2; // Input operands for CX2* instructions
+ dag Iops3; // Input operands for CX3* instructions
+ dag PredOp; // Input predicate operand
+ string PAsm; // Predicate assembly string
+ string Cstr; // asm constraint string
+ bit Dual; // "dual" field for encoding
+ bit Acc; // "acc" field for encoding
+}
+
+// VCX* CDE instruction parameter set
+class VCX_Params {
+ dag Oops; // Output operands for VCX* instructions
+ dag Iops1; // Input operands for VCX1* instructions
+ dag Iops2; // Input operands for VCX2* instructions
+ dag Iops3; // Input operands for VCX3* instructions
+ string Cstr; // asm constraint string
+ bit Acc; // "acc" field for encoding
+ vpred_ops Vpred; // Predication type for VCX* vector instructions
+}
+
+// CX1, CX1A, CX1D, CX1DA
+class CDE_CX1_Instr<string iname, CX_Params params>
+ : CDE_GPR_Instr<params.Dual, params.Acc, params.Oops,
+ !con(params.Iops1, (ins imm_13b:$imm), params.PredOp),
+ !strconcat(iname, params.PAsm, "\t$coproc, $Rd, $imm"),
+ params.Cstr> {
+ bits<13> imm;
+ bits<4> Rd;
+
+ let Inst{23-22} = 0b00;
+ let Inst{21-16} = imm{12-7};
+ let Inst{15-12} = Rd{3-0};
+ let Inst{7} = imm{6};
+ let Inst{5-0} = imm{5-0};
+}
+
+// CX2, CX2A, CX2D, CX2DA
+class CDE_CX2_Instr<string iname, CX_Params params>
+ : CDE_GPR_Instr<params.Dual, params.Acc, params.Oops,
+ !con(params.Iops2, (ins imm_9b:$imm), params.PredOp),
+ !strconcat(iname, params.PAsm, "\t$coproc, $Rd, $Rn, $imm"),
+ params.Cstr> {
+ bits<9> imm;
+ bits<4> Rd;
+ bits<4> Rn;
+
+ let Inst{23-22} = 0b01;
+ let Inst{21-20} = imm{8-7};
+ let Inst{19-16} = Rn{3-0};
+ let Inst{15-12} = Rd{3-0};
+ let Inst{7} = imm{6};
+ let Inst{5-0} = imm{5-0};
+}
+
+// CX3, CX3A, CX3D, CX3DA
+class CDE_CX3_Instr<string iname, CX_Params params>
+ : CDE_GPR_Instr<params.Dual, params.Acc, params.Oops,
+ !con(params.Iops3, (ins imm_6b:$imm), params.PredOp),
+ !strconcat(iname, params.PAsm, "\t$coproc, $Rd, $Rn, $Rm, $imm"),
+ params.Cstr> {
+ bits<6> imm;
+ bits<4> Rd;
+ bits<4> Rn;
+ bits<4> Rm;
+
+ let Inst{23} = 0b1;
+ let Inst{22-20} = imm{5-3};
+ let Inst{19-16} = Rn{3-0};
+ let Inst{15-12} = Rm{3-0};
+ let Inst{7} = imm{2};
+ let Inst{5-4} = imm{1-0};
+ let Inst{3-0} = Rd{3-0};
+}
+
+// Registers for single-register variants of CX* instructions
+def cde_cx_single_regs : CDE_RegisterOperands {
+ let Rd = (outs GPRwithAPSR_NZCVnosp:$Rd);
+ let Rd_src = (ins GPRwithAPSR_NZCVnosp:$Rd_src);
+ let Rn = (ins GPRwithAPSR_NZCVnosp:$Rn);
+ let Rm = (ins GPRwithAPSR_NZCVnosp:$Rm);
+}
+
+// Registers for single-register variants of CX* instructions
+def cde_cx_dual_regs : CDE_RegisterOperands {
+ let Rd = (outs CDEDualRegOp:$Rd);
+ let Rd_src = (ins CDEDualRegOp:$Rd_src);
+ let Rn = (ins GPRwithAPSR_NZCVnosp:$Rn);
+ let Rm = (ins GPRwithAPSR_NZCVnosp:$Rm);
+}
+
+class CDE_CX_ParamsTemplate<bit dual, bit acc, CDE_RegisterOperands ops>
+ : CX_Params {
+
+ dag IOpsPrefix = !if(acc, ops.Rd_src, (ins));
+
+ let Oops = ops.Rd;
+ let Iops1 = IOpsPrefix;
+ let Iops2 = !con(IOpsPrefix, ops.Rn);
+ let Iops3 = !con(IOpsPrefix, ops.Rn, ops.Rm);
+ let PredOp = !if(acc, (ins pred:$p), (ins));
+ let PAsm = !if(acc, "${p}", "");
+ let Cstr = !if(acc, "$Rd = $Rd_src", "");
+ let Dual = dual;
+ let Acc = acc;
+}
+
+def cde_cx_params_single_noacc : CDE_CX_ParamsTemplate<0b0, 0b0, cde_cx_single_regs>;
+def cde_cx_params_single_acc : CDE_CX_ParamsTemplate<0b0, 0b1, cde_cx_single_regs>;
+def cde_cx_params_dual_noacc : CDE_CX_ParamsTemplate<0b1, 0b0, cde_cx_dual_regs>;
+def cde_cx_params_dual_acc : CDE_CX_ParamsTemplate<0b1, 0b1, cde_cx_dual_regs>;
+
+def CDE_CX1 : CDE_CX1_Instr<"cx1", cde_cx_params_single_noacc>;
+def CDE_CX1A : CDE_CX1_Instr<"cx1a", cde_cx_params_single_acc>;
+def CDE_CX1D : CDE_CX1_Instr<"cx1d", cde_cx_params_dual_noacc>;
+def CDE_CX1DA : CDE_CX1_Instr<"cx1da", cde_cx_params_dual_acc>;
+
+def CDE_CX2 : CDE_CX2_Instr<"cx2", cde_cx_params_single_noacc>;
+def CDE_CX2A : CDE_CX2_Instr<"cx2a", cde_cx_params_single_acc>;
+def CDE_CX2D : CDE_CX2_Instr<"cx2d", cde_cx_params_dual_noacc>;
+def CDE_CX2DA : CDE_CX2_Instr<"cx2da", cde_cx_params_dual_acc>;
+
+def CDE_CX3 : CDE_CX3_Instr<"cx3", cde_cx_params_single_noacc>;
+def CDE_CX3A : CDE_CX3_Instr<"cx3a", cde_cx_params_single_acc>;
+def CDE_CX3D : CDE_CX3_Instr<"cx3d", cde_cx_params_dual_noacc>;
+def CDE_CX3DA : CDE_CX3_Instr<"cx3da", cde_cx_params_dual_acc>;
+
+class CDE_RequiresSReg : Requires<[HasCDE, HasFPRegs]>;
+class CDE_RequiresDReg : Requires<[HasCDE, HasFPRegs]>;
+class CDE_RequiresQReg : Requires<[HasCDE, HasMVEInt]>;
+
+// Base class for CDE VCX* instructions
+class CDE_FP_Vec_Instr<bit vec, bit acc, dag oops, dag iops, string asm, string cstr>
+ : CDE_Instr<acc, oops, iops, asm, cstr> {
+ let Inst{25} = 0b0;
+ let Inst{6} = vec;
+}
+
+// Base class for floating-point variants of CDE VCX* intructions
+class CDE_FP_Instr<bit acc, bit sz, dag oops, dag iops, string asm, string cstr>
+ : CDE_FP_Vec_Instr<0b0, acc, oops, iops, asm, cstr> {
+ let Inst{24} = sz;
+}
+
+// Base class for vector variants of CDE VCX* instruction
+class CDE_Vec_Instr<bit acc, dag oops, dag iops, string asm, string cstr,
+ vpred_ops vpred>
+ : CDE_FP_Vec_Instr<0b1, acc, oops,
+ !con(iops, (ins vpred:$vp)), asm,
+ !strconcat(cstr, vpred.vpred_constraint)>,
+ CDE_RequiresQReg {
+}
+
+
+// VCX1/VCX1A, vector variant
+class CDE_VCX1_Vec_Instr<string iname, VCX_Params params>
+ : CDE_Vec_Instr<params.Acc, params.Oops,
+ !con(params.Iops1, (ins imm_12b:$imm)),
+ iname#"${vp}\t$coproc, $Qd, $imm", params.Cstr, params.Vpred> {
+ bits<12> imm;
+ bits<3> Qd;
+
+ let Inst{24} = imm{11};
+ let Inst{23} = 0b0;
+ let Inst{22} = 0b0;
+ let Inst{21-20} = 0b10;
+ let Inst{19-16} = imm{10-7};
+ let Inst{15-13} = Qd{2-0};
+ let Inst{12} = 0b0;
+ let Inst{7} = imm{6};
+ let Inst{5-0} = imm{5-0};
+
+ let Unpredictable{22} = 0b1;
+}
+
+// VCX1/VCX1A, base class for FP variants
+class CDE_VCX1_FP_Instr<bit sz, string iname, VCX_Params params>
+ : CDE_FP_Instr<params.Acc, sz, params.Oops,
+ !con(params.Iops1, (ins imm_11b:$imm)),
+ iname#"\t$coproc, $Vd, $imm", params.Cstr> {
+ bits<11> imm;
+
+ let Inst{23} = 0b0;
+ let Inst{21-20} = 0b10;
+ let Inst{19-16} = imm{10-7};
+ let Inst{7} = imm{6};
+ let Inst{5-0} = imm{5-0};
+}
+
+// VCX1/VCX1A, S registers
+class CDE_VCX1_FP_Instr_S<string iname, VCX_Params params>
+ : CDE_VCX1_FP_Instr<0b0, iname, params>,
+ CDE_RequiresSReg {
+ bits<5> Vd;
+
+ let Inst{22} = Vd{0};
+ let Inst{15-12} = Vd{4-1};
+}
+
+// VCX1/VCX1A, D registers
+class CDE_VCX1_FP_Instr_D<string iname, VCX_Params params>
+ : CDE_VCX1_FP_Instr<0b1, iname, params>,
+ CDE_RequiresDReg {
+ bits<5> Vd;
+
+ let Inst{22} = Vd{4};
+ let Inst{15-12} = Vd{3-0};
+}
+
+// VCX2/VCX2A, vector variant
+class CDE_VCX2_Vec_Instr<string iname, VCX_Params params>
+ : CDE_Vec_Instr<params.Acc, params.Oops,
+ !con(params.Iops2, (ins imm_7b:$imm)),
+ iname#"${vp}\t$coproc, $Qd, $Qm, $imm", params.Cstr,
+ params.Vpred> {
+ bits<7> imm;
+ bits<3> Qd;
+ bits<3> Qm;
+
+ let Inst{24} = imm{6};
+ let Inst{23} = 0b0;
+ let Inst{22} = 0b0;
+ let Inst{21-20} = 0b11;
+ let Inst{19-16} = imm{5-2};
+ let Inst{15-13} = Qd{2-0};
+ let Inst{12} = 0b0;
+ let Inst{7} = imm{1};
+ let Inst{5} = 0b0;
+ let Inst{4} = imm{0};
+ let Inst{3-1} = Qm{2-0};
+ let Inst{0} = 0b0;
+
+ let Unpredictable{22} = 0b1;
+ let Unpredictable{5} = 0b1;
+}
+
+// VCX2/VCX2A, base class for FP variants
+class CDE_VCX2_FP_Instr<bit sz, string iname, VCX_Params params>
+ : CDE_FP_Instr<params.Acc, sz, params.Oops,
+ !con(params.Iops2, (ins imm_6b:$imm)),
+ iname#"\t$coproc, $Vd, $Vm, $imm", params.Cstr> {
+ bits<6> imm;
+
+ let Inst{23} = 0b0;
+ let Inst{21-20} = 0b11;
+ let Inst{19-16} = imm{5-2};
+ let Inst{7} = imm{1};
+ let Inst{4} = imm{0};
+}
+
+// VCX2/VCX2A, S registers
+class CDE_VCX2_FP_Instr_S<string iname, VCX_Params params>
+ : CDE_VCX2_FP_Instr<0b0, iname, params>,
+ CDE_RequiresSReg {
+ bits<5> Vd;
+ bits<5> Vm;
+
+ let Inst{15-12} = Vd{4-1};
+ let Inst{22} = Vd{0};
+ let Inst{3-0} = Vm{4-1};
+ let Inst{5} = Vm{0};
+}
+
+// VCX2/VCX2A, D registers
+class CDE_VCX2_FP_Instr_D<string iname, VCX_Params params>
+ : CDE_VCX2_FP_Instr<0b1, iname, params>,
+ CDE_RequiresDReg {
+ bits<5> Vd;
+ bits<5> Vm;
+
+ let Inst{15-12} = Vd{3-0};
+ let Inst{22} = Vd{4};
+ let Inst{3-0} = Vm{3-0};
+ let Inst{5} = Vm{4};
+}
+
+// VCX3/VCX3A, vector variant
+class CDE_VCX3_Vec_Instr<string iname, VCX_Params params>
+ : CDE_Vec_Instr<params.Acc, params.Oops,
+ !con(params.Iops3, (ins imm_4b:$imm)),
+ iname#"${vp}\t$coproc, $Qd, $Qn, $Qm, $imm", params.Cstr,
+ params.Vpred> {
+ bits<4> imm;
+ bits<3> Qd;
+ bits<3> Qm;
+ bits<3> Qn;
+
+ let Inst{24} = imm{3};
+ let Inst{23} = 0b1;
+ let Inst{22} = 0b0;
+ let Inst{21-20} = imm{2-1};
+ let Inst{19-17} = Qn{2-0};
+ let Inst{16} = 0b0;
+ let Inst{15-13} = Qd{2-0};
+ let Inst{12} = 0b0;
+ let Inst{7} = 0b0;
+ let Inst{5} = 0b0;
+ let Inst{4} = imm{0};
+ let Inst{3-1} = Qm{2-0};
+ let Inst{0} = 0b0;
+
+ let Unpredictable{22} = 0b1;
+ let Unpredictable{7} = 0b1;
+ let Unpredictable{5} = 0b1;
+}
+
+// VCX3/VCX3A, base class for FP variants
+class CDE_VCX3_FP_Instr<bit sz, string iname, VCX_Params params>
+ : CDE_FP_Instr<params.Acc, sz, params.Oops,
+ !con(params.Iops3, (ins imm_3b:$imm)),
+ iname#"\t$coproc, $Vd, $Vn, $Vm, $imm", params.Cstr> {
+ bits<3> imm;
+
+ let Inst{23} = 0b1;
+ let Inst{21-20} = imm{2-1};
+ let Inst{4} = imm{0};
+}
+
+// VCX3/VCX3A, S registers
+class CDE_VCX3_FP_Instr_S<string iname, VCX_Params params>
+ : CDE_VCX3_FP_Instr<0b0, iname, params>,
+ CDE_RequiresSReg {
+ bits<5> Vd;
+ bits<5> Vm;
+ bits<5> Vn;
+
+ let Inst{22} = Vd{0};
+ let Inst{19-16} = Vn{4-1};
+ let Inst{15-12} = Vd{4-1};
+ let Inst{7} = Vn{0};
+ let Inst{5} = Vm{0};
+ let Inst{3-0} = Vm{4-1};
+}
+
+// VCX3/VCX3A, D registers
+class CDE_VCX3_FP_Instr_D<string iname, VCX_Params params>
+ : CDE_VCX3_FP_Instr<0b1, iname, params>,
+ CDE_RequiresDReg {
+ bits<5> Vd;
+ bits<5> Vm;
+ bits<5> Vn;
+
+ let Inst{22} = Vd{4};
+ let Inst{19-16} = Vn{3-0};
+ let Inst{15-12} = Vd{3-0};
+ let Inst{7} = Vn{4};
+ let Inst{5} = Vm{4};
+ let Inst{3-0} = Vm{3-0};
+}
+
+// Register operands for VCX* instructions
+class CDE_VCX_RegisterOperandsTemplate<RegisterClass regclass>
+ : CDE_RegisterOperands {
+ let Rd = (outs regclass:$Vd);
+ let Rd_src = (ins regclass:$Vd_src);
+ let Rn = (ins regclass:$Vn);
+ let Rm = (ins regclass:$Vm);
+}
+
+class CDE_VCXQ_RegisterOperandsTemplate<RegisterClass regclass>
+ : CDE_RegisterOperands {
+ let Rd = (outs regclass:$Qd);
+ let Rd_src = (ins regclass:$Qd_src);
+ let Rn = (ins regclass:$Qn);
+ let Rm = (ins regclass:$Qm);
+}
+
+def cde_vcx_s_regs : CDE_VCX_RegisterOperandsTemplate<SPR>;
+def cde_vcx_d_regs : CDE_VCX_RegisterOperandsTemplate<DPR_VFP2>;
+def cde_vcx_q_regs : CDE_VCXQ_RegisterOperandsTemplate<MQPR>;
+
+class CDE_VCX_ParamsTemplate<bit acc, CDE_RegisterOperands ops>
+ : VCX_Params {
+
+ dag IOpsPrefix = !if(acc, ops.Rd_src, (ins));
+
+ let Oops = ops.Rd;
+ let Iops1 = IOpsPrefix;
+ let Iops2 = !con(IOpsPrefix, ops.Rm);
+ let Iops3 = !con(IOpsPrefix, ops.Rn, ops.Rm);
+ let Cstr = !if(acc, "$Vd = $Vd_src", "");
+ let Acc = acc;
+}
+
+class CDE_VCXQ_ParamsTemplate<bit acc, CDE_RegisterOperands ops>
+ : VCX_Params {
+
+ dag IOpsPrefix = !if(acc, ops.Rd_src, (ins));
+
+ let Oops = ops.Rd;
+ let Iops1 = IOpsPrefix;
+ let Iops2 = !con(IOpsPrefix, ops.Rm);
+ let Iops3 = !con(IOpsPrefix, ops.Rn, ops.Rm);
+ let Cstr = !if(acc, "$Qd = $Qd_src", "");
+ let Acc = acc;
+ let Vpred = !if(acc, vpred_n, vpred_r);
+}
+
+def cde_vcx_params_s_noacc : CDE_VCX_ParamsTemplate<0b0, cde_vcx_s_regs>;
+def cde_vcx_params_s_acc : CDE_VCX_ParamsTemplate<0b1, cde_vcx_s_regs>;
+def cde_vcx_params_d_noacc : CDE_VCX_ParamsTemplate<0b0, cde_vcx_d_regs>;
+def cde_vcx_params_d_acc : CDE_VCX_ParamsTemplate<0b1, cde_vcx_d_regs>;
+def cde_vcx_params_q_noacc : CDE_VCXQ_ParamsTemplate<0b0, cde_vcx_q_regs>;
+def cde_vcx_params_q_acc : CDE_VCXQ_ParamsTemplate<0b1, cde_vcx_q_regs>;
+
+def CDE_VCX1_fpsp : CDE_VCX1_FP_Instr_S<"vcx1", cde_vcx_params_s_noacc>;
+def CDE_VCX1A_fpsp : CDE_VCX1_FP_Instr_S<"vcx1a", cde_vcx_params_s_acc>;
+def CDE_VCX1_fpdp : CDE_VCX1_FP_Instr_D<"vcx1", cde_vcx_params_d_noacc>;
+def CDE_VCX1A_fpdp : CDE_VCX1_FP_Instr_D<"vcx1a", cde_vcx_params_d_acc>;
+def CDE_VCX1_vec : CDE_VCX1_Vec_Instr<"vcx1", cde_vcx_params_q_noacc>;
+def CDE_VCX1A_vec : CDE_VCX1_Vec_Instr<"vcx1a", cde_vcx_params_q_acc>;
+
+def CDE_VCX2_fpsp : CDE_VCX2_FP_Instr_S<"vcx2", cde_vcx_params_s_noacc>;
+def CDE_VCX2A_fpsp : CDE_VCX2_FP_Instr_S<"vcx2a", cde_vcx_params_s_acc>;
+def CDE_VCX2_fpdp : CDE_VCX2_FP_Instr_D<"vcx2", cde_vcx_params_d_noacc>;
+def CDE_VCX2A_fpdp : CDE_VCX2_FP_Instr_D<"vcx2a", cde_vcx_params_d_acc>;
+def CDE_VCX2_vec : CDE_VCX2_Vec_Instr<"vcx2", cde_vcx_params_q_noacc>;
+def CDE_VCX2A_vec : CDE_VCX2_Vec_Instr<"vcx2a", cde_vcx_params_q_acc>;
+
+def CDE_VCX3_fpsp : CDE_VCX3_FP_Instr_S<"vcx3", cde_vcx_params_s_noacc>;
+def CDE_VCX3A_fpsp : CDE_VCX3_FP_Instr_S<"vcx3a", cde_vcx_params_s_acc>;
+def CDE_VCX3_fpdp : CDE_VCX3_FP_Instr_D<"vcx3", cde_vcx_params_d_noacc>;
+def CDE_VCX3A_fpdp : CDE_VCX3_FP_Instr_D<"vcx3a", cde_vcx_params_d_acc>;
+def CDE_VCX3_vec : CDE_VCX3_Vec_Instr<"vcx3", cde_vcx_params_q_noacc>;
+def CDE_VCX3A_vec : CDE_VCX3_Vec_Instr<"vcx3a", cde_vcx_params_q_acc>;
diff --git a/llvm/lib/Target/ARM/ARMInstrInfo.td b/llvm/lib/Target/ARM/ARMInstrInfo.td
index 2674cc12b506..1efd57ea5e87 100644
--- a/llvm/lib/Target/ARM/ARMInstrInfo.td
+++ b/llvm/lib/Target/ARM/ARMInstrInfo.td
@@ -5994,6 +5994,12 @@ include "ARMInstrNEON.td"
include "ARMInstrMVE.td"
+//===----------------------------------------------------------------------===//
+// CDE (Custom Datapath Extension)
+//
+
+include "ARMInstrCDE.td"
+
//===----------------------------------------------------------------------===//
// Assembler aliases
//
diff --git a/llvm/lib/Target/ARM/ARMPredicates.td b/llvm/lib/Target/ARM/ARMPredicates.td
index dea1d767beb4..7337c8dcecd4 100644
--- a/llvm/lib/Target/ARM/ARMPredicates.td
+++ b/llvm/lib/Target/ARM/ARMPredicates.td
@@ -35,6 +35,9 @@ def HasMVEInt : Predicate<"Subtarget->hasMVEIntegerOps()">,
def HasMVEFloat : Predicate<"Subtarget->hasMVEFloatOps()">,
AssemblerPredicate<"HasMVEFloatOps",
"mve.fp">;
+def HasCDE : Predicate<"Subtarget->hasCDEOps()">,
+ AssemblerPredicate<"HasCDEOps",
+ "cde">;
def HasFPRegs : Predicate<"Subtarget->hasFPRegs()">,
AssemblerPredicate<"FeatureFPRegs",
"fp registers">;
diff --git a/llvm/lib/Target/ARM/ARMRegisterInfo.td b/llvm/lib/Target/ARM/ARMRegisterInfo.td
index 56055a15483a..3b260f95a98d 100644
--- a/llvm/lib/Target/ARM/ARMRegisterInfo.td
+++ b/llvm/lib/Target/ARM/ARMRegisterInfo.td
@@ -305,6 +305,17 @@ def rGPR : RegisterClass<"ARM", [i32], 32, (sub GPR, SP, PC)> {
let DiagnosticType = "rGPR";
}
+// GPRs without the PC and SP but with APSR_NZCV.Some instructions allow
+// accessing the APSR_NZCV, while actually encoding PC in the register field.
+// This is useful for assembly and disassembly only.
+// Currently used by the CDE extension.
+def GPRwithAPSR_NZCVnosp
+ : RegisterClass<"ARM", [i32], 32, (add (sequence "R%u", 0, 12), LR, APSR_NZCV)> {
+ let isAllocatable = 0;
+ let DiagnosticString =
+ "operand must be a register in the range [r0, r12], r14 or apsr_nzcv";
+}
+
// Thumb registers are R0-R7 normally. Some instructions can still use
// the general GPR register class above (MOV, e.g.)
def tGPR : RegisterClass<"ARM", [i32], 32, (trunc GPR, 8)> {
diff --git a/llvm/lib/Target/ARM/ARMSubtarget.h b/llvm/lib/Target/ARM/ARMSubtarget.h
index 6bdd021970ef..27f67a9acbd3 100644
--- a/llvm/lib/Target/ARM/ARMSubtarget.h
+++ b/llvm/lib/Target/ARM/ARMSubtarget.h
@@ -162,6 +162,7 @@ class ARMSubtarget : public ARMGenSubtargetInfo {
bool HasV8_1MMainlineOps = false;
bool HasMVEIntegerOps = false;
bool HasMVEFloatOps = false;
+ bool HasCDEOps = false;
/// HasVFPv2, HasVFPv3, HasVFPv4, HasFPARMv8, HasNEON - Specify what
/// floating point ISAs are supported.
@@ -562,6 +563,7 @@ class ARMSubtarget : public ARMGenSubtargetInfo {
void initSubtargetFeatures(StringRef CPU, StringRef FS);
ARMFrameLowering *initializeFrameLowering(StringRef CPU, StringRef FS);
+ std::bitset<8> CoprocCDE = {};
public:
void computeIssueWidth();
@@ -584,6 +586,7 @@ class ARMSubtarget : public ARMGenSubtargetInfo {
bool hasV8_1MMainlineOps() const { return HasV8_1MMainlineOps; }
bool hasMVEIntegerOps() const { return HasMVEIntegerOps; }
bool hasMVEFloatOps() const { return HasMVEFloatOps; }
+ bool hasCDEOps() const { return HasCDEOps; }
bool hasFPRegs() const { return HasFPRegs; }
bool hasFPRegs16() const { return HasFPRegs16; }
bool hasFPRegs64() const { return HasFPRegs64; }
diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
index 1d11da221b91..65c2d4790633 100644
--- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
+++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
@@ -22,6 +22,7 @@
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
@@ -180,10 +181,68 @@ class UnwindContext {
}
};
+// Various sets of ARM instruction mnemonics which are used by the asm parser
+class ARMMnemonicSets {
+ StringSet<> CDE;
+ StringSet<> CDEWithVPTSuffix;
+public:
+ ARMMnemonicSets(const MCSubtargetInfo &STI);
+
+ /// Returns true iff a given mnemonic is a CDE instruction
+ bool isCDEInstr(StringRef Mnemonic) {
+ // Quick check before searching the set
+ if (!Mnemonic.startswith("cx") && !Mnemonic.startswith("vcx"))
+ return false;
+ return CDE.count(Mnemonic);
+ }
+
+ /// Returns true iff a given mnemonic is a VPT-predicable CDE instruction
+ /// (possibly with a predication suffix "e" or "t")
+ bool isVPTPredicableCDEInstr(StringRef Mnemonic) {
+ if (!Mnemonic.startswith("vcx"))
+ return false;
+ return CDEWithVPTSuffix.count(Mnemonic);
+ }
+
+ /// Returns true iff a given mnemonic is an IT-predicable CDE instruction
+ /// (possibly with a condition suffix)
+ bool isITPredicableCDEInstr(StringRef Mnemonic) {
+ if (!Mnemonic.startswith("cx"))
+ return false;
+ return Mnemonic.startswith("cx1a") || Mnemonic.startswith("cx1da") ||
+ Mnemonic.startswith("cx2a") || Mnemonic.startswith("cx2da") ||
+ Mnemonic.startswith("cx3a") || Mnemonic.startswith("cx3da");
+ }
+
+ /// Return true iff a given mnemonic is an integer CDE instruction with
+ /// dual-register destination
+ bool isCDEDualRegInstr(StringRef Mnemonic) {
+ if (!Mnemonic.startswith("cx"))
+ return false;
+ return Mnemonic == "cx1d" || Mnemonic == "cx1da" ||
+ Mnemonic == "cx2d" || Mnemonic == "cx2da" ||
+ Mnemonic == "cx3d" || Mnemonic == "cx3da";
+ }
+};
+
+ARMMnemonicSets::ARMMnemonicSets(const MCSubtargetInfo &STI) {
+ for (StringRef Mnemonic: { "cx1", "cx1a", "cx1d", "cx1da",
+ "cx2", "cx2a", "cx2d", "cx2da",
+ "cx3", "cx3a", "cx3d", "cx3da", })
+ CDE.insert(Mnemonic);
+ for (StringRef Mnemonic :
+ {"vcx1", "vcx1a", "vcx2", "vcx2a", "vcx3", "vcx3a"}) {
+ CDE.insert(Mnemonic);
+ CDEWithVPTSuffix.insert(Mnemonic);
+ CDEWithVPTSuffix.insert(std::string(Mnemonic) + "t");
+ CDEWithVPTSuffix.insert(std::string(Mnemonic) + "e");
+ }
+}
class ARMAsmParser : public MCTargetAsmParser {
const MCRegisterInfo *MRI;
UnwindContext UC;
+ ARMMnemonicSets MS;
ARMTargetStreamer &getTargetStreamer() {
assert(getParser().getStreamer().getTargetStreamer() &&
@@ -444,6 +503,8 @@ class ARMAsmParser : public MCTargetAsmParser {
void tryConvertingToTwoOperandForm(StringRef Mnemonic, bool CarrySetting,
OperandVector &Operands);
+ bool CDEConvertDualRegOperand(StringRef Mnemonic, OperandVector &Operands);
+
bool isThumb() const {
// FIXME: Can tablegen auto-generate this?
return getSTI().getFeatureBits()[ARM::ModeThumb];
@@ -501,6 +562,9 @@ class ARMAsmParser : public MCTargetAsmParser {
bool hasMVEFloat() const {
return getSTI().getFeatureBits()[ARM::HasMVEFloatOps];
}
+ bool hasCDE() const {
+ return getSTI().getFeatureBits()[ARM::HasCDEOps];
+ }
bool has8MSecExt() const {
return getSTI().getFeatureBits()[ARM::Feature8MSecExt];
}
@@ -605,7 +669,7 @@ class ARMAsmParser : public MCTargetAsmParser {
ARMAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
const MCInstrInfo &MII, const MCTargetOptions &Options)
- : MCTargetAsmParser(Options, STI, MII), UC(Parser) {
+ : MCTargetAsmParser(Options, STI, MII), UC(Parser), MS(STI) {
MCAsmParserExtension::Initialize(Parser);
// Cache the MCRegisterInfo.
@@ -6391,6 +6455,8 @@ void ARMAsmParser::getMnemonicAcceptInfo(StringRef Mnemonic,
Mnemonic == "cinc" || Mnemonic == "cinv" || Mnemonic == "cneg" ||
Mnemonic == "cset" || Mnemonic == "csetm" ||
Mnemonic.startswith("vpt") || Mnemonic.startswith("vpst") ||
+ (hasCDE() && MS.isCDEInstr(Mnemonic) &&
+ !MS.isITPredicableCDEInstr(Mnemonic)) ||
(hasMVE() &&
(Mnemonic.startswith("vst2") || Mnemonic.startswith("vld2") ||
Mnemonic.startswith("vst4") || Mnemonic.startswith("vld4") ||
@@ -6780,6 +6846,69 @@ void ARMAsmParser::fixupGNULDRDAlias(StringRef Mnemonic,
ARMOperand::CreateReg(PairedReg, Op2.getStartLoc(), Op2.getEndLoc()));
}
+// Dual-register instruction have the following syntax:
+// <mnemonic> <predicate>? <coproc>, <Rdest>, <Rdest+1>, <Rsrc>, ..., #imm
+// This function tries to remove <Rdest+1> and replace <Rdest> with a pair
+// operand. If the conversion fails an error is diagnosed, and the function
+// returns true.
+bool ARMAsmParser::CDEConvertDualRegOperand(StringRef Mnemonic,
+ OperandVector &Operands) {
+ assert(MS.isCDEDualRegInstr(Mnemonic));
+ bool isPredicable =
+ Mnemonic == "cx1da" || Mnemonic == "cx2da" || Mnemonic == "cx3da";
+ size_t NumPredOps = isPredicable ? 1 : 0;
+
+ if (Operands.size() <= 3 + NumPredOps)
+ return false;
+
+ StringRef Op2Diag(
+ "operand must be an even-numbered register in the range [r0, r10]");
+
+ const MCParsedAsmOperand &Op2 = *Operands[2 + NumPredOps];
+ if (!Op2.isReg())
+ return Error(Op2.getStartLoc(), Op2Diag);
+
+ unsigned RNext;
+ unsigned RPair;
+ switch (Op2.getReg()) {
+ default:
+ return Error(Op2.getStartLoc(), Op2Diag);
+ case ARM::R0:
+ RNext = ARM::R1;
+ RPair = ARM::R0_R1;
+ break;
+ case ARM::R2:
+ RNext = ARM::R3;
+ RPair = ARM::R2_R3;
+ break;
+ case ARM::R4:
+ RNext = ARM::R5;
+ RPair = ARM::R4_R5;
+ break;
+ case ARM::R6:
+ RNext = ARM::R7;
+ RPair = ARM::R6_R7;
+ break;
+ case ARM::R8:
+ RNext = ARM::R9;
+ RPair = ARM::R8_R9;
+ break;
+ case ARM::R10:
+ RNext = ARM::R11;
+ RPair = ARM::R10_R11;
+ break;
+ }
+
+ const MCParsedAsmOperand &Op3 = *Operands[3 + NumPredOps];
+ if (!Op3.isReg() || Op3.getReg() != RNext)
+ return Error(Op3.getStartLoc(), "operand must be a consecutive register");
+
+ Operands.erase(Operands.begin() + 3 + NumPredOps);
+ Operands[2 + NumPredOps] =
+ ARMOperand::CreateReg(RPair, Op2.getStartLoc(), Op2.getEndLoc());
+ return false;
+}
+
/// Parse an arm instruction mnemonic followed by its operands.
bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
SMLoc NameLoc, OperandVector &Operands) {
@@ -6979,6 +7108,21 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
tryConvertingToTwoOperandForm(Mnemonic, CarrySetting, Operands);
+ if (hasCDE() && MS.isCDEInstr(Mnemonic)) {
+ // Dual-register instructions use even-odd register pairs as their
+ // destination operand, in assembly such pair is spelled as two
+ // consecutive registers, without any special syntax. ConvertDualRegOperand
+ // tries to convert such operand into register pair, e.g. r2, r3 -> r2_r3.
+ // It returns true, if an error message has been emitted. If the function
+ // returns false, the function either succeeded or an error (e.g. missing
+ // operand) will be diagnosed elsewhere.
+ if (MS.isCDEDualRegInstr(Mnemonic)) {
+ bool GotError = CDEConvertDualRegOperand(Mnemonic, Operands);
+ if (GotError)
+ return GotError;
+ }
+ }
+
// Some instructions, mostly Thumb, have forms for the same mnemonic that
// do and don't have a cc_out optional-def operand. With some spot-checks
// of the operand list, we can figure out which variant we're trying to
@@ -7991,6 +8135,54 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
}
break;
}
+
+ case ARM::CDE_CX1: case ARM::CDE_CX1A: case ARM::CDE_CX1D: case ARM::CDE_CX1DA:
+ case ARM::CDE_CX2: case ARM::CDE_CX2A: case ARM::CDE_CX2D: case ARM::CDE_CX2DA:
+ case ARM::CDE_CX3: case ARM::CDE_CX3A: case ARM::CDE_CX3D: case ARM::CDE_CX3DA:
+ case ARM::CDE_VCX1_vec: case ARM::CDE_VCX1_fpsp: case ARM::CDE_VCX1_fpdp:
+ case ARM::CDE_VCX1A_vec: case ARM::CDE_VCX1A_fpsp: case ARM::CDE_VCX1A_fpdp:
+ case ARM::CDE_VCX2_vec: case ARM::CDE_VCX2_fpsp: case ARM::CDE_VCX2_fpdp:
+ case ARM::CDE_VCX2A_vec: case ARM::CDE_VCX2A_fpsp: case ARM::CDE_VCX2A_fpdp:
+ case ARM::CDE_VCX3_vec: case ARM::CDE_VCX3_fpsp: case ARM::CDE_VCX3_fpdp:
+ case ARM::CDE_VCX3A_vec: case ARM::CDE_VCX3A_fpsp: case ARM::CDE_VCX3A_fpdp: {
+ assert(Inst.getOperand(1).isImm() &&
+ "CDE operand 1 must be a coprocessor ID");
+ int64_t Coproc = Inst.getOperand(1).getImm();
+ if (Coproc < 8 && !ARM::isCDECoproc(Coproc, *STI))
+ return Error(Operands[1]->getStartLoc(),
+ "coprocessor must be configured as CDE");
+ else if (Coproc >= 8)
+ return Error(Operands[1]->getStartLoc(),
+ "coprocessor must be in the range [p0, p7]");
+ break;
+ }
+
+ case ARM::t2CDP: case ARM::t2CDP2:
+ case ARM::t2LDC2L_OFFSET: case ARM::t2LDC2L_OPTION: case ARM::t2LDC2L_POST: case ARM::t2LDC2L_PRE:
+ case ARM::t2LDC2_OFFSET: case ARM::t2LDC2_OPTION: case ARM::t2LDC2_POST: case ARM::t2LDC2_PRE:
+ case ARM::t2LDCL_OFFSET: case ARM::t2LDCL_OPTION: case ARM::t2LDCL_POST: case ARM::t2LDCL_PRE:
+ case ARM::t2LDC_OFFSET: case ARM::t2LDC_OPTION: case ARM::t2LDC_POST: case ARM::t2LDC_PRE:
+ case ARM::t2MCR: case ARM::t2MCR2: case ARM::t2MCRR: case ARM::t2MCRR2:
+ case ARM::t2MRC: case ARM::t2MRC2: case ARM::t2MRRC: case ARM::t2MRRC2:
+ case ARM::t2STC2L_OFFSET: case ARM::t2STC2L_OPTION: case ARM::t2STC2L_POST: case ARM::t2STC2L_PRE:
+ case ARM::t2STC2_OFFSET: case ARM::t2STC2_OPTION: case ARM::t2STC2_POST: case ARM::t2STC2_PRE:
+ case ARM::t2STCL_OFFSET: case ARM::t2STCL_OPTION: case ARM::t2STCL_POST: case ARM::t2STCL_PRE:
+ case ARM::t2STC_OFFSET: case ARM::t2STC_OPTION: case ARM::t2STC_POST: case ARM::t2STC_PRE: {
+ unsigned Opcode = Inst.getOpcode();
+ // Inst.getOperand indexes operands in the (oops ...) and (iops ...) dags,
+ // CopInd is the index of the coprocessor operand.
+ size_t CopInd = 0;
+ if (Opcode == ARM::t2MRRC || Opcode == ARM::t2MRRC2)
+ CopInd = 2;
+ else if (Opcode == ARM::t2MRC || Opcode == ARM::t2MRC2)
+ CopInd = 1;
+ assert(Inst.getOperand(CopInd).isImm() && "Operand must be a coprocessor ID");
+ int64_t Coproc = Inst.getOperand(CopInd).getImm();
+ // Operands[2] is the coprocessor operand at syntactic level
+ if (ARM::isCDECoproc(Coproc, *STI))
+ return Error(Operands[2]->getStartLoc(), "coprocessor must be configured as GCP");
+ break;
+ }
}
return false;
@@ -11969,6 +12161,7 @@ bool ARMAsmParser::isMnemonicVPTPredicable(StringRef Mnemonic,
Mnemonic.startswith("vpnot") || Mnemonic.startswith("vbic") ||
Mnemonic.startswith("vrmlsldavh") || Mnemonic.startswith("vmlsldav") ||
Mnemonic.startswith("vcvt") ||
+ MS.isVPTPredicableCDEInstr(Mnemonic) ||
(Mnemonic.startswith("vmov") &&
!(ExtraToken == ".f16" || ExtraToken == ".32" ||
ExtraToken == ".16" || ExtraToken == ".8"));
diff --git a/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
index e640f09794ec..6938814e671a 100644
--- a/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
+++ b/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
@@ -182,6 +182,9 @@ static DecodeStatus DecodetGPROddRegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address, const void *Decoder);
static DecodeStatus DecodetGPREvenRegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address, const void *Decoder);
+static DecodeStatus
+DecodeGPRwithAPSR_NZCVnospRegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder);
static DecodeStatus DecodeGPRnopcRegisterClass(MCInst &Inst,
unsigned RegNo, uint64_t Address,
const void *Decoder);
@@ -201,6 +204,8 @@ static DecodeStatus DecoderGPRRegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address, const void *Decoder);
static DecodeStatus DecodeGPRPairRegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address, const void *Decoder);
+static DecodeStatus DecodeGPRPairnospRegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder);
static DecodeStatus DecodeGPRspRegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address,
const void *Decoder);
@@ -1083,8 +1088,12 @@ DecodeStatus ARMDisassembler::getThumbInstruction(MCInst &MI, uint64_t &Size,
}
}
+ uint32_t Coproc = fieldFromInstruction(Insn32, 8, 4);
+ const uint8_t *DecoderTable = ARM::isCDECoproc(Coproc, STI)
+ ? DecoderTableThumb2CDE32
+ : DecoderTableThumb2CoProc32;
Result =
- decodeInstruction(DecoderTableThumb2CoProc32, MI, Insn32, Address, this, STI);
+ decodeInstruction(DecoderTable, MI, Insn32, Address, this, STI);
if (Result != MCDisassembler::Fail) {
Size = 4;
Check(Result, AddThumbPredicate(MI));
@@ -1227,6 +1236,19 @@ static DecodeStatus DecodeGPRPairRegisterClass(MCInst &Inst, unsigned RegNo,
return S;
}
+static DecodeStatus DecodeGPRPairnospRegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder) {
+ if (RegNo > 13)
+ return MCDisassembler::Fail;
+
+ unsigned RegisterPair = GPRPairDecoderTable[RegNo/2];
+ Inst.addOperand(MCOperand::createReg(RegisterPair));
+
+ if ((RegNo & 1) || RegNo > 10)
+ return MCDisassembler::SoftFail;
+ return MCDisassembler::Success;
+}
+
static DecodeStatus DecodeGPRspRegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address,
const void *Decoder) {
@@ -6064,6 +6086,23 @@ static DecodeStatus DecodetGPREvenRegisterClass(MCInst &Inst, unsigned RegNo,
return MCDisassembler::Success;
}
+static DecodeStatus
+DecodeGPRwithAPSR_NZCVnospRegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder) {
+ if (RegNo == 15) {
+ Inst.addOperand(MCOperand::createReg(ARM::APSR_NZCV));
+ return MCDisassembler::Success;
+ }
+
+ unsigned Register = GPRDecoderTable[RegNo];
+ Inst.addOperand(MCOperand::createReg(Register));
+
+ if (RegNo == 13)
+ return MCDisassembler::SoftFail;
+
+ return MCDisassembler::Success;
+}
+
static DecodeStatus DecodeVSCCLRM(MCInst &Inst, unsigned Insn, uint64_t Address,
const void *Decoder) {
DecodeStatus S = MCDisassembler::Success;
diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp
index f24fea2ee06b..1536a3412ddd 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp
@@ -321,6 +321,14 @@ static MCInstrAnalysis *createThumbMCInstrAnalysis(const MCInstrInfo *Info) {
return new ThumbMCInstrAnalysis(Info);
}
+bool ARM::isCDECoproc(size_t Coproc, const MCSubtargetInfo &STI) {
+ // Unfortunately we don't have ARMTargetInfo in the disassembler, so we have
+ // to rely on feature bits.
+ if (Coproc >= 8)
+ return false;
+ return STI.getFeatureBits()[ARM::FeatureCoprocCDE0 + Coproc];
+}
+
// Force static initialization.
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeARMTargetMC() {
for (Target *T : {&getTheARMLETarget(), &getTheARMBETarget(),
diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.h b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.h
index 9cbbd56225ef..7cfe6881b456 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.h
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.h
@@ -107,6 +107,9 @@ inline bool isVpred(OperandType op) {
inline bool isVpred(uint8_t op) {
return isVpred(static_cast<OperandType>(op));
}
+
+bool isCDECoproc(size_t Coproc, const MCSubtargetInfo &STI);
+
} // end namespace ARM
} // End llvm namespace
diff --git a/llvm/test/MC/ARM/cde-fp-vec.s b/llvm/test/MC/ARM/cde-fp-vec.s
new file mode 100644
index 000000000000..4b139579b719
--- /dev/null
+++ b/llvm/test/MC/ARM/cde-fp-vec.s
@@ -0,0 +1,129 @@
+// RUN: not llvm-mc -triple=thumbv8m.main -mattr=+fp-armv8 -mattr=+cdecp0 -mattr=+cdecp1 -show-encoding < %s 2>%t | FileCheck %s
+// RUN: FileCheck <%t --check-prefixes=ERROR,ERROR-FP %s
+// RUN: not llvm-mc -triple=thumbv8m.main -mattr=+fp-armv8d16sp -mattr=+cdecp0 -mattr=+cdecp1 -show-encoding < %s 2>%t | FileCheck %s
+// RUN: FileCheck <%t --check-prefixes=ERROR,ERROR-FP %s
+// RUN: not llvm-mc -triple=thumbv8.1m.main -mattr=+mve -mattr=+cdecp0 -mattr=+cdecp1 -show-encoding < %s 2>%t | FileCheck --check-prefixes=CHECK,CHECK-MVE %s
+// RUN: FileCheck <%t --check-prefixes=ERROR,ERROR-MVE %s
+
+// CHECK-LABEL: test_predication:
+test_predication:
+ittt eq
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: instructions in IT block must be predicable
+vcx1a p1, s7, #2047
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: instructions in IT block must be predicable
+vcx2 p0, d0, d15, #0
+// ERROR-FP: [[@LINE+2]]:{{[0-9]+}}: error: invalid instruction
+// ERROR-MVE: [[@LINE+1]]:{{[0-9]+}}: error: instructions in IT block must be predicable
+vcx3 p0, q0, q7, q0, #12
+nop
+nop
+nop
+
+// CHECK-LABEL: test_vcx1:
+test_vcx1:
+// CHECK-NEXT: vcx1 p0, s11, #1234 @ encoding: [0x69,0xec,0x92,0x50]
+vcx1 p0, s11, #1234
+// CHECK-NEXT: vcx1a p1, s7, #2047 @ encoding: [0x6f,0xfc,0xbf,0x31]
+vcx1a p1, s7, #2047
+// CHECK-NEXT: vcx1 p0, d0, #0 @ encoding: [0x20,0xed,0x00,0x00]
+vcx1 p0, d0, #0
+// CHECK-NEXT: vcx1a p1, d3, #2047 @ encoding: [0x2f,0xfd,0xbf,0x31]
+vcx1a p1, d3, #2047
+// CHECK-MVE-NEXT: vcx1 p0, q1, #1234 @ encoding: [0x29,0xec,0xd2,0x20]
+// ERROR-FP: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction, any one of the following would fix this:
+vcx1 p0, q1, #1234
+// CHECK-MVE-NEXT: vcx1a p1, q5, #4095 @ encoding: [0x2f,0xfd,0xff,0xa1]
+// ERROR-FP: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx1a p1, q5, #4095
+
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx1a p1, s7, s7, #2047
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: operand must be an immediate in the range [0,2047]
+vcx1 p0, d0, #2048
+// ERROR-FP: [[@LINE+1]]:{{[0-9]+}}: error: operand must be an immediate in the range [0,2047]
+vcx1a p1, s0, #2048
+// ERROR-FP: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx1 p0, q0, #4096
+// ERROR-FP: [[@LINE+2]]:{{[0-9]+}}: error: coprocessor must be in the range [p0, p7]
+// ERROR-MVE: [[@LINE+1]]:{{[0-9]+}}: error: invalid operand for instruction
+vcx1 p8, d0, #1234
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx1 p0, d16, #1234
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx1 p0, s32, #1234
+// ERROR-FP: [[@LINE+4]]:{{[0-9]+}}: error: invalid instruction, any one of the following would fix this:
+// ERROR-FP: [[@LINE+3]]:{{[0-9]+}}: note: operand must be a register in range [s0, s31]
+// ERROR-FP: [[@LINE+2]]:{{[0-9]+}}: note: operand must be a register in range [d0, d15]
+// ERROR-MVE: [[@LINE+1]]:{{[0-9]+}}: error: operand must be a register in range [q0, q7]
+vcx1 p0, q8, #1234
+// ERROR: [[@LINE+3]]:{{[0-9]+}}: error: invalid instruction, any one of the following would fix this:
+// ERROR: [[@LINE+2]]:{{[0-9]+}}: note: operand must be a register in range [s0, s31]
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: note: operand must be a register in range [d0, d15]
+vcx1 p0, r0, #1234
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx1 p0, d0, d0, #0
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx1a p0, d0, d2, #0
+
+// CHECK-LABEL: test_vcx2:
+test_vcx2:
+// CHECK-NEXT: vcx2 p0, s0, s31, #12 @ encoding: [0x33,0xec,0x2f,0x00]
+vcx2 p0, s0, s31, #12
+// CHECK-NEXT: vcx2a p0, s1, s1, #63 @ encoding: [0x7f,0xfc,0xb0,0x00]
+vcx2a p0, s1, s1, #63
+// CHECK-NEXT: vcx2 p0, d0, d15, #0 @ encoding: [0x30,0xed,0x0f,0x00]
+vcx2 p0, d0, d15, #0
+// CHECK-NEXT: vcx2a p0, d1, d11, #63 @ encoding: [0x3f,0xfd,0x9b,0x10]
+vcx2a p0, d1, d11, #63
+// CHECK-MVE: vcx2 p1, q0, q6, #123 @ encoding: [0x3e,0xed,0xdc,0x01]
+vcx2 p1, q0, q6, #123
+// CHECK-MVE: vcx2a p1, q3, q7, #127 @ encoding: [0x3f,0xfd,0xde,0x61]
+vcx2a p1, q3, q7, #127
+
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: operand must be an immediate in the range [0,63]
+vcx2 p0, d0, d1, #64
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: operand must be an immediate in the range [0,63]
+vcx2a p0, s3, s1, #64
+// ERROR-MVE: [[@LINE+2]]:{{[0-9]+}}: error: operand must be an immediate in the range [0,127]
+// ERROR-FP: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx2a p0, q1, q5, #128
+// ERROR-FP: [[@LINE+1]]:{{[0-9]+}}: error: operand must be a register in range [d0, d15]
+vcx2 p1, d0, q2, #0
+// ERROR-FP: [[@LINE+1]]:{{[0-9]+}}: error: operand must be a register in range [s0, s31]
+vcx2a p1, q2, s3, #0
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx2 p1, d0, d0, d2, #0
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx2a p1, q2, q3, q1, #0
+
+// CHECK-LABEL: test_vcx3:
+test_vcx3:
+// CHECK-NEXT: vcx3 p0, s0, s31, s0, #1 @ encoding: [0x8f,0xec,0x90,0x00]
+vcx3 p0, s0, s31, s0, #1
+// CHECK-NEXT: vcx3a p1, s1, s17, s11, #7 @ encoding: [0xf8,0xfc,0xb5,0x01]
+vcx3a p1, s1, s17, s11, #7
+// CHECK-NEXT: vcx3 p0, d0, d15, d7, #0 @ encoding: [0x8f,0xed,0x07,0x00]
+vcx3 p0, d0, d15, d7, #0
+// CHECK-NEXT: vcx3a p1, d1, d11, d11, #7 @ encoding: [0xbb,0xfd,0x1b,0x11]
+vcx3a p1, d1, d11, d11, #7
+// CHECK-MVE-NEXT: vcx3 p0, q0, q2, q0, #12 @ encoding: [0xa4,0xed,0x40,0x00]
+vcx3 p0, q0, q2, q0, #12
+// CHECK-MVE-NEXT: vcx3a p1, q3, q7, q6, #15 @ encoding: [0xbe,0xfd,0x5c,0x61]
+vcx3a p1, q3, q7, q6, #15
+
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: operand must be an immediate in the range [0,7]
+vcx3a p1, d1, d11, d12, #8
+// ERROR-MVE: [[@LINE+2]]:{{[0-9]+}}: error: operand must be an immediate in the range [0,15]
+// ERROR-FP: error: invalid instruction
+vcx3a p1, q1, q2, q3, #16
+// ERROR-MVE: [[@LINE+2]]:{{[0-9]+}}: error: invalid instruction
+// ERROR-FP: [[@LINE+1]]:{{[0-9]+}}: error: operand must be a register in range [d0, d15]
+vcx3 p0, d0, q0, d7, #1
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: operand must be a register in range [s0, s31]
+vcx3a p1, s0, s1, d3, #2
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx3a p0, s0, d0, q0, #2
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx3 p0, s0, s0, s31, s0, #1
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx3a p1, d1, d3, d22, d22, #7
diff --git a/llvm/test/MC/ARM/cde-integer.s b/llvm/test/MC/ARM/cde-integer.s
new file mode 100644
index 000000000000..54c0598e6254
--- /dev/null
+++ b/llvm/test/MC/ARM/cde-integer.s
@@ -0,0 +1,219 @@
+// RUN: not llvm-mc -triple=thumbv8m.main -mattr=+cdecp0 -mattr=+cdecp1 -show-encoding < %s 2>%t | FileCheck %s
+// RUN: FileCheck <%t --check-prefix=ERROR %s
+
+// CHECK-LABEL: test_gcp
+test_gcp:
+// CHECK-NEXT: mrc p3, #1, r3, c15, c15, #5 @ encoding: [0x3f,0xee,0xbf,0x33]
+mrc p3, #1, r3, c15, c15, #5
+// CHECK-NEXT: mcr2 p3, #2, r2, c7, c11, #7 @ encoding: [0x47,0xfe,0xfb,0x23]
+mcr2 p3, #2, r2, c7, c11, #7
+
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: coprocessor must be configured as GCP
+mrc p0, #1, r2, c3, c4, #5
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: coprocessor must be configured as GCP
+ldc2 p1, c8, [r1, #4]
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: coprocessor must be configured as GCP
+ldc2 p0, c7, [r2]
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: coprocessor must be configured as GCP
+ldc2 p1, c6, [r3, #-224]
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: coprocessor must be configured as GCP
+ldc2 p0, c5, [r4, #-120]!
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: coprocessor must be configured as GCP
+ldc2l p1, c2, [r7, #4]
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: coprocessor must be configured as GCP
+ldc2l p0, c1, [r8]
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: coprocessor must be configured as GCP
+ldc2l p1, c0, [r9, #-224]
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: coprocessor must be configured as GCP
+ldc2l p0, c1, [r10, #-120]!
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: coprocessor must be configured as GCP
+stc2 p1, c8, [r1, #4]
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: coprocessor must be configured as GCP
+stc2 p0, c7, [r2]
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: coprocessor must be configured as GCP
+stc2 p1, c6, [r3, #-224]
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: coprocessor must be configured as GCP
+stc2 p0, c5, [r4, #-120]!
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: coprocessor must be configured as GCP
+stc2l p1, c2, [r7, #4]
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: coprocessor must be configured as GCP
+stc2l p0, c1, [r8]
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: coprocessor must be configured as GCP
+stc2l p1, c0, [r9, #-224]
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: coprocessor must be configured as GCP
+stc2l p0, c1, [r10, #-120]!
+
+// CHECK-LABEL: test_predication1:
+test_predication1:
+ittt eq
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: instructions in IT block must be predicable
+cx1 p0, r3, #8191
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: instructions in IT block must be predicable
+cx2 p0, r2, r3, #123
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: instructions in IT block must be predicable
+cx3 p0, r1, r5, r7, #63
+nop
+nop
+nop
+ittt eq
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: instructions in IT block must be predicable
+cx1d p0, r0, r1, #8191
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: instructions in IT block must be predicable
+cx2d p0, r0, r1, r3, #123
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: instructions in IT block must be predicable
+cx3d p0, r0, r1, r5, r7, #63
+nop
+nop
+nop
+
+// CHECK-LABEL: test_predication2:
+test_predication2:
+// CHECK: itte eq @ encoding: [0x06,0xbf]
+itte eq
+// CHECK-NEXT: cx1aeq p0, r3, #8191 @ encoding: [0x3f,0xfe,0xbf,0x30]
+cx1aeq p0, r3, #8191
+// CHECK-NEXT: cx2aeq p0, r2, r3, #123 @ encoding: [0x43,0xfe,0xbb,0x20]
+cx2aeq p0, r2, r3, #123
+// CHECK-NEXT: cx3ane p0, r1, r5, r7, #63 @ encoding: [0xf5,0xfe,0xb1,0x70]
+cx3ane p0, r1, r5, r7, #63
+// CHECK-NEXT: itte eq @ encoding: [0x06,0xbf]
+itte eq
+// CHECK-NEXT: cx1daeq p0, r0, r1, #8191 @ encoding: [0x3f,0xfe,0xff,0x00]
+cx1daeq p0, r0, r1, #8191
+// CHECK-NEXT: cx2daeq p0, r0, r1, r3, #123 @ encoding: [0x43,0xfe,0xfb,0x00]
+cx2daeq p0, r0, r1, r3, #123
+// CHECK-NEXT: cx3dane p0, r0, r1, r5, r7, #63 @ encoding: [0xf5,0xfe,0xf0,0x70]
+cx3dane p0, r0, r1, r5, r7, #63
+
+
+// CHECK-LABEL: test_cx1:
+test_cx1:
+// CHECK-NEXT: cx1 p0, r3, #8191 @ encoding: [0x3f,0xee,0xbf,0x30]
+cx1 p0, r3, #8191
+// CHECK-NEXT: cx1a p1, r2, #0 @ encoding: [0x00,0xfe,0x00,0x21]
+cx1a p1, r2, #0
+// CHECK-NEXT: cx1d p0, r4, r5, #1234 @ encoding: [0x09,0xee,0xd2,0x40]
+cx1d p0, r4, r5, #1234
+// CHECK-NEXT: cx1da p1, r2, r3, #1234 @ encoding: [0x09,0xfe,0xd2,0x21]
+cx1da p1, r2, r3, #1234
+// CHECK-NEXT: cx1 p0, apsr_nzcv, #8191 @ encoding: [0x3f,0xee,0xbf,0xf0]
+cx1 p0, apsr_nzcv, #8191
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: coprocessor must be in the range [p0, p7]
+cx1 p8, r1, #1234
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: coprocessor must be configured as CDE
+cx1 p2, r0, #1
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: operand must be an immediate in the range [0,8191]
+cx1 p0, r1, #8192
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: operand must be a register in the range [r0, r12], r14 or apsr_nzcv
+cx1 p0, r13, #1234
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: operand must be a consecutive register
+cx1d p1, r0, #1234, #123
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: operand must be an even-numbered register in the range [r0, r10]
+cx1d p1, r1, #1234
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: operand must be a consecutive register
+cx1d p1, r2, r4, #1234
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: operand must be an even-numbered register in the range [r0, r10]
+cx1da p0, r1, #1234
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+cx1 p0, r0, r0, #1234
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+cx1d p0, r0, r1, r2, #1234
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+cx1a p0, r0, r2, #1234
+
+// CHECK-LABEL: test_cx2:
+test_cx2:
+// CHECK-NEXT: cx2 p0, r3, r7, #0 @ encoding: [0x47,0xee,0x00,0x30]
+cx2 p0, r3, r7, #0
+// CHECK-NEXT: cx2a p0, r1, r4, #511 @ encoding: [0x74,0xfe,0xbf,0x10]
+cx2a p0, r1, r4, #511
+// CHECK-NEXT: cx2d p0, r2, r3, r1, #123 @ encoding: [0x41,0xee,0xfb,0x20]
+cx2d p0, r2, r3, r1, #123
+// CHECK-NEXT: cx2da p0, r2, r3, r7, #123 @ encoding: [0x47,0xfe,0xfb,0x20]
+cx2da p0, r2, r3, r7, #123
+// CHECK-NEXT: cx2da p1, r10, r11, apsr_nzcv, #123 @ encoding: [0x4f,0xfe,0xfb,0xa1]
+cx2da p1, r10, r11, apsr_nzcv, #123
+
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: operand must be an immediate in the range [0,511]
+cx2 p0, r1, r4, #512
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: operand must be an even-numbered register in the range [r0, r10]
+cx2d p0, r12, r7, #123
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: operand must be an even-numbered register in the range [r0, r10]
+cx2da p0, r7, r7, #123
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: operand must be an even-numbered register in the range [r0, r10]
+cx2da p1, apsr_nzcv, r7, #123
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+cx2 p0, r0, r0, r7, #1
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: operand must be a consecutive register
+cx2d p0, r0, r0, r7, #1
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+cx2a p0, r0, r2, r7, #1
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: operand must be a consecutive register
+cx2da p0, r0, r2, r7, #1
+
+// CHECK-LABEL: test_cx3:
+test_cx3:
+// CHECK-NEXT: cx3 p0, r1, r2, r3, #0 @ encoding: [0x82,0xee,0x01,0x30]
+cx3 p0, r1, r2, r3, #0
+// CHECK-NEXT: cx3a p0, r1, r5, r7, #63 @ encoding: [0xf5,0xfe,0xb1,0x70]
+cx3a p0, r1, r5, r7, #63
+// CHECK-NEXT: cx3d p1, r0, r1, r7, r1, #12 @ encoding: [0x97,0xee,0xc0,0x11]
+cx3d p1, r0, r1, r7, r1, #12
+// CHECK-NEXT: cx3da p0, r8, r9, r2, r3, #12 @ encoding: [0x92,0xfe,0xc8,0x30]
+cx3da p0, r8, r9, r2, r3, #12
+// CHECK-NEXT: cx3 p1, apsr_nzcv, r7, apsr_nzcv, #12 @ encoding: [0x97,0xee,0x8f,0xf1]
+cx3 p1, apsr_nzcv, r7, apsr_nzcv, #12
+// CHECK-NEXT: cx3d p0, r8, r9, apsr_nzcv, apsr_nzcv, #12 @ encoding: [0x9f,0xee,0xc8,0xf0]
+cx3d p0, r8, r9, apsr_nzcv, apsr_nzcv, #12
+
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: operand must be an immediate in the range [0,63]
+cx3 p0, r1, r5, r7, #64
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: operand must be an even-numbered register in the range [r0, r10]
+cx3da p1, r14, r2, r3, #12
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: operand must be a register in the range [r0, r12], r14 or apsr_nzcv
+cx3a p0, r15, r2, r3, #12
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+cx2 p0, r0, r0, r7, r3, #1
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: operand must be a consecutive register
+cx2d p0, r0, r0, r7, r3, #1
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+cx3a p0, r1, r2, r5, r7, #63
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: operand must be a consecutive register
+cx3da p0, r8, apsr_nzcv, r2, r3, #12
+
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx1 p0, s0, #0
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx1 p0, d0, #0
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx1 p0, q0, #0
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx1a p0, s0, #0
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx1a p0, d0, #0
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx1a p0, q0, #0
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx2 p0, s0, s1, #0
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx2 p0, d0, d1, #0
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx2 p0, q0, q1, #0
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx2a p0, s0, s1, #0
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx2a p0, d0, d1, #0
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx2 p0, q0, q1, #0
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx3 p0, s0, s1, s2, #0
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx3 p0, d0, d1, d2, #0
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx3 p0, q0, q1, q2, #0
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx3a p0, s0, s1, s2, #0
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx3a p0, d0, d1, d2, #0
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx3a p0, q0, q1, q2, #0
diff --git a/llvm/test/MC/ARM/cde-vec-pred.s b/llvm/test/MC/ARM/cde-vec-pred.s
new file mode 100644
index 000000000000..6274fafa1224
--- /dev/null
+++ b/llvm/test/MC/ARM/cde-vec-pred.s
@@ -0,0 +1,27 @@
+// RUN: not llvm-mc -triple=thumbv8.1m.main -mattr=+mve.fp -mattr=+cdecp0 -mattr=+cdecp1 -show-encoding < %s 2>%t | FileCheck %s
+// RUN: FileCheck <%t --check-prefix=ERROR %s
+
+// CHECK: vptete.i8 eq, q0, q0 @ encoding: [0x41,0xfe,0x00,0xef]
+vptete.i8 eq, q0, q0
+// CHECK-NEXT: vcx1t p0, q1, #1234 @ encoding: [0x29,0xec,0xd2,0x20]
+vcx1t p0, q1, #1234
+// CHECK-NEXT: vcx1ae p1, q5, #4095 @ encoding: [0x2f,0xfd,0xff,0xa1]
+vcx1ae p1, q5, #4095
+// CHECK-NEXT: vcx2t p1, q0, q6, #123 @ encoding: [0x3e,0xed,0xdc,0x01]
+vcx2t p1, q0, q6, #123
+// CHECK-NEXT: vcx2ae p1, q3, q7, #127 @ encoding: [0x3f,0xfd,0xde,0x61]
+vcx2ae p1, q3, q7, #127
+// CHECK-NEXT: vpte.i8 eq, q0, q0 @ encoding: [0x41,0xfe,0x00,0x8f]
+vpte.i8 eq, q0, q0
+// CHECK-NEXT: vcx3at p1, q3, q7, q6, #15 @ encoding: [0xbe,0xfd,0x5c,0x61]
+vcx3at p1, q3, q7, q6, #15
+// CHECK-NEXT: vcx3e p0, q0, q2, q0, #12 @ encoding: [0xa4,0xed,0x40,0x00]
+vcx3e p0, q0, q2, q0, #12
+
+vpt.i8 eq, q0, q0
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: incorrect predication in VPT block; got 'none', but expected 't'
+vcx1 p0, q1, #1234
+
+vpt.i8 eq, q0, q0
+// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction
+vcx3t p0, d0, d1, d7, #1
diff --git a/llvm/test/MC/Disassembler/ARM/cde-fp-vec.txt b/llvm/test/MC/Disassembler/ARM/cde-fp-vec.txt
new file mode 100644
index 000000000000..c8439eed485b
--- /dev/null
+++ b/llvm/test/MC/Disassembler/ARM/cde-fp-vec.txt
@@ -0,0 +1,79 @@
+# RUN: not llvm-mc -disassemble -triple=thumbv8m.main -mattr=+fp-armv8 -mattr=+cdecp0 -mattr=+cdecp1 < %s 2>%t | FileCheck %s
+# RUN: FileCheck <%t --check-prefixes=ERROR,ERROR-FP %s
+# RUN: not llvm-mc -disassemble -triple=thumbv8.1m.main -mattr=+mve -mattr=+cdecp0 -mattr=+cdecp1 < %s 2>%t | FileCheck --check-prefixes=CHECK,CHECK-MVE %s
+# RUN: FileCheck <%t --check-prefixes=ERROR,ERROR-MVE %s
+
+# GCP instructions
+
+# CHECK: mrc p3, #1, r3, c15, c15, #5
+[0x3f,0xee,0xbf,0x33]
+# CHECK-NEXT: mcr2 p3, #2, r2, c7, c11, #7
+[0x47,0xfe,0xfb,0x23]
+
+# VCX1
+
+# CHECK: vcx1 p0, s11, #1234
+[0x69,0xec,0x92,0x50]
+# CHECK-NEXT: vcx1a p1, s7, #2047
+[0x6f,0xfc,0xbf,0x31]
+# CHECK-NEXT: vcx1 p0, d0, #0
+[0x20,0xed,0x00,0x00]
+# CHECK-NEXT: vcx1a p1, d3, #2047
+[0x2f,0xfd,0xbf,0x31]
+# CHECK-MVE-NEXT: vcx1 p0, q1, #1234
+# ERROR-FP: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0x29,0xec,0xd2,0x20]
+# CHECK-MVE-NEXT: vcx1a p1, q5, #4095
+# ERROR-FP: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0x2f,0xfd,0xff,0xa1]
+
+# Vector variant, Vd<0> == 1
+# ERROR: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0x29,0xec,0xd2,0x30]
+
+# VCX2
+
+# CHECK: vcx2 p0, s0, s31, #12
+[0x33,0xec,0x2f,0x00]
+# CHECK-NEXT: vcx2a p0, s1, s1, #63
+[0x7f,0xfc,0xb0,0x00]
+# CHECK-NEXT: vcx2 p0, d0, d15, #0
+[0x30,0xed,0x0f,0x00]
+# CHECK-NEXT: vcx2a p0, d1, d11, #63
+[0x3f,0xfd,0x9b,0x10]
+# CHECK-MVE-NEXT: vcx2 p1, q0, q6, #123
+# ERROR-FP: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0x3e,0xed,0xdc,0x01]
+# CHECK-MVE-NEXT: vcx2a p1, q3, q7, #127
+# ERROR-FP: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0x3f,0xfd,0xde,0x61]
+
+# VCX2 Vector variant, Vm<0> == 1
+# ERROR-MVE: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0x3e,0xed,0xff,0x01]
+
+# vcx2 p1, q0, q15, #123
+# CHECK-MVE: vcx2 p1, q0, q7, #123
+# ERROR-MVE: [[@LINE+1]]:{{[0-9]+}}: warning: potentially undefined instruction encoding
+[0x3e,0xed,0xfe,0x01]
+
+# VCX3
+
+# CHECK: vcx3 p0, s0, s31, s0, #1
+[0x8f,0xec,0x90,0x00]
+# CHECK-NEXT: vcx3a p1, s1, s17, s11, #7
+[0xf8,0xfc,0xb5,0x01]
+# CHECK-NEXT: vcx3 p0, d0, d15, d7, #0
+[0x8f,0xed,0x07,0x00]
+# CHECK-NEXT: vcx3a p1, d1, d11, d11, #7
+[0xbb,0xfd,0x1b,0x11]
+# CHECK-MVE-NEXT: vcx3 p0, q0, q2, q0, #12
+# ERROR-FP: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0xa4,0xed,0x40,0x00]
+# CHECK-MVE-NEXT: vcx3a p1, q3, q7, q6, #15
+# ERROR-FP: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0xbe,0xfd,0x5c,0x61]
+
+# Vector variant, Vn<0> == 1
+# ERROR: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0xbf,0xfd,0x7e,0x61]
diff --git a/llvm/test/MC/Disassembler/ARM/cde-integer.txt b/llvm/test/MC/Disassembler/ARM/cde-integer.txt
new file mode 100644
index 000000000000..bf6022afa30d
--- /dev/null
+++ b/llvm/test/MC/Disassembler/ARM/cde-integer.txt
@@ -0,0 +1,137 @@
+# RUN: not llvm-mc -disassemble -triple=thumbv8m.main -mattr=+cdecp0 -mattr=+cdecp1 < %s 2>%t | FileCheck %s
+# RUN: FileCheck <%t --check-prefix=ERROR %s
+
+# GCP instructions
+
+# CHECK: mrc p3, #1, r3, c15, c15, #5
+[0x3f,0xee,0xbf,0x33]
+# CHECK-NEXT: mcr2 p3, #2, r2, c7, c11, #7
+[0x47,0xfe,0xfb,0x23]
+
+# Predication
+
+# CHECK: itte eq
+[0x06,0xbf]
+itte eq
+# CHECK-NEXT: cx1aeq p0, r3, #8191
+[0x3f,0xfe,0xbf,0x30]
+# CHECK-NEXT: cx2aeq p0, r2, r3, #123
+[0x43,0xfe,0xbb,0x20]
+# CHECK-NEXT: cx3ane p0, r1, r5, r7, #63
+[0xf5,0xfe,0xb1,0x70]
+# CHECK-NEXT: itte eq
+[0x06,0xbf]
+# CHECK-NEXT: cx1daeq p0, r0, r1, #8191
+[0x3f,0xfe,0xff,0x00]
+# CHECK-NEXT: cx2daeq p0, r0, r1, r3, #123
+[0x43,0xfe,0xfb,0x00]
+# CHECK-NEXT: cx3dane p0, r0, r1, r5, r7, #63
+[0xf5,0xfe,0xf0,0x70]
+
+# CX1
+
+# CHECK-NEXT: cx1 p0, r3, #8191
+[0x3f,0xee,0xbf,0x30]
+# CHECK-NEXT: cx1a p1, r2, #0
+[0x00,0xfe,0x00,0x21]
+# CHECK-NEXT: cx1d p0, r4, r5, #1234
+[0x09,0xee,0xd2,0x40]
+# CHECK-NEXT: cx1da p1, r2, r3, #1234
+[0x09,0xfe,0xd2,0x21]
+# CHECK-NEXT: cx1 p0, apsr_nzcv, #8191
+[0x3f,0xee,0xbf,0xf0]
+
+# ERROR: [[@LINE+2]]:{{[0-9]+}}: warning: potentially undefined instruction encoding
+# CHECK-NEXT: cx1 p0, sp, #8191
+[0x3f,0xee,0xbf,0xd0]
+# ERROR: [[@LINE+2]]:{{[0-9]+}}: warning: potentially undefined instruction encoding
+# CHECK-NEXT: cx1d p0, r12, sp, #1234
+[0x09,0xee,0xd2,0xc0]
+# ERROR: [[@LINE+2]]:{{[0-9]+}}: warning: potentially undefined instruction encoding
+# CHECK-NEXT: cx1d p0, r2, r3, #1234
+[0x09,0xee,0xd2,0x30]
+
+# CX2
+
+# CHECK-NEXT: cx2 p0, r3, r7, #0
+[0x47,0xee,0x00,0x30]
+# CHECK-NEXT: cx2a p0, r1, r4, #511
+[0x74,0xfe,0xbf,0x10]
+# CHECK-NEXT: cx2d p0, r2, r3, r1, #123
+[0x41,0xee,0xfb,0x20]
+# CHECK-NEXT: cx2da p0, r2, r3, r7, #123
+[0x47,0xfe,0xfb,0x20]
+# CHECK-NEXT: cx2da p1, r10, r11, apsr_nzcv, #123
+[0x4f,0xfe,0xfb,0xa1]
+
+# ERROR: [[@LINE+2]]:{{[0-9]+}}: warning: potentially undefined instruction encoding
+# CHECK-NEXT: cx2a p0, r1, sp, #511
+[0x7d,0xfe,0xbf,0x10]
+# ERROR: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0x4f,0xfe,0xfb,0xe1]
+
+# CX3
+
+# CHECK-NEXT: cx3 p0, r1, r2, r3, #0
+[0x82,0xee,0x01,0x30]
+# CHECK-NEXT: cx3a p0, r1, r5, r7, #63
+[0xf5,0xfe,0xb1,0x70]
+# CHECK-NEXT: cx3d p1, r0, r1, r7, r1, #12
+[0x97,0xee,0xc0,0x11]
+# CHECK-NEXT: cx3da p0, r8, r9, r2, r3, #12
+[0x92,0xfe,0xc8,0x30]
+# CHECK-NEXT: cx3 p1, apsr_nzcv, r7, apsr_nzcv, #12
+[0x97,0xee,0x8f,0xf1]
+# CHECK-NEXT: cx3d p0, r8, r9, apsr_nzcv, apsr_nzcv, #12
+[0x9f,0xee,0xc8,0xf0]
+
+# ERROR: [[@LINE+2]]:{{[0-9]+}}: warning: potentially undefined instruction encoding
+# CHECK-NEXT: cx3 p0, r1, r2, sp, #0
+[0x82,0xee,0x01,0xd0]
+# ERROR: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0x9f,0xee,0xce,0xf0]
+
+# VCX1
+
+# ERROR: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0x69,0xec,0x92,0x50]
+# ERROR: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0x6f,0xfc,0xbf,0x31]
+# ERROR: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0x20,0xed,0x00,0x00]
+# ERROR: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0x2f,0xfd,0xbf,0x31]
+# ERROR: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0x29,0xec,0xd2,0x20]
+# ERROR: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0x2f,0xfd,0xff,0xa1]
+
+# VCX2
+
+# ERROR: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0x33,0xec,0x2f,0x00]
+# ERROR: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0x7f,0xfc,0xb0,0x00]
+# ERROR: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0x30,0xed,0x2f,0x00]
+# ERROR: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0x3f,0xfd,0xb6,0x10]
+# ERROR: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0x3e,0xed,0xfe,0x01]
+# ERROR: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0x3f,0xfd,0xde,0x61]
+
+# VCX3
+
+# ERROR: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0x8f,0xec,0x90,0x00]
+# ERROR: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0xf8,0xfc,0xb5,0x01]
+# ERROR: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0x8f,0xed,0x87,0x00]
+# ERROR: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0xb6,0xfd,0xb6,0x11]
+# ERROR: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0xae,0xed,0xc0,0x00]
+# ERROR: [[@LINE+1]]:{{[0-9]+}}: warning: invalid instruction encoding
+[0xbe,0xfd,0x7e,0x61]
diff --git a/llvm/test/MC/Disassembler/ARM/cde-vec-pred.txt b/llvm/test/MC/Disassembler/ARM/cde-vec-pred.txt
new file mode 100644
index 000000000000..eab4b1b1ed0a
--- /dev/null
+++ b/llvm/test/MC/Disassembler/ARM/cde-vec-pred.txt
@@ -0,0 +1,19 @@
+# RUN: llvm-mc -disassemble -triple=thumbv8m.main -mattr=+mve -mattr=+cdecp0 -mattr=+cdecp1 < %s | FileCheck %s
+
+# CHECK: vptete.i8 eq, q0, q0
+[0x41,0xfe,0x00,0xef]
+# CHECK-NEXT: vcx1t p0, q1, #1234
+[0x29,0xec,0xd2,0x20]
+# CHECK-NEXT: vcx1ae p1, q5, #4095
+[0x2f,0xfd,0xff,0xa1]
+# CHECK-NEXT: vcx2t p1, q0, q6, #123
+[0x3e,0xed,0xdc,0x01]
+# CHECK-NEXT: vcx2ae p1, q3, q7, #127
+[0x3f,0xfd,0xde,0x61]
+
+# CHECK-NEXT: vpte.i8 eq, q0, q0
+[0x41,0xfe,0x00,0x8f]
+# CHECK-NEXT: vcx3at p1, q3, q7, q6, #15
+[0xbe,0xfd,0x5c,0x61]
+# CHECK-NEXT: vcx3e p0, q0, q2, q0, #12
+[0xa4,0xed,0x40,0x00]
More information about the cfe-commits
mailing list