forked from OSchip/llvm-project
[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:
parent
5fdc9851d0
commit
dd4d093762
|
@ -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"
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
//
|
||||
|
|
|
@ -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>;
|
|
@ -5994,6 +5994,12 @@ include "ARMInstrNEON.td"
|
|||
|
||||
include "ARMInstrMVE.td"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CDE (Custom Datapath Extension)
|
||||
//
|
||||
|
||||
include "ARMInstrCDE.td"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Assembler aliases
|
||||
//
|
||||
|
|
|
@ -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">;
|
||||
|
|
|
@ -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)> {
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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]
|
|
@ -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]
|
|
@ -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]
|
Loading…
Reference in New Issue