Index: clang/test/Driver/arm-cde.c =================================================================== --- /dev/null +++ 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" Index: llvm/include/llvm/Support/ARMTargetParser.h =================================================================== --- llvm/include/llvm/Support/ARMTargetParser.h +++ llvm/include/llvm/Support/ARMTargetParser.h @@ -46,6 +46,15 @@ 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, Index: llvm/include/llvm/Support/ARMTargetParser.def =================================================================== --- llvm/include/llvm/Support/ARMTargetParser.def +++ llvm/include/llvm/Support/ARMTargetParser.def @@ -166,6 +166,14 @@ 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 Index: llvm/lib/Target/ARM/ARM.td =================================================================== --- llvm/lib/Target/ARM/ARM.td +++ llvm/lib/Target/ARM/ARM.td @@ -536,6 +536,16 @@ "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. // Index: llvm/lib/Target/ARM/ARMInstrCDE.td =================================================================== --- /dev/null +++ llvm/lib/Target/ARM/ARMInstrCDE.td @@ -0,0 +1,456 @@ +// Immediate operand of arbitrary bit width +class BitWidthImmOperand + : ImmAsmOperand<0, !add(!shl(1, width), -1)> { + let Name = "Imm"#width#"b"; +} + +class BitWidthImm + : Operand, + ImmLeaf= 0 && Imm < (1 << "#width#"); }"> { + let ParserMatchClass = BitWidthImmOperand; +} + +def CDEDualRegOp : RegisterOperand; + +// 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 + : Thumb2XI, + 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 + : CDE_Instr, + Requires<[HasCDE]> { + + let Inst{25-24} = 0b10; + let Inst{6} = dual; +} + +// Set of registers used by the CDE instructions. +class CDE_RegisterOperands { + dag Rd; + dag Rd_src; + dag Rn; + dag Rm; +} + +// Base class for CDE instruction parameter set. +class CDE_Params { + dag Oops; // Output operands for {V}CX* instructions + dag Iops1; // Input operands for {V}CX1* instructions + dag Iops2; // Input operands for {V}CX2* instructions + dag Iops3; // Input operands for {V}CX3* instructions + string Cstr; // asm constraint string + bit Dual; // "dual" field for encoding (not used in VCX*) + bit Acc; // "acc" field for encoding +} + +// CX1, CX1A, CX1D, CX1DA +class CDE_CX1_Instr + : CDE_GPR_Instr { + 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 + : CDE_GPR_Instr { + 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 + : CDE_GPR_Instr { + 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 + : CDE_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 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 + : CDE_Instr { + let Inst{25} = 0b0; + let Inst{6} = vec; +} + +// Base class for floating-point variants of CDE VCX* intructions +class CDE_FP_Instr + : 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 + : CDE_FP_Vec_Instr<0b1, acc, oops, iops, asm, cstr>, + CDE_RequiresQReg; + + +// VCX1/VCX1A, vector variant +class CDE_VCX1_Vec_Instr + : CDE_Vec_Instr { + bits<12> imm; + bits<3> Vd; + + 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} = Vd{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 + : CDE_FP_Instr { + 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 + : 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 + : 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 + : CDE_Vec_Instr { + bits<7> imm; + bits<3> Vd; + bits<3> Vm; + + 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} = Vd{2-0}; + let Inst{12} = 0b0; + let Inst{7} = imm{1}; + let Inst{5} = 0b0; + let Inst{4} = imm{0}; + let Inst{3-1} = Vm{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 + : CDE_FP_Instr { + 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 + : 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 + : 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 + : CDE_Vec_Instr { + bits<4> imm; + bits<3> Vd; + bits<3> Vm; + bits<3> Vn; + + let Inst{24} = imm{3}; + let Inst{23} = 0b1; + let Inst{22} = 0b0; + let Inst{21-20} = imm{2-1}; + let Inst{19-17} = Vn{2-0}; + let Inst{16} = 0b0; + let Inst{15-13} = Vd{2-0}; + let Inst{12} = 0b0; + let Inst{7} = 0b0; + let Inst{5} = 0b0; + let Inst{4} = imm{0}; + let Inst{3-1} = Vm{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 + : CDE_FP_Instr { + 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 + : 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 + : 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 + : CDE_RegisterOperands { + let Rd = (outs regclass:$Vd); + let Rd_src = (ins regclass:$Vd_src); + let Rn = (ins regclass:$Vn); + let Rm = (ins regclass:$Vm); +} + +def cde_vcx_s_regs : CDE_VCX_RegisterOperandsTemplate; +def cde_vcx_d_regs : CDE_VCX_RegisterOperandsTemplate; +def cde_vcx_q_regs : CDE_VCX_RegisterOperandsTemplate; + +class CDE_VCX_ParamsTemplate + : CDE_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; +} + +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_VCX_ParamsTemplate<0b0, cde_vcx_q_regs>; +def cde_vcx_params_q_acc : CDE_VCX_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>; Index: llvm/lib/Target/ARM/ARMInstrInfo.td =================================================================== --- llvm/lib/Target/ARM/ARMInstrInfo.td +++ llvm/lib/Target/ARM/ARMInstrInfo.td @@ -6007,6 +6007,12 @@ include "ARMInstrMVE.td" //===----------------------------------------------------------------------===// +// CDE (Custom Datapath Extension) +// + +include "ARMInstrCDE.td" + +//===----------------------------------------------------------------------===// // Assembler aliases // Index: llvm/lib/Target/ARM/ARMPredicates.td =================================================================== --- llvm/lib/Target/ARM/ARMPredicates.td +++ llvm/lib/Target/ARM/ARMPredicates.td @@ -35,6 +35,9 @@ 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">; Index: llvm/lib/Target/ARM/ARMRegisterInfo.td =================================================================== --- llvm/lib/Target/ARM/ARMRegisterInfo.td +++ llvm/lib/Target/ARM/ARMRegisterInfo.td @@ -305,6 +305,17 @@ 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)> { Index: llvm/lib/Target/ARM/ARMSubtarget.h =================================================================== --- llvm/lib/Target/ARM/ARMSubtarget.h +++ llvm/lib/Target/ARM/ARMSubtarget.h @@ -162,6 +162,7 @@ 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 @@ void initSubtargetFeatures(StringRef CPU, StringRef FS); ARMFrameLowering *initializeFrameLowering(StringRef CPU, StringRef FS); + std::bitset<8> CoprocCDE = {}; public: void computeIssueWidth(); @@ -584,6 +586,7 @@ 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; } Index: llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp =================================================================== --- llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ 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,42 @@ } }; +// Various sets of ARM instruction mnemonics which are used by the asm parser +class ARMMnemonicSets { + StringSet<> CDE; +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); + } + + /// 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", "vcx1", "vcx1a", + "cx2", "cx2a", "cx2d", "cx2da", "vcx2", "vcx2a", + "cx3", "cx3a", "cx3d", "cx3da", "vcx3", "vcx3a" }) + CDE.insert(Mnemonic); +} class ARMAsmParser : public MCTargetAsmParser { const MCRegisterInfo *MRI; UnwindContext UC; + ARMMnemonicSets MS; ARMTargetStreamer &getTargetStreamer() { assert(getParser().getStreamer().getTargetStreamer() && @@ -444,6 +477,8 @@ 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 +536,9 @@ 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 +643,7 @@ 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. @@ -6380,6 +6418,7 @@ Mnemonic == "csinc" || Mnemonic == "csinv" || Mnemonic == "csneg" || Mnemonic == "cinc" || Mnemonic == "cinv" || Mnemonic == "cneg" || Mnemonic == "cset" || Mnemonic == "csetm" || + (hasCDE() && MS.isCDEInstr(Mnemonic)) || Mnemonic.startswith("vpt") || Mnemonic.startswith("vpst") || (hasMVE() && (Mnemonic.startswith("vst2") || Mnemonic.startswith("vld2") || @@ -6770,6 +6809,65 @@ ARMOperand::CreateReg(PairedReg, Op2.getStartLoc(), Op2.getEndLoc())); } +// Dual-register instruction have the following syntax: +// , , , , ..., #imm +// This function tries to remove and replace 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)); + + if (Operands.size() <= 3) + return false; + + StringRef Op2Diag( + "operand must be an even-numbered register in the range [r0, r10]"); + + const MCParsedAsmOperand &Op2 = *Operands[2]; + 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]; + if (!Op3.isReg() || Op3.getReg() != RNext) + return Error(Op3.getStartLoc(), "operand must be a consecutive register"); + + Operands.erase(Operands.begin() + 3); + Operands[2] = 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) { @@ -6969,6 +7067,21 @@ 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 @@ -7947,6 +8060,54 @@ return Error (Operands[3]->getStartLoc(), "Q-register indexes must be 2 and 0 or 3 and 1"); 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; Index: llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp =================================================================== --- llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp +++ llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp @@ -182,6 +182,9 @@ 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 @@ 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,12 +1088,22 @@ } } - Result = - decodeInstruction(DecoderTableThumb2CoProc32, MI, Insn32, Address, this, STI); - if (Result != MCDisassembler::Fail) { - Size = 4; - Check(Result, AddThumbPredicate(MI)); - return Result; + uint32_t Coproc = fieldFromInstruction(Insn32, 8, 4); + if (ARM::isCDECoproc(Coproc, STI)) { + Result = + decodeInstruction(DecoderTableThumb2CDE32, MI, Insn32, Address, this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; + } + } else { + Result = + decodeInstruction(DecoderTableThumb2CoProc32, MI, Insn32, Address, this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + Check(Result, AddThumbPredicate(MI)); + return Result; + } } Size = 0; @@ -1227,6 +1242,19 @@ 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 +6092,23 @@ 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; Index: llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.h =================================================================== --- llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.h +++ llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.h @@ -107,6 +107,9 @@ inline bool isVpred(uint8_t op) { return isVpred(static_cast(op)); } + +bool isCDECoproc(size_t Coproc, const MCSubtargetInfo &STI); + } // end namespace ARM } // End llvm namespace Index: llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp =================================================================== --- llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp +++ llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp @@ -321,6 +321,14 @@ 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(), Index: llvm/test/MC/ARM/cde-fp-vec.s =================================================================== --- /dev/null +++ llvm/test/MC/ARM/cde-fp-vec.s @@ -0,0 +1,137 @@ +// 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: instruction requires: mve +// 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: instruction requires: mve +vcx1a p1, q5, #4095 + +// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: invalid instruction +vcx1a p1, s7, s7, #2047 +// ERROR-FP: [[@LINE+4]]:{{[0-9]+}}: error: operand must be an immediate in the range [0,2047] +// ERROR-MVE: [[@LINE+3]]:{{[0-9]+}}: error: invalid instruction, any one of the following would fix this: +// ERROR-MVE: [[@LINE+2]]:{{[0-9]+}}: note: operand must be an immediate in the range [0,2047] +// ERROR-MVE: [[@LINE+1]]:{{[0-9]+}}: note: operand must be a register in range [q0, q7] +vcx1 p0, d0, #2048 +// ERROR-FP: [[@LINE+4]]:{{[0-9]+}}: error: operand must be an immediate in the range [0,2047] +// ERROR-MVE: [[@LINE+3]]:{{[0-9]+}}: error: invalid instruction, any one of the following would fix this: +// ERROR-MVE: [[@LINE+2]]:{{[0-9]+}}: note: operand must be an immediate in the range [0,2047] +// ERROR-MVE: [[@LINE+1]]:{{[0-9]+}}: note: operand must be a register in range [q0, q7] +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+7]]:{{[0-9]+}}: error: invalid instruction, any one of the following would fix this: +// ERROR-FP: [[@LINE+6]]:{{[0-9]+}}: note: operand must be a register in range [s0, s31] +// ERROR-FP: [[@LINE+5]]:{{[0-9]+}}: note: operand must be a register in range [d0, d15] +// ERROR-MVE: [[@LINE+4]]:{{[0-9]+}}: error: invalid instruction, any one of the following would fix this: +// ERROR-MVE: [[@LINE+3]]:{{[0-9]+}}: note: operand must be a register in range [s0, s31] +// ERROR-MVE: [[@LINE+2]]:{{[0-9]+}}: note: operand must be a register in range [d0, d15] +// ERROR-MVE: [[@LINE+1]]:{{[0-9]+}}: note: 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: [[@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 Index: llvm/test/MC/ARM/cde-integer.s =================================================================== --- /dev/null +++ llvm/test/MC/ARM/cde-integer.s @@ -0,0 +1,189 @@ +// 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_predication: +test_predication: +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 +cx2da p0, r2, r3, r1, #123 +// ERROR: [[@LINE+1]]:{{[0-9]+}}: error: instructions in IT block must be predicable +cx3a p0, r1, r5, r7, #63 +nop +nop +nop + +// 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 Index: llvm/test/MC/Disassembler/ARM/cde-fp-vec.txt =================================================================== --- /dev/null +++ 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] Index: llvm/test/MC/Disassembler/ARM/cde-integer.txt =================================================================== --- /dev/null +++ llvm/test/MC/Disassembler/ARM/cde-integer.txt @@ -0,0 +1,117 @@ +# 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] + +# 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]