diff options
Diffstat (limited to 'llvm/lib')
| -rw-r--r-- | llvm/lib/Target/ARM/ARMInstrMVE.td | 134 | ||||
| -rw-r--r-- | llvm/lib/Target/ARM/ARMInstrThumb2.td | 4 | ||||
| -rw-r--r-- | llvm/lib/Target/ARM/ARMRegisterInfo.td | 9 | ||||
| -rw-r--r-- | llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 105 | ||||
| -rw-r--r-- | llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp | 36 | ||||
| -rw-r--r-- | llvm/lib/Target/ARM/MCTargetDesc/ARMInstPrinter.cpp | 14 | ||||
| -rw-r--r-- | llvm/lib/Target/ARM/MCTargetDesc/ARMInstPrinter.h | 3 | 
7 files changed, 272 insertions, 33 deletions
diff --git a/llvm/lib/Target/ARM/ARMInstrMVE.td b/llvm/lib/Target/ARM/ARMInstrMVE.td index 85830077b98..d5c13205f60 100644 --- a/llvm/lib/Target/ARM/ARMInstrMVE.td +++ b/llvm/lib/Target/ARM/ARMInstrMVE.td @@ -126,6 +126,33 @@ def pred_basic_fp : VCMPPredicateOperand {    let EncoderMethod = "getRestrictedCondCodeOpValue";  } +// Register list operands for interleaving load/stores +def VecList2QAsmOperand : AsmOperandClass { +  let Name = "VecListTwoMQ"; +  let ParserMethod = "parseVectorList"; +  let RenderMethod = "addMVEVecListOperands"; +  let DiagnosticString = "operand must be a list of two consecutive "# +                         "q-registers in range [q0,q7]"; +} + +def VecList2Q : RegisterOperand<QQPR, "printMVEVectorListTwoQ"> { +  let ParserMatchClass = VecList2QAsmOperand; +  let PrintMethod = "printMVEVectorList<2>"; +} + +def VecList4QAsmOperand : AsmOperandClass { +  let Name = "VecListFourMQ"; +  let ParserMethod = "parseVectorList"; +  let RenderMethod = "addMVEVecListOperands"; +  let DiagnosticString = "operand must be a list of four consecutive "# +                         "q-registers in range [q0,q7]"; +} + +def VecList4Q : RegisterOperand<QQQQPR, "printMVEVectorListFourQ"> { +  let ParserMatchClass = VecList4QAsmOperand; +  let PrintMethod = "printMVEVectorList<4>"; +} +  class MVE_MI<dag oops, dag iops, InstrItinClass itin, string asm,               string ops, string cstr, list<dag> pattern>    : Thumb2XI<oops, iops, AddrModeNone, 4, itin, !strconcat(asm, "\t", ops), cstr, @@ -3111,6 +3138,113 @@ def MVE_VMOV_rr_q : MVE_VMOV_64bit<(outs rGPR:$Rt, rGPR:$Rt2), (ins MQPR:$Qd),  // end of coproc mov +// start of MVE interleaving load/store + +// Base class for the family of interleaving/deinterleaving +// load/stores with names like VLD20.8 and VST43.32. +class MVE_vldst24_base<bit writeback, bit fourregs, bits<2> stage, bits<2> size, +                       bit load, dag Oops, dag loadIops, dag wbIops, +                       string iname, string ops, +                       string cstr, list<dag> pattern=[]> +  : MVE_MI<Oops, !con(loadIops, wbIops), NoItinerary, iname, ops, cstr, pattern> { +  bits<4> VQd; +  bits<4> Rn; + +  let Inst{31-22} = 0b1111110010; +  let Inst{21} = writeback; +  let Inst{20} = load; +  let Inst{19-16} = Rn; +  let Inst{15-13} = VQd{2-0}; +  let Inst{12-9} = 0b1111; +  let Inst{8-7} = size; +  let Inst{6-5} = stage; +  let Inst{4-1} = 0b0000; +  let Inst{0} = fourregs; + +  let mayLoad = load; +  let mayStore = !eq(load,0); +} + +// A parameter class used to encapsulate all the ways the writeback +// variants of VLD20 and friends differ from the non-writeback ones. +class MVE_vldst24_writeback<bit b, dag Oo, dag Io, +                            string sy="", string c="", string n=""> { +  bit writeback = b; +  dag Oops = Oo; +  dag Iops = Io; +  string syntax = sy; +  string cstr = c; +  string id_suffix = n; +} + +// Another parameter class that encapsulates the differences between VLD2x +// and VLD4x. +class MVE_vldst24_nvecs<int n, list<int> s, bit b, RegisterOperand vl> { +  int nvecs = n; +  list<int> stages = s; +  bit bit0 = b; +  RegisterOperand VecList = vl; +} + +// A third parameter class that distinguishes VLDnn.8 from .16 from .32. +class MVE_vldst24_lanesize<int i, bits<2> b> { +  int lanesize = i; +  bits<2> sizebits = b; +} + +// A base class for each direction of transfer: one for load, one for +// store. I can't make these a fourth independent parametric tuple +// class, because they have to take the nvecs tuple class as a +// parameter, in order to find the right VecList operand type. + +class MVE_vld24_base<MVE_vldst24_nvecs n, bits<2> pat, bits<2> size, +                     MVE_vldst24_writeback wb, string iname, +                     list<dag> pattern=[]> +  : MVE_vldst24_base<wb.writeback, n.bit0, pat, size, 1, +                     !con((outs n.VecList:$VQd), wb.Oops), +                     (ins n.VecList:$VQdSrc), wb.Iops, +                     iname, "$VQd, $Rn" # wb.syntax, +                     wb.cstr # ",$VQdSrc = $VQd", pattern>; + +class MVE_vst24_base<MVE_vldst24_nvecs n, bits<2> pat, bits<2> size, +                     MVE_vldst24_writeback wb, string iname, +                     list<dag> pattern=[]> +  : MVE_vldst24_base<wb.writeback, n.bit0, pat, size, 0, +                     wb.Oops, (ins n.VecList:$VQd), wb.Iops, +                     iname, "$VQd, $Rn" # wb.syntax, +                     wb.cstr, pattern>; + +// Actually define all the interleaving loads and stores, by a series +// of nested foreaches over number of vectors (VLD2/VLD4); stage +// within one of those series (VLDx0/VLDx1/VLDx2/VLDx3); size of +// vector lane; writeback or no writeback. +foreach n = [MVE_vldst24_nvecs<2, [0,1],     0, VecList2Q>, +             MVE_vldst24_nvecs<4, [0,1,2,3], 1, VecList4Q>] in +foreach stage = n.stages in +foreach s = [MVE_vldst24_lanesize< 8, 0b00>, +             MVE_vldst24_lanesize<16, 0b01>, +             MVE_vldst24_lanesize<32, 0b10>] in +foreach wb = [MVE_vldst24_writeback< +                1, (outs rGPR:$wb), (ins t2_nosp_addr_offset_none:$Rn), +                "!", "$Rn.base = $wb", "_wb">, +              MVE_vldst24_writeback<0, (outs), (ins t2_addr_offset_none:$Rn)>] in { + +  // For each case within all of those foreaches, define the actual +  // instructions. The def names are made by gluing together pieces +  // from all the parameter classes, and will end up being things like +  // MVE_VLD20_8 and MVE_VST43_16_wb. + +  def "MVE_VLD" # n.nvecs # stage # "_" # s.lanesize # wb.id_suffix +    : MVE_vld24_base<n, stage, s.sizebits, wb, +                     "vld" # n.nvecs # stage # "." # s.lanesize>; + +  def "MVE_VST" # n.nvecs # stage # "_" # s.lanesize # wb.id_suffix +    : MVE_vst24_base<n, stage, s.sizebits, wb, +                     "vst" # n.nvecs # stage # "." # s.lanesize>; +} + +// end of MVE interleaving load/store +  class MVE_VPT<string suffix, bits<2> size, dag iops, string asm, list<dag> pattern=[]>    : MVE_MI<(outs ), iops, NoItinerary, !strconcat("vpt", "${Mk}", ".", suffix), asm, "", pattern> {    bits<3> fc; diff --git a/llvm/lib/Target/ARM/ARMInstrThumb2.td b/llvm/lib/Target/ARM/ARMInstrThumb2.td index 61e157ba986..8ca710cb468 100644 --- a/llvm/lib/Target/ARM/ARMInstrThumb2.td +++ b/llvm/lib/Target/ARM/ARMInstrThumb2.td @@ -176,9 +176,9 @@ def MemNoOffsetT2NoSpAsmOperand    : AsmOperandClass { let Name = "MemNoOffsetT2NoSp"; }  def t2_nosp_addr_offset_none : MemOperand {    let PrintMethod = "printAddrMode7Operand"; -  let DecoderMethod = "Decodet2rGPRRegisterClass"; +  let DecoderMethod = "DecoderGPRRegisterClass";    let ParserMatchClass = MemNoOffsetT2NoSpAsmOperand; -  let MIOperandInfo = (ops t2rGPR:$base); +  let MIOperandInfo = (ops rGPR:$base);  }  // t2addrmode_imm12  := reg + imm12 diff --git a/llvm/lib/Target/ARM/ARMRegisterInfo.td b/llvm/lib/Target/ARM/ARMRegisterInfo.td index 1322ed5577b..fc0286e724d 100644 --- a/llvm/lib/Target/ARM/ARMRegisterInfo.td +++ b/llvm/lib/Target/ARM/ARMRegisterInfo.td @@ -296,15 +296,6 @@ def rGPR : RegisterClass<"ARM", [i32], 32, (sub GPR, SP, PC)> {    let DiagnosticType = "rGPR";  } -// t2rGPR : All Thumb 2 registers with the exception of SP and PC. -def t2rGPR : RegisterClass<"ARM", [i32], 32, (sub GPR, SP, PC)> { -  let AltOrders = [(add LR, t2rGPR), (trunc t2rGPR, 8)]; -  let AltOrderSelect = [{ -      return 1 + MF.getSubtarget<ARMSubtarget>().isThumb1Only(); -  }]; -  let DiagnosticType = "rGPR"; -} -  // Thumb registers are R0-R7 normally. Some instructions can still use  // the general GPR register class above (MOV, e.g.)  def tGPR : RegisterClass<"ARM", [i32], 32, (trunc GPR, 8)> { diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 8ecdb139a04..6b5e77f81ce 100644 --- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -1759,6 +1759,12 @@ public:      return VectorList.Count == 1;    } +  bool isVecListTwoMQ() const { +    return isSingleSpacedVectorList() && VectorList.Count == 2 && +           ARMMCRegisterClasses[ARM::MQPRRegClassID].contains( +               VectorList.RegNum); +  } +    bool isVecListDPair() const {      if (!isSingleSpacedVectorList()) return false;      return (ARMMCRegisterClasses[ARM::DPairRegClassID] @@ -1792,6 +1798,12 @@ public:      return VectorList.Count == 4;    } +  bool isVecListFourMQ() const { +    return isSingleSpacedVectorList() && VectorList.Count == 4 && +           ARMMCRegisterClasses[ARM::MQPRRegClassID].contains( +               VectorList.RegNum); +  } +    bool isSingleSpacedVectorAllLanes() const {      return Kind == k_VectorListAllLanes && !VectorList.isDoubleSpaced;    } @@ -2550,6 +2562,11 @@ public:      Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum));    } +  void addMemNoOffsetT2NoSpOperands(MCInst &Inst, unsigned N) const { +    assert(N == 1 && "Invalid number of operands!"); +    Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); +  } +    void addMemPCRelImm12Operands(MCInst &Inst, unsigned N) const {      assert(N == 1 && "Invalid number of operands!");      int32_t Imm = Memory.OffsetImm->getValue(); @@ -2973,6 +2990,37 @@ public:      Inst.addOperand(MCOperand::createReg(VectorList.RegNum));    } +  void addMVEVecListOperands(MCInst &Inst, unsigned N) const { +    assert(N == 1 && "Invalid number of operands!"); + +    // When we come here, the VectorList field will identify a range +    // of q-registers by its base register and length, and it will +    // have already been error-checked to be the expected length of +    // range and contain only q-regs in the range q0-q7. So we can +    // count on the base register being in the range q0-q6 (for 2 +    // regs) or q0-q4 (for 4) +    // +    // The MVE instructions taking a register range of this kind will +    // need an operand in the QQPR or QQQQPR class, representing the +    // entire range as a unit. So we must translate into that class, +    // by finding the index of the base register in the MQPR reg +    // class, and returning the super-register at the corresponding +    // index in the target class. + +    const MCRegisterClass *RC_in = &ARMMCRegisterClasses[ARM::MQPRRegClassID]; +    const MCRegisterClass *RC_out = (VectorList.Count == 2) ? +      &ARMMCRegisterClasses[ARM::QQPRRegClassID] : +      &ARMMCRegisterClasses[ARM::QQQQPRRegClassID]; + +    unsigned I, E = RC_out->getNumRegs(); +    for (I = 0; I < E; I++) +      if (RC_in->getRegister(I) == VectorList.RegNum) +        break; +    assert(I < E && "Invalid vector list start register!"); + +    Inst.addOperand(MCOperand::createReg(RC_out->getRegister(I))); +  } +    void addVecListIndexedOperands(MCInst &Inst, unsigned N) const {      assert(N == 2 && "Invalid number of operands!");      Inst.addOperand(MCOperand::createReg(VectorList.RegNum)); @@ -4257,7 +4305,7 @@ ARMAsmParser::parseVectorList(OperandVector &Operands) {    // As an extension (to match gas), support a plain D register or Q register    // (without encosing curly braces) as a single or double entry list,    // respectively. -  if (Parser.getTok().is(AsmToken::Identifier)) { +  if (!hasMVE() && Parser.getTok().is(AsmToken::Identifier)) {      SMLoc E = Parser.getTok().getEndLoc();      int Reg = tryParseRegister();      if (Reg == -1) @@ -4325,9 +4373,14 @@ ARMAsmParser::parseVectorList(OperandVector &Operands) {    unsigned Count = 1;    int Spacing = 0;    unsigned FirstReg = Reg; + +  if (hasMVE() && !ARMMCRegisterClasses[ARM::MQPRRegClassID].contains(Reg)) { +      Error(Parser.getTok().getLoc(), "vector register in range Q0-Q7 expected"); +      return MatchOperand_ParseFail; +  }    // The list is of D registers, but we also allow Q regs and just interpret    // them as the two D sub-registers. -  if (ARMMCRegisterClasses[ARM::QPRRegClassID].contains(Reg)) { +  else if (!hasMVE() && ARMMCRegisterClasses[ARM::QPRRegClassID].contains(Reg)) {      FirstReg = Reg = getDRegFromQReg(Reg);      Spacing = 1; // double-spacing requires explicit D registers, otherwise                   // it's ambiguous with four-register single spaced. @@ -4357,14 +4410,17 @@ ARMAsmParser::parseVectorList(OperandVector &Operands) {          return MatchOperand_ParseFail;        }        // Allow Q regs and just interpret them as the two D sub-registers. -      if (ARMMCRegisterClasses[ARM::QPRRegClassID].contains(EndReg)) +      if (!hasMVE() && ARMMCRegisterClasses[ARM::QPRRegClassID].contains(EndReg))          EndReg = getDRegFromQReg(EndReg) + 1;        // If the register is the same as the start reg, there's nothing        // more to do.        if (Reg == EndReg)          continue;        // The register must be in the same register class as the first. -      if (!ARMMCRegisterClasses[ARM::DPRRegClassID].contains(EndReg)) { +      if ((hasMVE() && +           !ARMMCRegisterClasses[ARM::MQPRRegClassID].contains(EndReg)) || +          (!hasMVE() && +           !ARMMCRegisterClasses[ARM::DPRRegClassID].contains(EndReg))) {          Error(AfterMinusLoc, "invalid register in register list");          return MatchOperand_ParseFail;        } @@ -4397,13 +4453,21 @@ ARMAsmParser::parseVectorList(OperandVector &Operands) {        Error(RegLoc, "register expected");        return MatchOperand_ParseFail;      } + +    if (hasMVE()) { +      if (!ARMMCRegisterClasses[ARM::MQPRRegClassID].contains(Reg)) { +        Error(RegLoc, "vector register in range Q0-Q7 expected"); +        return MatchOperand_ParseFail; +      } +      Spacing = 1; +    }      // vector register lists must be contiguous.      // It's OK to use the enumeration values directly here rather, as the      // VFP register classes have the enum sorted properly.      //      // The list is of D registers, but we also allow Q regs and just interpret      // them as the two D sub-registers. -    if (ARMMCRegisterClasses[ARM::QPRRegClassID].contains(Reg)) { +    else if (ARMMCRegisterClasses[ARM::QPRRegClassID].contains(Reg)) {        if (!Spacing)          Spacing = 1; // Register range implies a single spaced list.        else if (Spacing == 2) { @@ -4464,30 +4528,20 @@ ARMAsmParser::parseVectorList(OperandVector &Operands) {    switch (LaneKind) {    case NoLanes: +  case AllLanes: {      // Two-register operands have been converted to the      // composite register classes. -    if (Count == 2) { -      const MCRegisterClass *RC = (Spacing == 1) ? -        &ARMMCRegisterClasses[ARM::DPairRegClassID] : -        &ARMMCRegisterClasses[ARM::DPairSpcRegClassID]; -      FirstReg = MRI->getMatchingSuperReg(FirstReg, ARM::dsub_0, RC); -    } -    Operands.push_back(ARMOperand::CreateVectorList(FirstReg, Count, -                                                    (Spacing == 2), S, E)); -    break; -  case AllLanes: -    // Two-register operands have been converted to the -    // composite register classes. -    if (Count == 2) { +    if (Count == 2 && !hasMVE()) {        const MCRegisterClass *RC = (Spacing == 1) ?          &ARMMCRegisterClasses[ARM::DPairRegClassID] :          &ARMMCRegisterClasses[ARM::DPairSpcRegClassID];        FirstReg = MRI->getMatchingSuperReg(FirstReg, ARM::dsub_0, RC);      } -    Operands.push_back(ARMOperand::CreateVectorListAllLanes(FirstReg, Count, -                                                            (Spacing == 2), -                                                            S, E)); +    auto Create = (LaneKind == NoLanes ? ARMOperand::CreateVectorList : +                   ARMOperand::CreateVectorListAllLanes); +    Operands.push_back(Create(FirstReg, Count, (Spacing == 2), S, E));      break; +  }    case IndexedLane:      Operands.push_back(ARMOperand::CreateVectorListIndexed(FirstReg, Count,                                                             LaneIndex, @@ -6127,7 +6181,10 @@ void ARMAsmParser::getMnemonicAcceptInfo(StringRef Mnemonic,        Mnemonic == "csinc" || Mnemonic == "csinv" || Mnemonic == "csneg" ||        Mnemonic == "cinc" || Mnemonic == "cinv" || Mnemonic == "cneg" ||        Mnemonic == "cset" || Mnemonic == "csetm" || -      Mnemonic.startswith("vpt") || Mnemonic.startswith("vpst")) { +      Mnemonic.startswith("vpt") || Mnemonic.startswith("vpst") || +      (hasMVE() && +       (Mnemonic.startswith("vst2") || Mnemonic.startswith("vld2") || +        Mnemonic.startswith("vst4") || Mnemonic.startswith("vld4")))) {      // These mnemonics are never predicable      CanAcceptPredicationCode = false;    } else if (!isThumb()) { @@ -6385,6 +6442,10 @@ bool ARMAsmParser::shouldOmitVectorPredicateOperand(StringRef Mnemonic,    if (!hasMVE() || Operands.size() < 3)      return true; +  if (Mnemonic.startswith("vld2") || Mnemonic.startswith("vld4") || +      Mnemonic.startswith("vst2") || Mnemonic.startswith("vst4")) +    return true; +    if (Mnemonic.startswith("vctp"))      return false; diff --git a/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp index acabfd32cd7..7ccf37ef0e6 100644 --- a/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp +++ b/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp @@ -220,6 +220,10 @@ static DecodeStatus DecodeQPRRegisterClass(MCInst &Inst, unsigned RegNo,                                     uint64_t Address, const void *Decoder);  static DecodeStatus DecodeMQPRRegisterClass(MCInst &Inst, unsigned RegNo,                                     uint64_t Address, const void *Decoder); +static DecodeStatus DecodeQQPRRegisterClass(MCInst &Inst, unsigned RegNo, +                                   uint64_t Address, const void *Decoder); +static DecodeStatus DecodeQQQQPRRegisterClass(MCInst &Inst, unsigned RegNo, +                                   uint64_t Address, const void *Decoder);  static DecodeStatus DecodeDPairRegisterClass(MCInst &Inst, unsigned RegNo,                                     uint64_t Address, const void *Decoder);  static DecodeStatus DecodeDPairSpacedRegisterClass(MCInst &Inst, @@ -5940,6 +5944,38 @@ static DecodeStatus DecodeMQPRRegisterClass(MCInst &Inst, unsigned RegNo,    return MCDisassembler::Success;  } +static const uint16_t QQPRDecoderTable[] = { +     ARM::Q0_Q1,  ARM::Q1_Q2,  ARM::Q2_Q3,  ARM::Q3_Q4, +     ARM::Q4_Q5,  ARM::Q5_Q6,  ARM::Q6_Q7 +}; + +static DecodeStatus DecodeQQPRRegisterClass(MCInst &Inst, unsigned RegNo, +                              uint64_t Address, +                              const void *Decoder) { +  if (RegNo > 6) +    return MCDisassembler::Fail; + +  unsigned Register = QQPRDecoderTable[RegNo]; +  Inst.addOperand(MCOperand::createReg(Register)); +  return MCDisassembler::Success; +} + +static const uint16_t QQQQPRDecoderTable[] = { +     ARM::Q0_Q1_Q2_Q3,  ARM::Q1_Q2_Q3_Q4,  ARM::Q2_Q3_Q4_Q5, +     ARM::Q3_Q4_Q5_Q6,  ARM::Q4_Q5_Q6_Q7 +}; + +static DecodeStatus DecodeQQQQPRRegisterClass(MCInst &Inst, unsigned RegNo, +                              uint64_t Address, +                              const void *Decoder) { +  if (RegNo > 4) +    return MCDisassembler::Fail; + +  unsigned Register = QQQQPRDecoderTable[RegNo]; +  Inst.addOperand(MCOperand::createReg(Register)); +  return MCDisassembler::Success; +} +  static DecodeStatus DecodeVPTMaskOperand(MCInst &Inst, unsigned Val,                                           uint64_t Address,                                           const void *Decoder) { diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMInstPrinter.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMInstPrinter.cpp index f85c8ee774e..72600c9209a 100644 --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMInstPrinter.cpp +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMInstPrinter.cpp @@ -1588,6 +1588,20 @@ void ARMInstPrinter::printVectorListFourSpaced(const MCInst *MI, unsigned OpNum,    O << "}";  } +template<unsigned NumRegs> +void ARMInstPrinter::printMVEVectorList(const MCInst *MI, unsigned OpNum, +                                        const MCSubtargetInfo &STI, +                                        raw_ostream &O) { +  unsigned Reg = MI->getOperand(OpNum).getReg(); +  const char *Prefix = "{"; +  for (unsigned i = 0; i < NumRegs; i++) { +    O << Prefix; +    printRegName(O, MRI.getSubReg(Reg, ARM::qsub_0 + i)); +    Prefix = ", "; +  } +  O << "}"; +} +  template<int64_t Angle, int64_t Remainder>  void ARMInstPrinter::printComplexRotationOp(const MCInst *MI, unsigned OpNo,                                              const MCSubtargetInfo &STI, diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMInstPrinter.h b/llvm/lib/Target/ARM/MCTargetDesc/ARMInstPrinter.h index 2805f7b58d1..4230ee975e7 100644 --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMInstPrinter.h +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMInstPrinter.h @@ -243,6 +243,9 @@ public:                                    const MCSubtargetInfo &STI, raw_ostream &O);    void printVectorListFourSpaced(const MCInst *MI, unsigned OpNum,                                   const MCSubtargetInfo &STI, raw_ostream &O); +  template<unsigned NumRegs> +  void printMVEVectorList(const MCInst *MI, unsigned OpNum, +                          const MCSubtargetInfo &STI, raw_ostream &O);    template<int64_t Angle, int64_t Remainder>    void printComplexRotationOp(const MCInst *MI, unsigned OpNum,                                const MCSubtargetInfo &STI, raw_ostream &O);  | 

