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