[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