[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
This commit is contained in:
Mikhail Maltsev 2020-02-17 15:37:49 +00:00
parent 5fdc9851d0
commit dd4d093762
19 changed files with 1432 additions and 2 deletions

View File

@ -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"

View File

@ -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

View File

@ -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,

View File

@ -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.
//

View File

@ -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>;

View File

@ -5994,6 +5994,12 @@ include "ARMInstrNEON.td"
include "ARMInstrMVE.td"
//===----------------------------------------------------------------------===//
// CDE (Custom Datapath Extension)
//
include "ARMInstrCDE.td"
//===----------------------------------------------------------------------===//
// Assembler aliases
//

View File

@ -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">;

View File

@ -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)> {

View File

@ -162,6 +162,7 @@ protected:
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 @@ private:
void initSubtargetFeatures(StringRef CPU, StringRef FS);
ARMFrameLowering *initializeFrameLowering(StringRef CPU, StringRef FS);
std::bitset<8> CoprocCDE = {};
public:
void computeIssueWidth();
@ -584,6 +586,7 @@ public:
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; }

View File

@ -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 @@ public:
}
};
// 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 @@ public:
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"));

View File

@ -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;

View File

@ -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(),

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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]

View File

@ -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]

View File

@ -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]