bool AArch64AsmParser::validateInstruction()

in llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp [4642:5096]


bool AArch64AsmParser::validateInstruction(MCInst &Inst, SMLoc &IDLoc,
                                           SmallVectorImpl<SMLoc> &Loc) {
  const MCRegisterInfo *RI = getContext().getRegisterInfo();
  const MCInstrDesc &MCID = MII.get(Inst.getOpcode());

  // A prefix only applies to the instruction following it.  Here we extract
  // prefix information for the next instruction before validating the current
  // one so that in the case of failure we don't erronously continue using the
  // current prefix.
  PrefixInfo Prefix = NextPrefix;
  NextPrefix = PrefixInfo::CreateFromInst(Inst, MCID.TSFlags);

  // Before validating the instruction in isolation we run through the rules
  // applicable when it follows a prefix instruction.
  // NOTE: brk & hlt can be prefixed but require no additional validation.
  if (Prefix.isActive() &&
      (Inst.getOpcode() != AArch64::BRK) &&
      (Inst.getOpcode() != AArch64::HLT)) {

    // Prefixed intructions must have a destructive operand.
    if ((MCID.TSFlags & AArch64::DestructiveInstTypeMask) ==
        AArch64::NotDestructive)
      return Error(IDLoc, "instruction is unpredictable when following a"
                   " movprfx, suggest replacing movprfx with mov");

    // Destination operands must match.
    if (Inst.getOperand(0).getReg() != Prefix.getDstReg())
      return Error(Loc[0], "instruction is unpredictable when following a"
                   " movprfx writing to a different destination");

    // Destination operand must not be used in any other location.
    for (unsigned i = 1; i < Inst.getNumOperands(); ++i) {
      if (Inst.getOperand(i).isReg() &&
          (MCID.getOperandConstraint(i, MCOI::TIED_TO) == -1) &&
          isMatchingOrAlias(Prefix.getDstReg(), Inst.getOperand(i).getReg()))
        return Error(Loc[0], "instruction is unpredictable when following a"
                     " movprfx and destination also used as non-destructive"
                     " source");
    }

    auto PPRRegClass = AArch64MCRegisterClasses[AArch64::PPRRegClassID];
    if (Prefix.isPredicated()) {
      int PgIdx = -1;

      // Find the instructions general predicate.
      for (unsigned i = 1; i < Inst.getNumOperands(); ++i)
        if (Inst.getOperand(i).isReg() &&
            PPRRegClass.contains(Inst.getOperand(i).getReg())) {
          PgIdx = i;
          break;
        }

      // Instruction must be predicated if the movprfx is predicated.
      if (PgIdx == -1 ||
          (MCID.TSFlags & AArch64::ElementSizeMask) == AArch64::ElementSizeNone)
        return Error(IDLoc, "instruction is unpredictable when following a"
                     " predicated movprfx, suggest using unpredicated movprfx");

      // Instruction must use same general predicate as the movprfx.
      if (Inst.getOperand(PgIdx).getReg() != Prefix.getPgReg())
        return Error(IDLoc, "instruction is unpredictable when following a"
                     " predicated movprfx using a different general predicate");

      // Instruction element type must match the movprfx.
      if ((MCID.TSFlags & AArch64::ElementSizeMask) != Prefix.getElementSize())
        return Error(IDLoc, "instruction is unpredictable when following a"
                     " predicated movprfx with a different element size");
    }
  }

  // Check for indexed addressing modes w/ the base register being the
  // same as a destination/source register or pair load where
  // the Rt == Rt2. All of those are undefined behaviour.
  switch (Inst.getOpcode()) {
  case AArch64::LDPSWpre:
  case AArch64::LDPWpost:
  case AArch64::LDPWpre:
  case AArch64::LDPXpost:
  case AArch64::LDPXpre: {
    unsigned Rt = Inst.getOperand(1).getReg();
    unsigned Rt2 = Inst.getOperand(2).getReg();
    unsigned Rn = Inst.getOperand(3).getReg();
    if (RI->isSubRegisterEq(Rn, Rt))
      return Error(Loc[0], "unpredictable LDP instruction, writeback base "
                           "is also a destination");
    if (RI->isSubRegisterEq(Rn, Rt2))
      return Error(Loc[1], "unpredictable LDP instruction, writeback base "
                           "is also a destination");
    LLVM_FALLTHROUGH;
  }
  case AArch64::LDPDi:
  case AArch64::LDPQi:
  case AArch64::LDPSi:
  case AArch64::LDPSWi:
  case AArch64::LDPWi:
  case AArch64::LDPXi: {
    unsigned Rt = Inst.getOperand(0).getReg();
    unsigned Rt2 = Inst.getOperand(1).getReg();
    if (Rt == Rt2)
      return Error(Loc[1], "unpredictable LDP instruction, Rt2==Rt");
    break;
  }
  case AArch64::LDPDpost:
  case AArch64::LDPDpre:
  case AArch64::LDPQpost:
  case AArch64::LDPQpre:
  case AArch64::LDPSpost:
  case AArch64::LDPSpre:
  case AArch64::LDPSWpost: {
    unsigned Rt = Inst.getOperand(1).getReg();
    unsigned Rt2 = Inst.getOperand(2).getReg();
    if (Rt == Rt2)
      return Error(Loc[1], "unpredictable LDP instruction, Rt2==Rt");
    break;
  }
  case AArch64::STPDpost:
  case AArch64::STPDpre:
  case AArch64::STPQpost:
  case AArch64::STPQpre:
  case AArch64::STPSpost:
  case AArch64::STPSpre:
  case AArch64::STPWpost:
  case AArch64::STPWpre:
  case AArch64::STPXpost:
  case AArch64::STPXpre: {
    unsigned Rt = Inst.getOperand(1).getReg();
    unsigned Rt2 = Inst.getOperand(2).getReg();
    unsigned Rn = Inst.getOperand(3).getReg();
    if (RI->isSubRegisterEq(Rn, Rt))
      return Error(Loc[0], "unpredictable STP instruction, writeback base "
                           "is also a source");
    if (RI->isSubRegisterEq(Rn, Rt2))
      return Error(Loc[1], "unpredictable STP instruction, writeback base "
                           "is also a source");
    break;
  }
  case AArch64::LDRBBpre:
  case AArch64::LDRBpre:
  case AArch64::LDRHHpre:
  case AArch64::LDRHpre:
  case AArch64::LDRSBWpre:
  case AArch64::LDRSBXpre:
  case AArch64::LDRSHWpre:
  case AArch64::LDRSHXpre:
  case AArch64::LDRSWpre:
  case AArch64::LDRWpre:
  case AArch64::LDRXpre:
  case AArch64::LDRBBpost:
  case AArch64::LDRBpost:
  case AArch64::LDRHHpost:
  case AArch64::LDRHpost:
  case AArch64::LDRSBWpost:
  case AArch64::LDRSBXpost:
  case AArch64::LDRSHWpost:
  case AArch64::LDRSHXpost:
  case AArch64::LDRSWpost:
  case AArch64::LDRWpost:
  case AArch64::LDRXpost: {
    unsigned Rt = Inst.getOperand(1).getReg();
    unsigned Rn = Inst.getOperand(2).getReg();
    if (RI->isSubRegisterEq(Rn, Rt))
      return Error(Loc[0], "unpredictable LDR instruction, writeback base "
                           "is also a source");
    break;
  }
  case AArch64::STRBBpost:
  case AArch64::STRBpost:
  case AArch64::STRHHpost:
  case AArch64::STRHpost:
  case AArch64::STRWpost:
  case AArch64::STRXpost:
  case AArch64::STRBBpre:
  case AArch64::STRBpre:
  case AArch64::STRHHpre:
  case AArch64::STRHpre:
  case AArch64::STRWpre:
  case AArch64::STRXpre: {
    unsigned Rt = Inst.getOperand(1).getReg();
    unsigned Rn = Inst.getOperand(2).getReg();
    if (RI->isSubRegisterEq(Rn, Rt))
      return Error(Loc[0], "unpredictable STR instruction, writeback base "
                           "is also a source");
    break;
  }
  case AArch64::STXRB:
  case AArch64::STXRH:
  case AArch64::STXRW:
  case AArch64::STXRX:
  case AArch64::STLXRB:
  case AArch64::STLXRH:
  case AArch64::STLXRW:
  case AArch64::STLXRX: {
    unsigned Rs = Inst.getOperand(0).getReg();
    unsigned Rt = Inst.getOperand(1).getReg();
    unsigned Rn = Inst.getOperand(2).getReg();
    if (RI->isSubRegisterEq(Rt, Rs) ||
        (RI->isSubRegisterEq(Rn, Rs) && Rn != AArch64::SP))
      return Error(Loc[0],
                   "unpredictable STXR instruction, status is also a source");
    break;
  }
  case AArch64::STXPW:
  case AArch64::STXPX:
  case AArch64::STLXPW:
  case AArch64::STLXPX: {
    unsigned Rs = Inst.getOperand(0).getReg();
    unsigned Rt1 = Inst.getOperand(1).getReg();
    unsigned Rt2 = Inst.getOperand(2).getReg();
    unsigned Rn = Inst.getOperand(3).getReg();
    if (RI->isSubRegisterEq(Rt1, Rs) || RI->isSubRegisterEq(Rt2, Rs) ||
        (RI->isSubRegisterEq(Rn, Rs) && Rn != AArch64::SP))
      return Error(Loc[0],
                   "unpredictable STXP instruction, status is also a source");
    break;
  }
  case AArch64::LDRABwriteback:
  case AArch64::LDRAAwriteback: {
    unsigned Xt = Inst.getOperand(0).getReg();
    unsigned Xn = Inst.getOperand(1).getReg();
    if (Xt == Xn)
      return Error(Loc[0],
          "unpredictable LDRA instruction, writeback base"
          " is also a destination");
    break;
  }
  }

  // Check v8.8-A memops instructions.
  switch (Inst.getOpcode()) {
  case AArch64::CPYFP:
  case AArch64::CPYFPWN:
  case AArch64::CPYFPRN:
  case AArch64::CPYFPN:
  case AArch64::CPYFPWT:
  case AArch64::CPYFPWTWN:
  case AArch64::CPYFPWTRN:
  case AArch64::CPYFPWTN:
  case AArch64::CPYFPRT:
  case AArch64::CPYFPRTWN:
  case AArch64::CPYFPRTRN:
  case AArch64::CPYFPRTN:
  case AArch64::CPYFPT:
  case AArch64::CPYFPTWN:
  case AArch64::CPYFPTRN:
  case AArch64::CPYFPTN:
  case AArch64::CPYFM:
  case AArch64::CPYFMWN:
  case AArch64::CPYFMRN:
  case AArch64::CPYFMN:
  case AArch64::CPYFMWT:
  case AArch64::CPYFMWTWN:
  case AArch64::CPYFMWTRN:
  case AArch64::CPYFMWTN:
  case AArch64::CPYFMRT:
  case AArch64::CPYFMRTWN:
  case AArch64::CPYFMRTRN:
  case AArch64::CPYFMRTN:
  case AArch64::CPYFMT:
  case AArch64::CPYFMTWN:
  case AArch64::CPYFMTRN:
  case AArch64::CPYFMTN:
  case AArch64::CPYFE:
  case AArch64::CPYFEWN:
  case AArch64::CPYFERN:
  case AArch64::CPYFEN:
  case AArch64::CPYFEWT:
  case AArch64::CPYFEWTWN:
  case AArch64::CPYFEWTRN:
  case AArch64::CPYFEWTN:
  case AArch64::CPYFERT:
  case AArch64::CPYFERTWN:
  case AArch64::CPYFERTRN:
  case AArch64::CPYFERTN:
  case AArch64::CPYFET:
  case AArch64::CPYFETWN:
  case AArch64::CPYFETRN:
  case AArch64::CPYFETN:
  case AArch64::CPYP:
  case AArch64::CPYPWN:
  case AArch64::CPYPRN:
  case AArch64::CPYPN:
  case AArch64::CPYPWT:
  case AArch64::CPYPWTWN:
  case AArch64::CPYPWTRN:
  case AArch64::CPYPWTN:
  case AArch64::CPYPRT:
  case AArch64::CPYPRTWN:
  case AArch64::CPYPRTRN:
  case AArch64::CPYPRTN:
  case AArch64::CPYPT:
  case AArch64::CPYPTWN:
  case AArch64::CPYPTRN:
  case AArch64::CPYPTN:
  case AArch64::CPYM:
  case AArch64::CPYMWN:
  case AArch64::CPYMRN:
  case AArch64::CPYMN:
  case AArch64::CPYMWT:
  case AArch64::CPYMWTWN:
  case AArch64::CPYMWTRN:
  case AArch64::CPYMWTN:
  case AArch64::CPYMRT:
  case AArch64::CPYMRTWN:
  case AArch64::CPYMRTRN:
  case AArch64::CPYMRTN:
  case AArch64::CPYMT:
  case AArch64::CPYMTWN:
  case AArch64::CPYMTRN:
  case AArch64::CPYMTN:
  case AArch64::CPYE:
  case AArch64::CPYEWN:
  case AArch64::CPYERN:
  case AArch64::CPYEN:
  case AArch64::CPYEWT:
  case AArch64::CPYEWTWN:
  case AArch64::CPYEWTRN:
  case AArch64::CPYEWTN:
  case AArch64::CPYERT:
  case AArch64::CPYERTWN:
  case AArch64::CPYERTRN:
  case AArch64::CPYERTN:
  case AArch64::CPYET:
  case AArch64::CPYETWN:
  case AArch64::CPYETRN:
  case AArch64::CPYETN: {
    unsigned Xd_wb = Inst.getOperand(0).getReg();
    unsigned Xs_wb = Inst.getOperand(1).getReg();
    unsigned Xn_wb = Inst.getOperand(2).getReg();
    unsigned Xd = Inst.getOperand(3).getReg();
    unsigned Xs = Inst.getOperand(4).getReg();
    unsigned Xn = Inst.getOperand(5).getReg();
    if (Xd_wb != Xd)
      return Error(Loc[0],
                   "invalid CPY instruction, Xd_wb and Xd do not match");
    if (Xs_wb != Xs)
      return Error(Loc[0],
                   "invalid CPY instruction, Xs_wb and Xs do not match");
    if (Xn_wb != Xn)
      return Error(Loc[0],
                   "invalid CPY instruction, Xn_wb and Xn do not match");
    if (Xd == Xs)
      return Error(Loc[0], "invalid CPY instruction, destination and source"
                           " registers are the same");
    if (Xd == Xn)
      return Error(Loc[0], "invalid CPY instruction, destination and size"
                           " registers are the same");
    if (Xs == Xn)
      return Error(Loc[0], "invalid CPY instruction, source and size"
                           " registers are the same");
    break;
  }
  case AArch64::SETP:
  case AArch64::SETPT:
  case AArch64::SETPN:
  case AArch64::SETPTN:
  case AArch64::SETM:
  case AArch64::SETMT:
  case AArch64::SETMN:
  case AArch64::SETMTN:
  case AArch64::SETE:
  case AArch64::SETET:
  case AArch64::SETEN:
  case AArch64::SETETN:
  case AArch64::SETGP:
  case AArch64::SETGPT:
  case AArch64::SETGPN:
  case AArch64::SETGPTN:
  case AArch64::SETGM:
  case AArch64::SETGMT:
  case AArch64::SETGMN:
  case AArch64::SETGMTN:
  case AArch64::MOPSSETGE:
  case AArch64::MOPSSETGET:
  case AArch64::MOPSSETGEN:
  case AArch64::MOPSSETGETN: {
    unsigned Xd_wb = Inst.getOperand(0).getReg();
    unsigned Xn_wb = Inst.getOperand(1).getReg();
    unsigned Xd = Inst.getOperand(2).getReg();
    unsigned Xn = Inst.getOperand(3).getReg();
    unsigned Xm = Inst.getOperand(4).getReg();
    if (Xd_wb != Xd)
      return Error(Loc[0],
                   "invalid SET instruction, Xd_wb and Xd do not match");
    if (Xn_wb != Xn)
      return Error(Loc[0],
                   "invalid SET instruction, Xn_wb and Xn do not match");
    if (Xd == Xn)
      return Error(Loc[0], "invalid SET instruction, destination and size"
                           " registers are the same");
    if (Xd == Xm)
      return Error(Loc[0], "invalid SET instruction, destination and source"
                           " registers are the same");
    if (Xn == Xm)
      return Error(Loc[0], "invalid SET instruction, source and size"
                           " registers are the same");
    break;
  }
  }

  // Now check immediate ranges. Separate from the above as there is overlap
  // in the instructions being checked and this keeps the nested conditionals
  // to a minimum.
  switch (Inst.getOpcode()) {
  case AArch64::ADDSWri:
  case AArch64::ADDSXri:
  case AArch64::ADDWri:
  case AArch64::ADDXri:
  case AArch64::SUBSWri:
  case AArch64::SUBSXri:
  case AArch64::SUBWri:
  case AArch64::SUBXri: {
    // Annoyingly we can't do this in the isAddSubImm predicate, so there is
    // some slight duplication here.
    if (Inst.getOperand(2).isExpr()) {
      const MCExpr *Expr = Inst.getOperand(2).getExpr();
      AArch64MCExpr::VariantKind ELFRefKind;
      MCSymbolRefExpr::VariantKind DarwinRefKind;
      int64_t Addend;
      if (classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, Addend)) {

        // Only allow these with ADDXri.
        if ((DarwinRefKind == MCSymbolRefExpr::VK_PAGEOFF ||
             DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGEOFF) &&
            Inst.getOpcode() == AArch64::ADDXri)
          return false;

        // Only allow these with ADDXri/ADDWri
        if ((ELFRefKind == AArch64MCExpr::VK_LO12 ||
             ELFRefKind == AArch64MCExpr::VK_DTPREL_HI12 ||
             ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12 ||
             ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12_NC ||
             ELFRefKind == AArch64MCExpr::VK_TPREL_HI12 ||
             ELFRefKind == AArch64MCExpr::VK_TPREL_LO12 ||
             ELFRefKind == AArch64MCExpr::VK_TPREL_LO12_NC ||
             ELFRefKind == AArch64MCExpr::VK_TLSDESC_LO12 ||
             ELFRefKind == AArch64MCExpr::VK_SECREL_LO12 ||
             ELFRefKind == AArch64MCExpr::VK_SECREL_HI12) &&
            (Inst.getOpcode() == AArch64::ADDXri ||
             Inst.getOpcode() == AArch64::ADDWri))
          return false;

        // Don't allow symbol refs in the immediate field otherwise
        // Note: Loc.back() may be Loc[1] or Loc[2] depending on the number of
        // operands of the original instruction (i.e. 'add w0, w1, borked' vs
        // 'cmp w0, 'borked')
        return Error(Loc.back(), "invalid immediate expression");
      }
      // We don't validate more complex expressions here
    }
    return false;
  }
  default:
    return false;
  }
}