diff --git a/llvm/lib/Target/ARM/ARMInstrInfo.td b/llvm/lib/Target/ARM/ARMInstrInfo.td --- a/llvm/lib/Target/ARM/ARMInstrInfo.td +++ b/llvm/lib/Target/ARM/ARMInstrInfo.td @@ -461,6 +461,28 @@ let ParserMatchClass = RotImmAsmOperand; } +// vcmla_rot_imm: An integer that encodes a rotate amount. Must be 0, 90, 180, 270. +def VCMLARotImmAsmOperand : AsmOperandClass { + let Name = "VCMLARotImm"; + let RenderMethod = "addImmOperands"; +} +def vcmla_rot_imm : Operand { + let EncoderMethod = "getVCMLARotOpValue"; + let DecoderMethod = "DecodeVCMLARotOperand"; + let ParserMatchClass = VCMLARotImmAsmOperand; +} + +// vcadd_rot_imm: An integer that encodes a rotate amount. Must be 90, 180. +def VCADDRotImmAsmOperand : AsmOperandClass { + let Name = "VCADDRotImm"; + let RenderMethod = "addImmOperands"; +} +def vcadd_rot_imm : Operand { + let EncoderMethod = "getVCADDRotOpValue"; + let DecoderMethod = "DecodeVCADDRotOperand"; + let ParserMatchClass = VCADDRotImmAsmOperand; +} + // Vector indexing class MVEVectorIndexOperand : AsmOperandClass { let Name = "MVEVectorIndex"#NumLanes; diff --git a/llvm/lib/Target/ARM/ARMInstrMVE.td b/llvm/lib/Target/ARM/ARMInstrMVE.td --- a/llvm/lib/Target/ARM/ARMInstrMVE.td +++ b/llvm/lib/Target/ARM/ARMInstrMVE.td @@ -142,6 +142,13 @@ let Inst{27-26} = 0b11; } +class MVE_f pattern=[]> + : MVE_p { + let Predicates = [HasMVEFloat]; +} + class MVE_MI_with_pred pattern> : Thumb2I pattern=[]> + : MVE_f { + bits<4> Qm; + + let Inst{12} = 0b0; + let Inst{6} = 0b1; + let Inst{5} = Qm{3}; + let Inst{3-1} = Qm{2-0}; + let Inst{0} = 0b0; +} + +class MVE_VRINT op, string suffix, bits<2> size, + list pattern=[]> + : MVE_float { + bits<4> Qd; + + let Inst{28} = 0b1; + let Inst{25-23} = 0b111; + let Inst{22} = Qd{3}; + let Inst{21-20} = 0b11; + let Inst{19-18} = size; + let Inst{17-16} = 0b10; + let Inst{15-13} = Qd{2-0}; + let Inst{11-10} = 0b01; + let Inst{9-7} = op{2-0}; + let Inst{4} = 0b0; + +} + +multiclass MVE_VRINT_ops size, list pattern=[]> { + def N : MVE_VRINT<"n", 0b000, suffix, size, pattern>; + def X : MVE_VRINT<"x", 0b001, suffix, size, pattern>; + def A : MVE_VRINT<"a", 0b010, suffix, size, pattern>; + def Z : MVE_VRINT<"z", 0b011, suffix, size, pattern>; + def M : MVE_VRINT<"m", 0b101, suffix, size, pattern>; + def P : MVE_VRINT<"p", 0b111, suffix, size, pattern>; +} + +defm MVE_VRINTf16 : MVE_VRINT_ops<"f16", 0b01>; +defm MVE_VRINTf32 : MVE_VRINT_ops<"f32", 0b10>; + +class MVEFloatArithNeon pattern=[]> + : MVE_float { + let Inst{20} = size; + let Inst{16} = 0b0; +} + +class MVE_VMUL_fp pattern=[]> + : MVEFloatArithNeon<"vmul", suffix, size, (outs MQPR:$Qd), + (ins MQPR:$Qn, MQPR:$Qm), "$Qd, $Qn, $Qm", vpred_r, "", + pattern> { + bits<4> Qd; + bits<4> Qn; + + let Inst{28} = 0b1; + let Inst{25-23} = 0b110; + let Inst{22} = Qd{3}; + let Inst{21} = 0b0; + let Inst{19-17} = Qn{2-0}; + let Inst{15-13} = Qd{2-0}; + let Inst{12-8} = 0b01101; + let Inst{7} = Qn{3}; + let Inst{4} = 0b1; +} + +def MVE_VMULf32 : MVE_VMUL_fp<"f32", 0b0>; +def MVE_VMULf16 : MVE_VMUL_fp<"f16", 0b1>; + +class MVE_VCMLA pattern=[]> + : MVEFloatArithNeon<"vcmla", suffix, size, (outs MQPR:$Qd), + (ins MQPR:$Qd_src, MQPR:$Qn, MQPR:$Qm, vcmla_rot_imm:$rot), + "$Qd, $Qn, $Qm, $rot", vpred_n, "$Qd = $Qd_src", pattern> { + bits<4> Qd; + bits<4> Qn; + bits<2> rot; + + let Inst{28} = 0b1; + let Inst{25} = 0b0; + let Inst{24-23} = rot; + let Inst{22} = Qd{3}; + let Inst{21} = 0b1; + let Inst{19-17} = Qn{2-0}; + let Inst{15-13} = Qd{2-0}; + let Inst{12-8} = 0b01000; + let Inst{7} = Qn{3}; + let Inst{4} = 0b0; +} + +def MVE_VCMLAf16 : MVE_VCMLA<"f16", 0b0>; +def MVE_VCMLAf32 : MVE_VCMLA<"f32", 0b1>; + +class MVE_VADDSUBFMA_fp pattern=[]> + : MVEFloatArithNeon { + bits<4> Qd; + bits<4> Qn; + + let Inst{28} = 0b0; + let Inst{25-23} = 0b110; + let Inst{22} = Qd{3}; + let Inst{21} = bit_21; + let Inst{19-17} = Qn{2-0}; + let Inst{15-13} = Qd{2-0}; + let Inst{11-9} = 0b110; + let Inst{8} = bit_8; + let Inst{7} = Qn{3}; + let Inst{4} = bit_4; +} + +def MVE_VFMAf32 : MVE_VADDSUBFMA_fp<"vfma", "f32", 0b0, 0b1, 0b0, 0b0, + (ins MQPR:$Qd_src), vpred_n, "$Qd = $Qd_src">; +def MVE_VFMAf16 : MVE_VADDSUBFMA_fp<"vfma", "f16", 0b1, 0b1, 0b0, 0b0, + (ins MQPR:$Qd_src), vpred_n, "$Qd = $Qd_src">; + +def MVE_VFMSf32 : MVE_VADDSUBFMA_fp<"vfms", "f32", 0b0, 0b1, 0b0, 0b1, + (ins MQPR:$Qd_src), vpred_n, "$Qd = $Qd_src">; +def MVE_VFMSf16 : MVE_VADDSUBFMA_fp<"vfms", "f16", 0b1, 0b1, 0b0, 0b1, + (ins MQPR:$Qd_src), vpred_n, "$Qd = $Qd_src">; + +def MVE_VADDf32 : MVE_VADDSUBFMA_fp<"vadd", "f32", 0b0, 0b0, 0b1, 0b0>; +def MVE_VADDf16 : MVE_VADDSUBFMA_fp<"vadd", "f16", 0b1, 0b0, 0b1, 0b0>; + +def MVE_VSUBf32 : MVE_VADDSUBFMA_fp<"vsub", "f32", 0b0, 0b0, 0b1, 0b1>; +def MVE_VSUBf16 : MVE_VADDSUBFMA_fp<"vsub", "f16", 0b1, 0b0, 0b1, 0b1>; + +class MVE_VCADD pattern=[]> + : MVEFloatArithNeon<"vcadd", suffix, size, (outs MQPR:$Qd), + (ins MQPR:$Qn, MQPR:$Qm, vcadd_rot_imm:$rot), + "$Qd, $Qn, $Qm, $rot", vpred_r, "", pattern> { + bits<4> Qd; + bits<4> Qn; + bit rot; + + let Inst{28} = 0b1; + let Inst{25} = 0b0; + let Inst{24} = rot; + let Inst{23} = 0b1; + let Inst{22} = Qd{3}; + let Inst{21} = 0b0; + let Inst{19-17} = Qn{2-0}; + let Inst{15-13} = Qd{2-0}; + let Inst{12-8} = 0b01000; + let Inst{7} = Qn{3}; + let Inst{4} = 0b0; +} + +def MVE_VCADDf16 : MVE_VCADD<"f16", 0b0>; +def MVE_VCADDf32 : MVE_VCADD<"f32", 0b1>; + +class MVE_VABD_fp + : MVE_float<"vabd", suffix, (outs MQPR:$Qd), (ins MQPR:$Qn, MQPR:$Qm), + "$Qd, $Qn, $Qm", vpred_r, ""> { + bits<4> Qd; + bits<4> Qn; + + let Inst{28} = 0b1; + let Inst{25-23} = 0b110; + let Inst{22} = Qd{3}; + let Inst{21} = 0b1; + let Inst{20} = size; + let Inst{19-17} = Qn{2-0}; + let Inst{16} = 0b0; + let Inst{15-13} = Qd{2-0}; + let Inst{11-8} = 0b1101; + let Inst{7} = Qn{3}; + let Inst{4} = 0b0; +} + +def MVE_VABDf32 : MVE_VABD_fp<"f32", 0b0>; +def MVE_VABDf16 : MVE_VABD_fp<"f16", 0b1>; + +class MVE_VCVT_fix pattern=[]> + : MVE_float<"vcvt", suffix, (outs MQPR:$Qd), (ins MQPR:$Qm, + neon_vcvt_imm32:$imm6), "$Qd, $Qm, $imm6", vpred_r, "", pattern> { + bits<4> Qd; + bits<6> imm6; + + let Inst{28} = U; + let Inst{25-23} = 0b111; + let Inst{22} = Qd{3}; + let Inst{21} = 0b1; + let Inst{19-16} = imm6{3-0}; + let Inst{15-13} = Qd{2-0}; + let Inst{11-10} = 0b11; + let Inst{9} = fsi; + let Inst{8} = op; + let Inst{7} = 0b0; + let Inst{4} = 0b1; + + let DecoderMethod = "DecodeMVEVCVTt1fp"; +} + +class MVE_VCVT_fix_f32 + : MVE_VCVT_fix { + let Inst{20} = imm6{4}; +} +class MVE_VCVT_fix_f16 + : MVE_VCVT_fix { + let Inst{20} = 0b1; +} + +def MVE_VCVTf16s16_fix : MVE_VCVT_fix_f16<"f16.s16", 0b0, 0b0>; +def MVE_VCVTs16f16_fix : MVE_VCVT_fix_f16<"s16.f16", 0b0, 0b1>; +def MVE_VCVTf16u16_fix : MVE_VCVT_fix_f16<"f16.u16", 0b1, 0b0>; +def MVE_VCVTu16f16_fix : MVE_VCVT_fix_f16<"u16.f16", 0b1, 0b1>; +def MVE_VCVTf32s32_fix : MVE_VCVT_fix_f32<"f32.s32", 0b0, 0b0>; +def MVE_VCVTs32f32_fix : MVE_VCVT_fix_f32<"s32.f32", 0b0, 0b1>; +def MVE_VCVTf32u32_fix : MVE_VCVT_fix_f32<"f32.u32", 0b1, 0b0>; +def MVE_VCVTu32f32_fix : MVE_VCVT_fix_f32<"u32.f32", 0b1, 0b1>; + +class MVE_VCVT_fp_int_anpm size, bit op, string anpm, + bits<2> rm, list pattern=[]> + : MVE_float { + bits<4> Qd; + + let Inst{28} = 0b1; + let Inst{25-23} = 0b111; + let Inst{22} = Qd{3}; + let Inst{21-20} = 0b11; + let Inst{19-18} = size; + let Inst{17-16} = 0b11; + let Inst{15-13} = Qd{2-0}; + let Inst{12-10} = 0b000; + let Inst{9-8} = rm; + let Inst{7} = op; + let Inst{4} = 0b0; +} + +multiclass MVE_VCVT_fp_int_anpm_multi size, bit op, + list pattern=[]> { + def a : MVE_VCVT_fp_int_anpm; + def n : MVE_VCVT_fp_int_anpm; + def p : MVE_VCVT_fp_int_anpm; + def m : MVE_VCVT_fp_int_anpm; +} + +// This defines instructions such as MVE_VCVTu16f16a, with an explicit +// rounding-mode suffix on the mnemonic. The class below will define +// the bare MVE_VCVTu16f16 (with implied rounding toward zero). +defm MVE_VCVTs16f16 : MVE_VCVT_fp_int_anpm_multi<"s16.f16", 0b01, 0b0>; +defm MVE_VCVTu16f16 : MVE_VCVT_fp_int_anpm_multi<"u16.f16", 0b01, 0b1>; +defm MVE_VCVTs32f32 : MVE_VCVT_fp_int_anpm_multi<"s32.f32", 0b10, 0b0>; +defm MVE_VCVTu32f32 : MVE_VCVT_fp_int_anpm_multi<"u32.f32", 0b10, 0b1>; + +class MVE_VCVT_fp_int size, bits<2> op, + list pattern=[]> + : MVE_float<"vcvt", suffix, (outs MQPR:$Qd), + (ins MQPR:$Qm), "$Qd, $Qm", vpred_r, "", pattern> { + bits<4> Qd; + + let Inst{28} = 0b1; + let Inst{25-23} = 0b111; + let Inst{22} = Qd{3}; + let Inst{21-20} = 0b11; + let Inst{19-18} = size; + let Inst{17-16} = 0b11; + let Inst{15-13} = Qd{2-0}; + let Inst{12-9} = 0b0011; + let Inst{8-7} = op; + let Inst{4} = 0b0; +} + +// The unsuffixed VCVT for float->int implicitly rounds toward zero, +// which I reflect here in the llvm instruction names +def MVE_VCVTs16f16z : MVE_VCVT_fp_int<"s16.f16", 0b01, 0b10>; +def MVE_VCVTu16f16z : MVE_VCVT_fp_int<"u16.f16", 0b01, 0b11>; +def MVE_VCVTs32f32z : MVE_VCVT_fp_int<"s32.f32", 0b10, 0b10>; +def MVE_VCVTu32f32z : MVE_VCVT_fp_int<"u32.f32", 0b10, 0b11>; +// Whereas VCVT for int->float rounds to nearest +def MVE_VCVTf16s16n : MVE_VCVT_fp_int<"f16.s16", 0b01, 0b00>; +def MVE_VCVTf16u16n : MVE_VCVT_fp_int<"f16.u16", 0b01, 0b01>; +def MVE_VCVTf32s32n : MVE_VCVT_fp_int<"f32.s32", 0b10, 0b00>; +def MVE_VCVTf32u32n : MVE_VCVT_fp_int<"f32.u32", 0b10, 0b01>; + +class MVE_VABSNEG_fp size, bit negate, + list pattern=[]> + : MVE_float { + bits<4> Qd; + + let Inst{28} = 0b1; + let Inst{25-23} = 0b111; + let Inst{22} = Qd{3}; + let Inst{21-20} = 0b11; + let Inst{19-18} = size; + let Inst{17-16} = 0b01; + let Inst{15-13} = Qd{2-0}; + let Inst{11-8} = 0b0111; + let Inst{7} = negate; + let Inst{4} = 0b0; +} + +def MVE_VABSf16 : MVE_VABSNEG_fp<"vabs", "f16", 0b01, 0b0>; +def MVE_VABSf32 : MVE_VABSNEG_fp<"vabs", "f32", 0b10, 0b0>; + +def MVE_VNEGf16 : MVE_VABSNEG_fp<"vneg", "f16", 0b01, 0b1>; +def MVE_VNEGf32 : MVE_VABSNEG_fp<"vneg", "f32", 0b10, 0b1>; + +class MVE_VMAXMINNMA pattern=[]> + : MVE_f<(outs MQPR:$Qd), (ins MQPR:$Qd_src, MQPR:$Qm), + NoItinerary, iname, suffix, "$Qd, $Qm", vpred_n, "$Qd = $Qd_src", + pattern> { + bits<4> Qd; + bits<4> Qm; + + let Inst{28} = size; + let Inst{25-23} = 0b100; + let Inst{22} = Qd{3}; + let Inst{21-16} = 0b111111; + let Inst{15-13} = Qd{2-0}; + let Inst{12} = bit_12; + let Inst{11-6} = 0b111010; + let Inst{5} = Qm{3}; + let Inst{4} = 0b0; + let Inst{3-1} = Qm{2-0}; + let Inst{0} = 0b1; +} + +def MVE_VMAXNMAf32 : MVE_VMAXMINNMA<"vmaxnma", "f32", 0b0, 0b0>; +def MVE_VMAXNMAf16 : MVE_VMAXMINNMA<"vmaxnma", "f16", 0b1, 0b0>; + +def MVE_VMINNMAf32 : MVE_VMAXMINNMA<"vminnma", "f32", 0b0, 0b1>; +def MVE_VMINNMAf16 : MVE_VMAXMINNMA<"vminnma", "f16", 0b1, 0b1>; + +// end of MVE Floating Point instructions + class MVE_VPT size, dag iops, string asm, list pattern=[]> : MVE_MI<(outs ), iops, NoItinerary, !strconcat("vpt", "${Mk}", ".", suffix), asm, "", pattern> { bits<3> fc; diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp --- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -1276,6 +1276,20 @@ RegShiftedImm.SrcReg); } bool isRotImm() const { return Kind == k_RotateImmediate; } + bool isVCMLARotImm() const { + if (!isImm()) return false; + const MCConstantExpr *CE = dyn_cast(getImm()); + if (!CE) return false; + int64_t Value = CE->getValue(); + return Value == 0 || Value == 90 || Value == 180 || Value == 270; + } + bool isVCADDRotImm() const { + if (!isImm()) return false; + const MCConstantExpr *CE = dyn_cast(getImm()); + if (!CE) return false; + int64_t Value = CE->getValue(); + return Value == 90 || Value == 270; + } bool isModImm() const { return Kind == k_ModifiedImmediate; } bool isModImmNot() const { @@ -5964,6 +5978,8 @@ Mnemonic == "vshle" || Mnemonic == "vshlt" || Mnemonic == "vshllt" || Mnemonic == "vmvne" || Mnemonic == "vorne" || Mnemonic == "vnege" || Mnemonic == "vnegt" || + Mnemonic == "vmule" || Mnemonic == "vmult" || + Mnemonic == "vrintne" || Mnemonic.startswith("vq")))) { unsigned CC = ARMCondCodeFromString(Mnemonic.substr(Mnemonic.size()-2)); if (CC != ~0U) { @@ -6008,7 +6024,7 @@ if (isMnemonicVPTPredicable(Mnemonic, ExtraToken) && Mnemonic != "vmovlt" && Mnemonic != "vshllt" && Mnemonic != "vrshrnt" && Mnemonic != "vshrnt" && Mnemonic != "vqrshrunt" && Mnemonic != "vqshrunt" && - Mnemonic != "vqrshrnt" && Mnemonic != "vqshrnt") { + Mnemonic != "vqrshrnt" && Mnemonic != "vqshrnt" && Mnemonic != "vcvt") { unsigned CC = ARMVectorCondCodeFromString(Mnemonic.substr(Mnemonic.size()-1)); if (CC != ~0U) { Mnemonic = Mnemonic.slice(0, Mnemonic.size()-1); @@ -6315,7 +6331,8 @@ OperandVector &Operands) { // VRINT{Z, X} have a predicate operand in VFP, but not in NEON unsigned RegIdx = 3; - if ((Mnemonic == "vrintz" || Mnemonic == "vrintx") && + if ((((Mnemonic == "vrintz" || Mnemonic == "vrintx") && !hasMVE()) || + Mnemonic == "vrintr") && (static_cast(*Operands[2]).getToken() == ".f32" || static_cast(*Operands[2]).getToken() == ".f16")) { if (static_cast(*Operands[3]).isToken() && @@ -6564,7 +6581,9 @@ // definition in tblgen. Since these instructions may also have the // scalar predication operand we do not add the vector one and leave until // now to fix it up. - if (CanAcceptVPTPredicationCode && Mnemonic != "vmov") { + if (CanAcceptVPTPredicationCode && Mnemonic != "vmov" && + !(Mnemonic.startswith("vcvt") && Mnemonic != "vcvta" && + Mnemonic != "vcvtn" && Mnemonic != "vcvtp" && Mnemonic != "vcvtm")) { SMLoc Loc = SMLoc::getFromPointer(NameLoc.getPointer() + Mnemonic.size() + CarrySetting); Operands.push_back(ARMOperand::CreateVPTPred( @@ -6662,14 +6681,52 @@ ARMOperand::CreateVPTPred(ARMVCC::None, PLoc)); Operands.insert(Operands.begin(), ARMOperand::CreateToken(StringRef("vmovlt"), MLoc)); + } else if (Mnemonic == "vcvt" && PredicationCode == ARMCC::NE && + !shouldOmitVectorPredicateOperand(Mnemonic, Operands)) { + // Another nasty hack to deal with the ambiguity between vcvt with scalar + // predication 'ne' and vcvtn with vector predication 'e'. As above we + // can only distinguish between the two after we have parsed their + // operands. + Operands.erase(Operands.begin() + 1); + Operands.erase(Operands.begin()); + SMLoc MLoc = SMLoc::getFromPointer(NameLoc.getPointer()); + SMLoc PLoc = SMLoc::getFromPointer(NameLoc.getPointer() + + Mnemonic.size() - 1 + CarrySetting); + Operands.insert(Operands.begin(), + ARMOperand::CreateVPTPred(ARMVCC::Else, PLoc)); + Operands.insert(Operands.begin(), + ARMOperand::CreateToken(StringRef("vcvtn"), MLoc)); } // For vmov instructions, as mentioned earlier, we did not add the vector // predication code, since these may contain operands that require // special parsing. So now we have to see if they require vector // predication and replace the scalar one with the vector predication // operand if that is the case. - else if (Mnemonic == "vmov") { + else if (Mnemonic == "vmov" || + (Mnemonic.startswith("vcvt") && !Mnemonic.startswith("vcvta") && + !Mnemonic.startswith("vcvtn") && !Mnemonic.startswith("vcvtp") && + !Mnemonic.startswith("vcvtm"))) { if (!shouldOmitVectorPredicateOperand(Mnemonic, Operands)) { + // We could not split the vector predicate off vcvt because it might + // have been the scalar vcvtt instruction. Now we know its a vector + // instruction, we still need to check whether its the vector + // predicated vcvt with 'Then' predication or the vector vcvtt. We can + // distinguish the two based on the suffixes, if it is any of + // ".f16.f32", ".f32.f16", ".f16.f64" or ".f64.f16" then it is the vcvtt. + if (Mnemonic.startswith("vcvtt") && Operands.size() >= 4) { + auto Sz1 = static_cast(*Operands[2]); + auto Sz2 = static_cast(*Operands[3]); + if (!(Sz1.isToken() && Sz1.getToken().startswith(".f") && + Sz2.isToken() && Sz2.getToken().startswith(".f"))) { + Operands.erase(Operands.begin()); + SMLoc MLoc = SMLoc::getFromPointer(NameLoc.getPointer()); + VPTPredicationCode = ARMVCC::Then; + + Mnemonic = Mnemonic.substr(0, 4); + Operands.insert(Operands.begin(), + ARMOperand::CreateToken(Mnemonic, MLoc)); + } + } Operands.erase(Operands.begin() + 1); SMLoc PLoc = SMLoc::getFromPointer(NameLoc.getPointer() + Mnemonic.size() + CarrySetting); diff --git a/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp --- a/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp +++ b/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp @@ -379,6 +379,8 @@ uint64_t Address, const void *Decoder); static DecodeStatus DecodeVCVTQ(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeVCVTImmOperand(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder); static DecodeStatus DecodeNEONComplexLane64Instruction(MCInst &Inst, unsigned Val, uint64_t Address, @@ -502,6 +504,12 @@ unsigned Val, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeVCMLARotOperand(MCInst &Inst, unsigned Val, + uint64_t Address, + const void *Decoder); +static DecodeStatus DecodeVCADDRotOperand(MCInst &Inst, unsigned Val, + uint64_t Address, + const void *Decoder); template static DecodeStatus DecodeVSTRVLDR_SYSREG(MCInst &Inst, unsigned Insn, uint64_t Address, @@ -510,6 +518,8 @@ static DecodeStatus DecodeExpandedImmOperand(MCInst &Inst, unsigned Val, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeMVEVCVTt1fp(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder); static DecodeStatus DecodeMVEOverlappingLongShift(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder); @@ -6002,6 +6012,58 @@ return MCDisassembler::Success; } +static DecodeStatus DecodeVCMLARotOperand(MCInst &Inst, unsigned Val, + uint64_t Address, + const void *Decoder) { + DecodeStatus S = MCDisassembler::Success; + + if (Val > 3) + return MCDisassembler::Fail; + + Inst.addOperand(MCOperand::createImm(Val * 90)); + + return S; +} + +static DecodeStatus DecodeVCADDRotOperand(MCInst &Inst, unsigned Val, + uint64_t Address, + const void *Decoder) { + DecodeStatus S = MCDisassembler::Success; + + if (Val > 3) + return MCDisassembler::Fail; + + Inst.addOperand(MCOperand::createImm(Val == 0 ? 90 : 270)); + + return S; +} + +static DecodeStatus DecodeVCVTImmOperand(MCInst &Inst, unsigned Val, + uint64_t Address, const void *Decoder) { + DecodeStatus S = MCDisassembler::Success; + + unsigned DecodedVal = 64 - Val; + + switch (Inst.getOpcode()) { + case ARM::MVE_VCVTf16s16_fix: + case ARM::MVE_VCVTs16f16_fix: + case ARM::MVE_VCVTf16u16_fix: + case ARM::MVE_VCVTu16f16_fix: + if (DecodedVal > 16) + return MCDisassembler::Fail; + case ARM::MVE_VCVTf32s32_fix: + case ARM::MVE_VCVTs32f32_fix: + case ARM::MVE_VCVTf32u32_fix: + case ARM::MVE_VCVTu32f32_fix: + if (DecodedVal > 32) + return MCDisassembler::Fail; + } + + Inst.addOperand(MCOperand::createImm(64 - Val)); + + return S; +} + static unsigned FixedRegForVSTRVLDR_SYSREG(unsigned Opcode) { switch (Opcode) { case ARM::VSTR_P0_off: @@ -6135,3 +6197,22 @@ return S; } + +static DecodeStatus DecodeMVEVCVTt1fp(MCInst &Inst, unsigned Insn, uint64_t Address, + const void *Decoder) { + DecodeStatus S = MCDisassembler::Success; + unsigned Qd = ((fieldFromInstruction(Insn, 22, 1) << 3) | + fieldFromInstruction(Insn, 13, 3)); + unsigned Qm = ((fieldFromInstruction(Insn, 5, 1) << 3) | + fieldFromInstruction(Insn, 1, 3)); + unsigned imm6 = fieldFromInstruction(Insn, 16, 6); + + if (!Check(S, DecodeMQPRRegisterClass(Inst, Qd, Address, Decoder))) + return MCDisassembler::Fail; + if (!Check(S, DecodeMQPRRegisterClass(Inst, Qm, Address, Decoder))) + return MCDisassembler::Fail; + if (!Check(S, DecodeVCVTImmOperand(Inst, imm6, Address, Decoder))) + return MCDisassembler::Fail; + + return S; +} diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp @@ -424,6 +424,14 @@ unsigned EncodedValue, const MCSubtargetInfo &STI) const; + // MVE + unsigned getVCMLARotOpValue(const MCInst &MI, unsigned OpIdx, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned getVCADDRotOpValue(const MCInst &MI, unsigned OpIdx, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; void EmitByte(unsigned char C, raw_ostream &OS) const { OS << (char)C; } @@ -1913,6 +1921,32 @@ } } +unsigned ARMMCCodeEmitter:: +getVCMLARotOpValue(const MCInst &MI, unsigned OpIdx, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpIdx); + assert(MO.isImm() && "Unexpected operand type!"); + + unsigned Value = MO.getImm(); + assert(Value == 0 || Value == 90 || Value == 180 || Value == 270); + + return Value / 90; +} + +unsigned ARMMCCodeEmitter:: +getVCADDRotOpValue(const MCInst &MI, unsigned OpIdx, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpIdx); + assert(MO.isImm() && "Unexpected operand type!"); + + unsigned Value = MO.getImm(); + assert(Value == 90 || Value == 270); + + return Value == 270; +} + #include "ARMGenMCCodeEmitter.inc" MCCodeEmitter *llvm::createARMLEMCCodeEmitter(const MCInstrInfo &MCII, diff --git a/llvm/test/MC/ARM/mve-float.s b/llvm/test/MC/ARM/mve-float.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/ARM/mve-float.s @@ -0,0 +1,392 @@ +# RUN: not llvm-mc -triple=thumbv8.1m.main-none-eabi -mattr=+mve -show-encoding < %s \ +# RUN: | FileCheck --check-prefix=CHECK-NOFP %s +# RUN: not llvm-mc -triple=thumbv8.1m.main-none-eabi -mattr=+mve.fp,+fp64 -show-encoding < %s 2>%t \ +# RUN: | FileCheck --check-prefix=CHECK %s +# RUN: FileCheck --check-prefix=ERROR < %t %s + +# CHECK: vrintn.f16 q1, q0 @ encoding: [0xb6,0xff,0x40,0x24] +# CHECK-NOFP-NOT: vrintn.f16 q1, q0 @ encoding: [0xb6,0xff,0x40,0x24] +vrintn.f16 q1, q0 + +# CHECK: vrintn.f32 q0, q4 @ encoding: [0xba,0xff,0x48,0x04] +# CHECK-NOFP-NOT: vrintn.f32 q0, q4 @ encoding: [0xba,0xff,0x48,0x04] +vrintn.f32 q0, q4 + +# CHECK: vrinta.f16 q0, q1 @ encoding: [0xb6,0xff,0x42,0x05] +# CHECK-NOFP-NOT: vrinta.f16 q0, q1 @ encoding: [0xb6,0xff,0x42,0x05] +vrinta.f16 q0, q1 + +# CHECK: vrinta.f32 q1, q3 @ encoding: [0xba,0xff,0x46,0x25] +# CHECK-NOFP-NOT: vrinta.f32 q1, q3 @ encoding: [0xba,0xff,0x46,0x25] +vrinta.f32 q1, q3 + +# CHECK: vrintm.f16 q0, q5 @ encoding: [0xb6,0xff,0xca,0x06] +# CHECK-NOFP-NOT: vrintm.f16 q0, q5 @ encoding: [0xb6,0xff,0xca,0x06] +vrintm.f16 q0, q5 + +# CHECK: vrintm.f32 q0, q4 @ encoding: [0xba,0xff,0xc8,0x06] +# CHECK-NOFP-NOT: vrintm.f32 q0, q4 @ encoding: [0xba,0xff,0xc8,0x06] +vrintm.f32 q0, q4 + +# CHECK: vrintp.f16 q1, q0 @ encoding: [0xb6,0xff,0xc0,0x27] +# CHECK-NOFP-NOT: vrintp.f16 q1, q0 @ encoding: [0xb6,0xff,0xc0,0x27] +vrintp.f16 q1, q0 + +# CHECK: vrintp.f32 q0, q1 @ encoding: [0xba,0xff,0xc2,0x07] +# CHECK-NOFP-NOT: vrintp.f32 q0, q1 @ encoding: [0xba,0xff,0xc2,0x07] +vrintp.f32 q0, q1 + +# CHECK: vrintx.f16 q1, q2 @ encoding: [0xb6,0xff,0xc4,0x24] +# CHECK-NOFP-NOT: vrintx.f16 q1, q2 @ encoding: [0xb6,0xff,0xc4,0x24] +vrintx.f16 q1, q2 + +# CHECK: vrintx.f32 q1, q1 @ encoding: [0xba,0xff,0xc2,0x24] +# CHECK-NOFP-NOT: vrintx.f32 q1, q1 @ encoding: [0xba,0xff,0xc2,0x24] +vrintx.f32 q1, q1 + +# CHECK: vrintz.f16 q1, q6 @ encoding: [0xb6,0xff,0xcc,0x25] +# CHECK-NOFP-NOT: vrintz.f16 q1, q6 @ encoding: [0xb6,0xff,0xcc,0x25] +vrintz.f16 q1, q6 + +# CHECK: vrintz.f32 q1, q0 @ encoding: [0xba,0xff,0xc0,0x25] +# CHECK-NOFP-NOT: vrintz.f32 q1, q0 @ encoding: [0xba,0xff,0xc0,0x25] +vrintz.f32 q1, q0 + +# CHECK: vrintr.f32 s0, s1 @ encoding: [0xb6,0xee,0x60,0x0a] +# CHECK-NOFP-NOT: vrintr.f32 s0, s1 @ encoding: [0xb6,0xee,0x60,0x0a] +vrintr.f32.f32 s0, s1 + +# CHECK: vrintr.f64 d0, d1 @ encoding: [0xb6,0xee,0x41,0x0b] +# CHECK-NOFP-NOT: vrintr.f64 d0, d1 @ encoding: [0xb6,0xee,0x41,0x0b] +vrintr.f64.f64 d0, d1 + +# ERROR: [[@LINE+1]]:{{[0-9]+}}: {{error|note}}: invalid instruction +vrintr.f32.f32 q0, q1 + +# ERROR: [[@LINE+1]]:{{[0-9]+}}: {{error|note}}: invalid instruction +vrintr.f64 q0, q1 + +# CHECK: vmul.f16 q2, q1, q3 @ encoding: [0x12,0xff,0x56,0x4d] +# CHECK-NOFP-NOT: vmul.f16 q2, q1, q3 @ encoding: [0x12,0xff,0x56,0x4d] +vmul.f16 q2, q1, q3 + +# CHECK: vmul.f32 q0, q0, q5 @ encoding: [0x00,0xff,0x5a,0x0d] +# CHECK-NOFP-NOT: vmul.f32 q0, q0, q5 @ encoding: [0x00,0xff,0x5a,0x0d] +vmul.f32 q0, q0, q5 + +# CHECK: vcmla.f16 q3, q2, q1, #0 @ encoding: [0x24,0xfc,0x42,0x68] +# CHECK-NOFP-NOT: vcmla.f16 q3, q2, q1, #0 @ encoding: [0x24,0xfc,0x42,0x68] +vcmla.f16 q3, q2, q1, #0 + +# CHECK: vcmla.f16 q0, q0, q5, #90 @ encoding: [0xa0,0xfc,0x4a,0x08] +# CHECK-NOFP-NOT: vcmla.f16 q0, q0, q5, #90 @ encoding: [0xa0,0xfc,0x4a,0x08] +vcmla.f16 q0, q0, q5, #90 + +# CHECK: vcmla.f16 q3, q7, q2, #180 @ encoding: [0x2e,0xfd,0x44,0x68] +# CHECK-NOFP-NOT: vcmla.f16 q3, q7, q2, #180 @ encoding: [0x2e,0xfd,0x44,0x68] +vcmla.f16 q3, q7, q2, #180 + +# CHECK: vcmla.f16 q2, q7, q6, #270 @ encoding: [0xae,0xfd,0x4c,0x48] +# CHECK-NOFP-NOT: vcmla.f16 q2, q7, q6, #270 @ encoding: [0xae,0xfd,0x4c,0x48] +vcmla.f16 q2, q7, q6, #270 + +# ERROR: [[@LINE+1]]:{{[0-9]+}}: {{error|note}}: invalid operand for instruction +vcmla.f16 q3, q2, q1, #200 + +# CHECK: vcmla.f32 q2, q6, q6, #0 @ encoding: [0x3c,0xfc,0x4c,0x48] +# CHECK-NOFP-NOT: vcmla.f32 q2, q6, q6, #0 @ encoding: [0x3c,0xfc,0x4c,0x48] +vcmla.f32 q2, q6, q6, #0 + +# CHECK: vcmla.f32 q7, q1, q3, #90 @ encoding: [0xb2,0xfc,0x46,0xe8] +# CHECK-NOFP-NOT: vcmla.f32 q7, q1, q3, #90 @ encoding: [0xb2,0xfc,0x46,0xe8] +vcmla.f32 q7, q1, q3, #90 + +# CHECK: vcmla.f32 q4, q5, q3, #180 @ encoding: [0x3a,0xfd,0x46,0x88] +# CHECK-NOFP-NOT: vcmla.f32 q4, q5, q3, #180 @ encoding: [0x3a,0xfd,0x46,0x88] +vcmla.f32 q4, q5, q3, #180 + +# CHECK: vcmla.f32 q3, q2, q7, #270 @ encoding: [0xb4,0xfd,0x4e,0x68] +# CHECK-NOFP-NOT: vcmla.f32 q3, q2, q7, #270 @ encoding: [0xb4,0xfd,0x4e,0x68] +vcmla.f32 q3, q2, q7, #270 + +# ERROR: [[@LINE+1]]:{{[0-9]+}}: {{error|note}}: invalid operand for instruction +vcmla.f32 q3, q2, q1, #16 + +# CHECK: vfma.f16 q0, q2, q3 @ encoding: [0x14,0xef,0x56,0x0c] +# CHECK-NOFP-NOT: vfma.f16 q0, q2, q3 @ encoding: [0x14,0xef,0x56,0x0c] +vfma.f16 q0, q2, q3 + +# CHECK: vfma.f32 q0, q3, q7 @ encoding: [0x06,0xef,0x5e,0x0c] +# CHECK-NOFP-NOT: vfma.f32 q0, q3, q7 @ encoding: [0x06,0xef,0x5e,0x0c] +vfma.f32 q0, q3, q7 + +# CHECK: vfms.f16 q0, q2, q5 @ encoding: [0x34,0xef,0x5a,0x0c] +# CHECK-NOFP-NOT: vfms.f16 q0, q2, q5 @ encoding: [0x34,0xef,0x5a,0x0c] +vfms.f16 q0, q2, q5 + +# CHECK: vfms.f32 q1, q1, q2 @ encoding: [0x22,0xef,0x54,0x2c] +# CHECK-NOFP-NOT: vfms.f32 q1, q1, q2 @ encoding: [0x22,0xef,0x54,0x2c] +vfms.f32 q1, q1, q2 + +# CHECK: vadd.f16 q0, q0, q5 @ encoding: [0x10,0xef,0x4a,0x0d] +# CHECK-NOFP-NOT: vadd.f16 q0, q0, q5 @ encoding: [0x10,0xef,0x4a,0x0d] +vadd.f16 q0, q0, q5 + +# CHECK: vadd.f32 q1, q3, q0 @ encoding: [0x06,0xef,0x40,0x2d] +# CHECK-NOFP-NOT: vadd.f32 q1, q3, q0 @ encoding: [0x06,0xef,0x40,0x2d] +vadd.f32 q1, q3, q0 + +# ERROR: [[@LINE+1]]:{{[0-9]+}}: {{error|note}}: invalid instruction +vaddeq.f32 q0, q1, q2 + +# CHECK: vadd.f32 q0, q1, q2 @ encoding: [0x02,0xef,0x44,0x0d] +# CHECK-NOFP-NOT: vadd.f32 q0, q1, q2 @ encoding: [0x02,0xef,0x44,0x0d] +vadd.f32 q0, q1, q2 + +# CHECK: vcadd.f16 q2, q1, q7, #90 @ encoding: [0x82,0xfc,0x4e,0x48] +# CHECK-NOFP-NOT: vcadd.f16 q2, q1, q7, #90 @ encoding: [0x82,0xfc,0x4e,0x48] +vcadd.f16 q2, q1, q7, #90 + +# CHECK: vcadd.f16 q2, q5, q7, #270 @ encoding: [0x8a,0xfd,0x4e,0x48] +# CHECK-NOFP-NOT: vcadd.f16 q2, q5, q7, #270 @ encoding: [0x8a,0xfd,0x4e,0x48] +vcadd.f16 q2, q5, q7, #270 + +# ERROR: [[@LINE+1]]:{{[0-9]+}}: {{error|note}}: invalid operand for instruction +vcadd.f16 q2, q5, q7, #180 + +# CHECK: vcadd.f32 q0, q4, q7, #90 @ encoding: [0x98,0xfc,0x4e,0x08] +# CHECK-NOFP-NOT: vcadd.f32 q0, q4, q7, #90 @ encoding: [0x98,0xfc,0x4e,0x08] +vcadd.f32 q0, q4, q7, #90 + +# CHECK: vcadd.f32 q2, q2, q3, #270 @ encoding: [0x94,0xfd,0x46,0x48] +# CHECK-NOFP-NOT: vcadd.f32 q2, q2, q3, #270 @ encoding: [0x94,0xfd,0x46,0x48] +vcadd.f32 q2, q2, q3, #270 + +# ERROR: [[@LINE+1]]:{{[0-9]+}}: {{error|note}}: invalid operand for instruction +vcadd.f32 q2, q5, q7, #0 + +# CHECK: vabd.f16 q0, q0, q6 @ encoding: [0x30,0xff,0x4c,0x0d] +# CHECK-NOFP-NOT: vabd.f16 q0, q0, q6 @ encoding: [0x30,0xff,0x4c,0x0d] +vabd.f16 q0, q0, q6 + +# CHECK: vabd.f32 q0, q1, q4 @ encoding: [0x22,0xff,0x48,0x0d] +# CHECK-NOFP-NOT: vabd.f32 q0, q1, q4 @ encoding: [0x22,0xff,0x48,0x0d] +vabd.f32 q0, q1, q4 + +# CHECK: vcvt.f16.s16 q1, q7, #11 @ encoding: [0xb5,0xef,0x5e,0x2c] +# CHECK-NOFP-NOT: vcvt.f16.s16 q1, q7, #11 @ encoding: [0xb5,0xef,0x5e,0x2c] +vcvt.f16.s16 q1, q7, #11 + +# CHECK: vcvt.s16.f16 q1, q1, #3 @ encoding: [0xbd,0xef,0x52,0x2d] +# CHECK-NOFP-NOT: vcvt.s16.f16 q1, q1, #3 @ encoding: [0xbd,0xef,0x52,0x2d] +vcvt.s16.f16 q1, q1, #3 + +# CHECK: vcvt.f16.u16 q2, q1, #10 @ encoding: [0xb6,0xff,0x52,0x4c] +# CHECK-NOFP-NOT: vcvt.f16.u16 q2, q1, #10 @ encoding: [0xb6,0xff,0x52,0x4c] +vcvt.f16.u16 q2, q1, #10 + +# CHECK: vcvt.u16.f16 q0, q0, #3 @ encoding: [0xbd,0xff,0x50,0x0d] +# CHECK-NOFP-NOT: vcvt.u16.f16 q0, q0, #3 @ encoding: [0xbd,0xff,0x50,0x0d] +vcvt.u16.f16 q0, q0, #3 + +# CHECK: vcvt.f32.s32 q1, q7, #6 @ encoding: [0xba,0xef,0x5e,0x2e] +# CHECK-NOFP-NOT: vcvt.f32.s32 q1, q7, #6 @ encoding: [0xba,0xef,0x5e,0x2e] +vcvt.f32.s32 q1, q7, #6 + +# CHECK: vcvt.s32.f32 q1, q0, #21 @ encoding: [0xab,0xef,0x50,0x2f] +# CHECK-NOFP-NOT: vcvt.s32.f32 q1, q0, #21 @ encoding: [0xab,0xef,0x50,0x2f] +vcvt.s32.f32 q1, q0, #21 + +# CHECK: vcvt.f32.u32 q1, q4, #4 @ encoding: [0xbc,0xff,0x58,0x2e] +# CHECK-NOFP-NOT: vcvt.f32.u32 q1, q4, #4 @ encoding: [0xbc,0xff,0x58,0x2e] +vcvt.f32.u32 q1, q4, #4 + +# CHECK: vcvt.u32.f32 q1, q5, #8 @ encoding: [0xb8,0xff,0x5a,0x2f] +# CHECK-NOFP-NOT: vcvt.u32.f32 q1, q5, #8 @ encoding: [0xb8,0xff,0x5a,0x2f] +vcvt.u32.f32 q1, q5, #8 + +# CHECK: vcvt.f16.s16 q0, q1 @ encoding: [0xb7,0xff,0x42,0x06] +# CHECK-NOFP-NOT: vcvt.f16.s16 q0, q1 @ encoding: [0xb7,0xff,0x42,0x06] +vcvt.f16.s16 q0, q1 + +# CHECK: vcvt.f16.u16 q0, q4 @ encoding: [0xb7,0xff,0xc8,0x06] +# CHECK-NOFP-NOT: vcvt.f16.u16 q0, q4 @ encoding: [0xb7,0xff,0xc8,0x06] +vcvt.f16.u16 q0, q4 + +# CHECK: vcvt.s16.f16 q0, q0 @ encoding: [0xb7,0xff,0x40,0x07] +# CHECK-NOFP-NOT: vcvt.s16.f16 q0, q0 @ encoding: [0xb7,0xff,0x40,0x07] +vcvt.s16.f16 q0, q0 + +# CHECK: vcvt.u16.f16 q0, q0 @ encoding: [0xb7,0xff,0xc0,0x07] +# CHECK-NOFP-NOT: vcvt.u16.f16 q0, q0 @ encoding: [0xb7,0xff,0xc0,0x07] +vcvt.u16.f16 q0, q0 + +# CHECK: vcvt.f32.s32 q0, q0 @ encoding: [0xbb,0xff,0x40,0x06] +# CHECK-NOFP-NOT: vcvt.f32.s32 q0, q0 @ encoding: [0xbb,0xff,0x40,0x06] +vcvt.f32.s32 q0, q0 + +# CHECK: vcvt.f32.u32 q0, q0 @ encoding: [0xbb,0xff,0xc0,0x06] +# CHECK-NOFP-NOT: vcvt.f32.u32 q0, q0 @ encoding: [0xbb,0xff,0xc0,0x06] +vcvt.f32.u32 q0, q0 + +# CHECK: vcvt.s32.f32 q0, q0 @ encoding: [0xbb,0xff,0x40,0x07] +# CHECK-NOFP-NOT: vcvt.s32.f32 q0, q0 @ encoding: [0xbb,0xff,0x40,0x07] +vcvt.s32.f32 q0, q0 + +# CHECK: vcvt.u32.f32 q0, q2 @ encoding: [0xbb,0xff,0xc4,0x07] +# CHECK-NOFP-NOT: vcvt.u32.f32 q0, q2 @ encoding: [0xbb,0xff,0xc4,0x07] +vcvt.u32.f32 q0, q2 + +# CHECK: vcvta.s16.f16 q0, q7 @ encoding: [0xb7,0xff,0x4e,0x00] +# CHECK-NOFP-NOT: vcvta.s16.f16 q0, q7 @ encoding: [0xb7,0xff,0x4e,0x00] +vcvta.s16.f16 q0, q7 + +# CHECK: vcvta.s32.f32 s2, s3 @ encoding: [0xbc,0xfe,0xe1,0x1a] +# CHECK-NOFP-NOT: vcvta.s32.f32 s2, s3 @ encoding: [0xbc,0xfe,0xe1,0x1a] +vcvta.s32.f32 s2, s3 + +# CHECK: vcvta.s16.f16 q0, q7 @ encoding: [0xb7,0xff,0x4e,0x00] +# CHECK-NOFP-NOT: vcvta.s16.f16 q0, q7 @ encoding: [0xb7,0xff,0x4e,0x00] +vcvta.s16.f16 q0, q7 + +# CHECK: vcvtn.u32.f32 q7, q6 @ encoding: [0xbb,0xff,0xcc,0xe1] +# CHECK-NOFP-NOT: vcvtn.u32.f32 q7, q6 @ encoding: [0xbb,0xff,0xcc,0xe1] +vcvtn.u32.f32 q7, q6 + +# CHECK: vcvtp.s32.f32 q0, q7 @ encoding: [0xbb,0xff,0x4e,0x02] +# CHECK-NOFP-NOT: vcvtp.s32.f32 q0, q7 @ encoding: [0xbb,0xff,0x4e,0x02] +vcvtp.s32.f32 q0, q7 + +# CHECK: vcvtm.u32.f32 q1, q4 @ encoding: [0xbb,0xff,0xc8,0x23] +# CHECK-NOFP-NOT: vcvtm.u32.f32 q1, q4 @ encoding: [0xbb,0xff,0xc8,0x23] +vcvtm.u32.f32 q1, q4 + +# CHECK: vneg.f16 q0, q7 @ encoding: [0xb5,0xff,0xce,0x07] +# CHECK-NOFP-NOT: vneg.f16 q0, q7 @ encoding: [0xb5,0xff,0xce,0x07] +vneg.f16 q0, q7 + +# CHECK: vneg.f32 q0, q2 @ encoding: [0xb9,0xff,0xc4,0x07] +# CHECK-NOFP-NOT: vneg.f32 q0, q2 @ encoding: [0xb9,0xff,0xc4,0x07] +vneg.f32 q0, q2 + +# CHECK: vabs.f16 q0, q2 @ encoding: [0xb5,0xff,0x44,0x07] +# CHECK-NOFP-NOT: vabs.f16 q0, q2 @ encoding: [0xb5,0xff,0x44,0x07] +vabs.f16 q0, q2 + +# CHECK: vabs.f32 q0, q0 @ encoding: [0xb9,0xff,0x40,0x07] +# CHECK-NOFP-NOT: vabs.f32 q0, q0 @ encoding: [0xb9,0xff,0x40,0x07] +vabs.f32 q0, q0 + +# CHECK: vmaxnma.f16 q1, q1 @ encoding: [0x3f,0xfe,0x83,0x2e] +# CHECK-NOFP-NOT: vmaxnma.f16 q1, q1 @ encoding: [0x3f,0xfe,0x83,0x2e] +vmaxnma.f16 q1, q1 + +# CHECK: vmaxnma.f32 q2, q6 @ encoding: [0x3f,0xee,0x8d,0x4e] +# CHECK-NOFP-NOT: vmaxnma.f32 q2, q6 @ encoding: [0x3f,0xee,0x8d,0x4e] +vmaxnma.f32 q2, q6 + +# CHECK: vminnma.f16 q0, q2 @ encoding: [0x3f,0xfe,0x85,0x1e] +# CHECK-NOFP-NOT: vminnma.f16 q0, q2 @ encoding: [0x3f,0xfe,0x85,0x1e] +vminnma.f16 q0, q2 + +# CHECK: vminnma.f32 q0, q1 @ encoding: [0x3f,0xee,0x83,0x1e] +# CHECK-NOFP-NOT: vminnma.f32 q0, q1 @ encoding: [0x3f,0xee,0x83,0x1e] +vminnma.f32 q0, q1 + +it eq +vaddeq.f32 s0, s1 +# CHECK: it eq @ encoding: [0x08,0xbf] +# CHECK: vaddeq.f32 s0, s0, s1 @ encoding: [0x30,0xee,0x20,0x0a] +# CHECK-NOFP-NOT: vaddeq.f32 s0, s0, s1 @ encoding: [0x30,0xee,0x20,0x0a] + +vpst +vaddt.f16 q0, q1, q2 +# CHECK: vpst @ encoding: [0x71,0xfe,0x4d,0x0f] +# CHECK: vaddt.f16 q0, q1, q2 @ encoding: [0x12,0xef,0x44,0x0d] +# CHECK-NOFP-NOT: vaddt.f16 q0, q1, q2 @ encoding: [0x12,0xef,0x44,0x0d] + +vpste +vcvtmt.u32.f32 q0, q1 +vcvtne.s32.f32 q0, q1 +# CHECK: vpste @ encoding: [0x71,0xfe,0x4d,0x8f] +# CHECK: vtmt.u32.f32 q0, q1 @ encoding: [0xbb,0xff,0xc2,0x03] +# CHECK-NOFP-NOT: vtmt.u32.f32 q0, q1 @ encoding: [0xbb,0xff,0xc2,0x03] +# CHECK: vcvtne.s32.f32 q0, q1 @ encoding: [0xbb,0xff,0x42,0x01] +# CHECK-NOFP-NOT: vcvtne.s32.f32 q0, q1 @ encoding: [0xbb,0xff,0x42,0x01] + +it ne +vcvtne.s32.f32 s0, s1 +# CHECK: it ne @ encoding: [0x18,0xbf] +# CHECK: vcvtne.s32.f32 s0, s1 @ encoding: [0xbd,0xee,0xe0,0x0a] +# CHECK-NOFP-NOT: vcvtne.s32.f32 s0, s1 @ encoding: [0xbd,0xee,0xe0,0x0a] + +it ge +vcvttge.f64.f16 d3, s1 +# CHECK: it ge @ encoding: [0xa8,0xbf] +# CHECK: vcvttge.f64.f16 d3, s1 @ encoding: [0xb2,0xee,0xe0,0x3b] +# CHECK-NOFP-NOT: vcvttge.f64.f16 d3, s1 @ encoding: [0xb2,0xee,0xe0,0x3b] + +# ---------------------------------------------------------------------- +# The following tests have to go last because of the NOFP-NOT checks inside the +# VPT block. + +vpte.f32 lt, q3, r1 +vcvtt.u32.f32 q2, q0 +vcvte.u32.f32 q1, q0 +# CHECK: vpte.f32 lt, q3, r1 @ encoding: [0x77,0xee,0xc1,0x9f] +# CHECK-NOFP-NOT: vpte.f32 lt, q3, r1 @ encoding: [0x77,0xee,0xe1,0x8f] +# CHECK: vcvtt.u32.f32 q2, q0 @ encoding: [0xbb,0xff,0xc0,0x47] +# CHECK-NOFP-NOT: vcvtt.u32.f32 q2, q0 @ encoding: [0xbb,0xff,0xc0,0x47] +# CHECK: vcvte.u32.f32 q1, q0 @ encoding: [0xbb,0xff,0xc0,0x27] +# CHECK-NOFP-NOT: vcvte.u32.f32 q1, q0 @ encoding: [0xbb,0xff,0xc0,0x27] + +ite eq +vcvteq.u32.f32 s0, s1 +vcvtne.f32.u32 s0, s1 +# CHECK: ite eq @ encoding: [0x0c,0xbf] +# CHECK: vcvteq.u32.f32 s0, s1 @ encoding: [0xbc,0xee,0xe0,0x0a] +# CHECK-NOFP-NOT: vcvteq.u32.f32 s0, s1 @ encoding: [0xbc,0xee,0xe0,0x0a] +# CHECK: vcvtne.f32.u32 s0, s1 @ encoding: [0xb8,0xee,0x60,0x0a] +# CHECK-NOFP-NOT: vcvtne.f32.u32 s0, s1 @ encoding: [0xb8,0xee,0x60,0x0a] + +vpste +vmult.f16 q0, q1, q2 +vmule.f16 q0, q1, q2 +# CHECK: vpste @ encoding: [0x71,0xfe,0x4d,0x8f] +# CHECK: vmult.f16 q0, q1, q2 @ encoding: [0x12,0xff,0x54,0x0d] +# CHECK-NOFP-NOT: vmult.f16 q0, q1, q2 @ encoding: [0x12,0xff,0x54,0x0d] +# CHECK: vmule.f16 q0, q1, q2 @ encoding: [0x12,0xff,0x54,0x0d] +# CHECK-NOFP-NOT: vmule.f16 q0, q1, q2 @ encoding: [0x12,0xff,0x54,0x0d] + +ite eq +vmuleq.f64 d0, d0, d1 +vmulne.f64 d1, d0, d2 +# CHECK: ite eq @ encoding: [0x0c,0xbf] +# CHECK: vmuleq.f64 d0, d0, d1 @ encoding: [0x20,0xee,0x01,0x0b] +# CHECK-NOFP-NOT: vmuleq.f64 d0, d0, d1 @ encoding: [0x20,0xee,0x01,0x0b] +# CHECK: vmulne.f64 d1, d0, d2 @ encoding: [0x20,0xee,0x02,0x1b] +# CHECK-NOFP-NOT: vmulne.f64 d1, d0, d2 @ encoding: [0x20,0xee,0x02,0x1b] + +it eq +vnegeq.f32 s0, s1 +# CHECK: it eq @ encoding: [0x08,0xbf] +# CHECK: vnegeq.f32 s0, s1 @ encoding: [0xb1,0xee,0x60,0x0a] +# CHECK-NOFP-NOT: vnegeq.f32 s0, s1 @ encoding: [0xb1,0xee,0x60,0x0a] + +itt eq +vnmuleq.f32 s0, s1, s2 +vmuleq.f32 s0, s1, s2 +# CHECK: itt eq @ encoding: [0x04,0xbf] +# CHECK: vnmuleq.f32 s0, s1, s2 @ encoding: [0x20,0xee,0xc1,0x0a] +# CHECK-NOFP-NOT: vnmuleq.f32 s0, s1, s2 @ encoding: [0x20,0xee,0xc1,0x0a] +# CHECK: vmuleq.f32 s0, s1, s2 @ encoding: [0x20,0xee,0x81,0x0a] +# CHECK-NOFP-NOT: vmuleq.f32 s0, s1, s2 @ encoding: [0x20,0xee,0x81,0x0a] + +vpste +vrintnt.f16 q0, q1 +vrintne.f32 q0, q1 +# CHECK: vpste @ encoding: [0x71,0xfe,0x4d,0x8f] +# CHECK: vrintnt.f16 q0, q1 @ encoding: [0xb6,0xff,0x42,0x04] +# CHECK-NOFP-NOT: vrintnt.f16 q0, q1 @ encoding: [0xb6,0xff,0x42,0x04] +# CHECK: vrintne.f32 q0, q1 @ encoding: [0xba,0xff,0x42,0x04] +# CHECK-NOFP-NOT: vrintne.f32 q0, q1 @ encoding: [0xba,0xff,0x42,0x04] diff --git a/llvm/test/MC/Disassembler/ARM/mve-float.txt b/llvm/test/MC/Disassembler/ARM/mve-float.txt new file mode 100644 --- /dev/null +++ b/llvm/test/MC/Disassembler/ARM/mve-float.txt @@ -0,0 +1,195 @@ +# RUN: llvm-mc -disassemble -triple=thumbv8.1m.main-none-eabi -mattr=+mve.fp,+fp64 -show-encoding %s | FileCheck %s +# RUN: not llvm-mc -disassemble -triple=thumbv8.1m.main-none-eabi -show-encoding %s &> %t +# RUN: FileCheck --check-prefix=CHECK-NOMVE < %t %s + +# CHECK: vrintn.f16 q1, q0 @ encoding: [0xb6,0xff,0x40,0x24] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xb6,0xff,0x40,0x24] + +# CHECK: vrintn.f32 q0, q4 @ encoding: [0xba,0xff,0x48,0x04] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xba,0xff,0x48,0x04] + +# CHECK: vrinta.f16 q0, q1 @ encoding: [0xb6,0xff,0x42,0x05] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xb6,0xff,0x42,0x05] + +# CHECK: vrinta.f32 q1, q3 @ encoding: [0xba,0xff,0x46,0x25] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xba,0xff,0x46,0x25] + +# CHECK: vrintm.f16 q0, q5 @ encoding: [0xb6,0xff,0xca,0x06] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xb6,0xff,0xca,0x06] + +# CHECK: vrintm.f32 q0, q4 @ encoding: [0xba,0xff,0xc8,0x06] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xba,0xff,0xc8,0x06] + +# CHECK: vrintp.f16 q1, q0 @ encoding: [0xb6,0xff,0xc0,0x27] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xb6,0xff,0xc0,0x27] + +# CHECK: vrintp.f32 q0, q1 @ encoding: [0xba,0xff,0xc2,0x07] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xba,0xff,0xc2,0x07] + +# CHECK: vrintx.f16 q1, q2 @ encoding: [0xb6,0xff,0xc4,0x24] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xb6,0xff,0xc4,0x24] + +# CHECK: vrintx.f32 q1, q1 @ encoding: [0xba,0xff,0xc2,0x24] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xba,0xff,0xc2,0x24] + +# CHECK: vrintz.f16 q1, q6 @ encoding: [0xb6,0xff,0xcc,0x25] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xb6,0xff,0xcc,0x25] + +# CHECK: vrintz.f32 q1, q0 @ encoding: [0xba,0xff,0xc0,0x25] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xba,0xff,0xc0,0x25] + +# CHECK: vrintr.f32 s0, s1 @ encoding: [0xb6,0xee,0x60,0x0a] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xb6,0xee,0x60,0x0a] + +# CHECK: vrintr.f64 d0, d1 @ encoding: [0xb6,0xee,0x41,0x0b] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xb6,0xee,0x41,0x0b] + +# CHECK: vmul.f16 q2, q1, q3 @ encoding: [0x12,0xff,0x56,0x4d] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0x12,0xff,0x56,0x4d] + +# CHECK: vmul.f32 q0, q0, q5 @ encoding: [0x00,0xff,0x5a,0x0d] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0x00,0xff,0x5a,0x0d] + +# CHECK: vfma.f16 q0, q2, q3 @ encoding: [0x14,0xef,0x56,0x0c] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0x14,0xef,0x56,0x0c] + +# CHECK: vfma.f32 q0, q3, q7 @ encoding: [0x06,0xef,0x5e,0x0c] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0x06,0xef,0x5e,0x0c] + +# CHECK: vfms.f16 q0, q2, q5 @ encoding: [0x34,0xef,0x5a,0x0c] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0x34,0xef,0x5a,0x0c] + +# CHECK: vfms.f32 q1, q1, q2 @ encoding: [0x22,0xef,0x54,0x2c] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0x22,0xef,0x54,0x2c] + +# CHECK: vadd.f16 q0, q0, q5 @ encoding: [0x10,0xef,0x4a,0x0d] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0x10,0xef,0x4a,0x0d] + +# CHECK: vadd.f32 q1, q3, q0 @ encoding: [0x06,0xef,0x40,0x2d] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0x06,0xef,0x40,0x2d] + +# CHECK: vcadd.f16 q2, q1, q7, #90 @ encoding: [0x82,0xfc,0x4e,0x48] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0x82,0xfc,0x4e,0x48] + +# CHECK: vcadd.f16 q2, q5, q7, #270 @ encoding: [0x8a,0xfd,0x4e,0x48] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0x8a,0xfd,0x4e,0x48] + +# CHECK: vcadd.f32 q0, q4, q7, #90 @ encoding: [0x98,0xfc,0x4e,0x08] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0x98,0xfc,0x4e,0x08] + +# CHECK: vcadd.f32 q2, q2, q3, #270 @ encoding: [0x94,0xfd,0x46,0x48] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0x94,0xfd,0x46,0x48] + +# CHECK: vabd.f16 q0, q0, q6 @ encoding: [0x30,0xff,0x4c,0x0d] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0x30,0xff,0x4c,0x0d] + +# CHECK: vabd.f32 q0, q1, q4 @ encoding: [0x22,0xff,0x48,0x0d] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0x22,0xff,0x48,0x0d] + +# CHECK: vcvt.f16.s16 q0, q1 @ encoding: [0xb7,0xff,0x42,0x06] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xb7,0xff,0x42,0x06] + +# CHECK: vcvt.f16.u16 q0, q4 @ encoding: [0xb7,0xff,0xc8,0x06] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xb7,0xff,0xc8,0x06] + +# CHECK: vcvt.s16.f16 q0, q0 @ encoding: [0xb7,0xff,0x40,0x07] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xb7,0xff,0x40,0x07] + +# CHECK: vcvt.u16.f16 q0, q0 @ encoding: [0xb7,0xff,0xc0,0x07] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xb7,0xff,0xc0,0x07] + +# CHECK: vcvt.f32.s32 q0, q0 @ encoding: [0xbb,0xff,0x40,0x06] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xbb,0xff,0x40,0x06] + +# CHECK: vcvt.f32.u32 q0, q0 @ encoding: [0xbb,0xff,0xc0,0x06] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xbb,0xff,0xc0,0x06] + +# CHECK: vcvt.s32.f32 q0, q0 @ encoding: [0xbb,0xff,0x40,0x07] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xbb,0xff,0x40,0x07] + +# CHECK: vcvt.u32.f32 q0, q2 @ encoding: [0xbb,0xff,0xc4,0x07] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xbb,0xff,0xc4,0x07] + +# CHECK: vcvta.s16.f16 q0, q7 @ encoding: [0xb7,0xff,0x4e,0x00] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xb7,0xff,0x4e,0x00] + +# CHECK: vcvtn.u32.f32 q7, q6 @ encoding: [0xbb,0xff,0xcc,0xe1] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xbb,0xff,0xcc,0xe1] + +# CHECK: vcvtp.s32.f32 q0, q7 @ encoding: [0xbb,0xff,0x4e,0x02] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xbb,0xff,0x4e,0x02] + +# CHECK: vcvtm.u32.f32 q1, q4 @ encoding: [0xbb,0xff,0xc8,0x23] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xbb,0xff,0xc8,0x23] + +# CHECK: vneg.f16 q0, q7 @ encoding: [0xb5,0xff,0xce,0x07] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xb5,0xff,0xce,0x07] + +# CHECK: vneg.f32 q0, q2 @ encoding: [0xb9,0xff,0xc4,0x07] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xb9,0xff,0xc4,0x07] + +# CHECK: vabs.f16 q0, q2 @ encoding: [0xb5,0xff,0x44,0x07] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xb5,0xff,0x44,0x07] + +# CHECK: vabs.f32 q0, q0 @ encoding: [0xb9,0xff,0x40,0x07] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0xb9,0xff,0x40,0x07] + +# CHECK: vmaxnma.f16 q1, q1 @ encoding: [0x3f,0xfe,0x83,0x2e] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0x3f,0xfe,0x83,0x2e] + +# CHECK: vmaxnma.f32 q2, q6 @ encoding: [0x3f,0xee,0x8d,0x4e] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0x3f,0xee,0x8d,0x4e] + +# CHECK: vminnma.f16 q0, q2 @ encoding: [0x3f,0xfe,0x85,0x1e] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0x3f,0xfe,0x85,0x1e] + +# CHECK: vminnma.f32 q0, q1 @ encoding: [0x3f,0xee,0x83,0x1e] +# CHECK-NOMVE: [[@LINE+1]]:2: warning: invalid instruction encoding +[0x3f,0xee,0x83,0x1e]