Skip to content

[AsmParser][NFCI] Restructure DiagnosticPredicate #126653

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Feb 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 17 additions & 20 deletions llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,12 +167,6 @@ class ParseStatus {
}
};

enum class DiagnosticPredicateTy {
Match,
NearMatch,
NoMatch,
};

// When an operand is parsed, the assembler will try to iterate through a set of
// possible operand classes that the operand might match and call the
// corresponding PredicateMethod to determine that.
Expand All @@ -198,21 +192,24 @@ enum class DiagnosticPredicateTy {
// This is a light-weight alternative to the 'NearMissInfo' approach
// below which collects *all* possible diagnostics. This alternative
// is optional and fully backward compatible with existing
// PredicateMethods that return a 'bool' (match or no match).
// PredicateMethods that return a 'bool' (match or near match).
struct DiagnosticPredicate {
DiagnosticPredicateTy Type;

explicit DiagnosticPredicate(bool Match)
: Type(Match ? DiagnosticPredicateTy::Match
: DiagnosticPredicateTy::NearMatch) {}
DiagnosticPredicate(DiagnosticPredicateTy T) : Type(T) {}
DiagnosticPredicate(const DiagnosticPredicate &) = default;
DiagnosticPredicate& operator=(const DiagnosticPredicate &) = default;

operator bool() const { return Type == DiagnosticPredicateTy::Match; }
bool isMatch() const { return Type == DiagnosticPredicateTy::Match; }
bool isNearMatch() const { return Type == DiagnosticPredicateTy::NearMatch; }
bool isNoMatch() const { return Type == DiagnosticPredicateTy::NoMatch; }
enum PredicateTy {
Match, // Matches
NearMatch, // Close Match: use Specific Diagnostic
NoMatch, // No Match: use `InvalidOperand`
} Predicate;

constexpr DiagnosticPredicate(PredicateTy T) : Predicate(T) {}

explicit constexpr DiagnosticPredicate(bool Matches)
: Predicate(Matches ? Match : NearMatch) {}

explicit operator bool() const { return Predicate == Match; }

constexpr bool isMatch() const { return Predicate == Match; }
constexpr bool isNearMatch() const { return Predicate == NearMatch; }
constexpr bool isNoMatch() const { return Predicate == NoMatch; }
};

// When matching of an assembly instruction fails, there may be multiple
Expand Down
130 changes: 67 additions & 63 deletions llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -814,7 +814,9 @@ class AArch64Operand : public MCParsedAsmOperand {
return (Val >= 0 && Val < 64);
}

template <int Width> bool isSImm() const { return isSImmScaled<Width, 1>(); }
template <int Width> bool isSImm() const {
return bool(isSImmScaled<Width, 1>());
}

template <int Bits, int Scale> DiagnosticPredicate isSImmScaled() const {
return isImmScaled<Bits, Scale>(true);
Expand All @@ -824,7 +826,7 @@ class AArch64Operand : public MCParsedAsmOperand {
DiagnosticPredicate isUImmScaled() const {
if (IsRange && isImmRange() &&
(getLastImmVal() != getFirstImmVal() + Offset))
return DiagnosticPredicateTy::NoMatch;
return DiagnosticPredicate::NoMatch;

return isImmScaled<Bits, Scale, IsRange>(false);
}
Expand All @@ -833,15 +835,15 @@ class AArch64Operand : public MCParsedAsmOperand {
DiagnosticPredicate isImmScaled(bool Signed) const {
if ((!isImm() && !isImmRange()) || (isImm() && IsRange) ||
(isImmRange() && !IsRange))
return DiagnosticPredicateTy::NoMatch;
return DiagnosticPredicate::NoMatch;

int64_t Val;
if (isImmRange())
Val = getFirstImmVal();
else {
const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
if (!MCE)
return DiagnosticPredicateTy::NoMatch;
return DiagnosticPredicate::NoMatch;
Val = MCE->getValue();
}

Expand All @@ -856,33 +858,33 @@ class AArch64Operand : public MCParsedAsmOperand {
}

if (Val >= MinVal && Val <= MaxVal && (Val % Scale) == 0)
return DiagnosticPredicateTy::Match;
return DiagnosticPredicate::Match;

return DiagnosticPredicateTy::NearMatch;
return DiagnosticPredicate::NearMatch;
}

DiagnosticPredicate isSVEPattern() const {
if (!isImm())
return DiagnosticPredicateTy::NoMatch;
return DiagnosticPredicate::NoMatch;
auto *MCE = dyn_cast<MCConstantExpr>(getImm());
if (!MCE)
return DiagnosticPredicateTy::NoMatch;
return DiagnosticPredicate::NoMatch;
int64_t Val = MCE->getValue();
if (Val >= 0 && Val < 32)
return DiagnosticPredicateTy::Match;
return DiagnosticPredicateTy::NearMatch;
return DiagnosticPredicate::Match;
return DiagnosticPredicate::NearMatch;
}

DiagnosticPredicate isSVEVecLenSpecifier() const {
if (!isImm())
return DiagnosticPredicateTy::NoMatch;
return DiagnosticPredicate::NoMatch;
auto *MCE = dyn_cast<MCConstantExpr>(getImm());
if (!MCE)
return DiagnosticPredicateTy::NoMatch;
return DiagnosticPredicate::NoMatch;
int64_t Val = MCE->getValue();
if (Val >= 0 && Val <= 1)
return DiagnosticPredicateTy::Match;
return DiagnosticPredicateTy::NearMatch;
return DiagnosticPredicate::Match;
return DiagnosticPredicate::NearMatch;
}

bool isSymbolicUImm12Offset(const MCExpr *Expr) const {
Expand Down Expand Up @@ -1057,41 +1059,41 @@ class AArch64Operand : public MCParsedAsmOperand {
template <typename T>
DiagnosticPredicate isSVECpyImm() const {
if (!isShiftedImm() && (!isImm() || !isa<MCConstantExpr>(getImm())))
return DiagnosticPredicateTy::NoMatch;
return DiagnosticPredicate::NoMatch;

bool IsByte = std::is_same<int8_t, std::make_signed_t<T>>::value ||
std::is_same<int8_t, T>::value;
if (auto ShiftedImm = getShiftedVal<8>())
if (!(IsByte && ShiftedImm->second) &&
AArch64_AM::isSVECpyImm<T>(uint64_t(ShiftedImm->first)
<< ShiftedImm->second))
return DiagnosticPredicateTy::Match;
return DiagnosticPredicate::Match;

return DiagnosticPredicateTy::NearMatch;
return DiagnosticPredicate::NearMatch;
}

// Unsigned value in the range 0 to 255. For element widths of
// 16 bits or higher it may also be a signed multiple of 256 in the
// range 0 to 65280.
template <typename T> DiagnosticPredicate isSVEAddSubImm() const {
if (!isShiftedImm() && (!isImm() || !isa<MCConstantExpr>(getImm())))
return DiagnosticPredicateTy::NoMatch;
return DiagnosticPredicate::NoMatch;

bool IsByte = std::is_same<int8_t, std::make_signed_t<T>>::value ||
std::is_same<int8_t, T>::value;
if (auto ShiftedImm = getShiftedVal<8>())
if (!(IsByte && ShiftedImm->second) &&
AArch64_AM::isSVEAddSubImm<T>(ShiftedImm->first
<< ShiftedImm->second))
return DiagnosticPredicateTy::Match;
return DiagnosticPredicate::Match;

return DiagnosticPredicateTy::NearMatch;
return DiagnosticPredicate::NearMatch;
}

template <typename T> DiagnosticPredicate isSVEPreferredLogicalImm() const {
if (isLogicalImm<T>() && !isSVECpyImm<T>())
return DiagnosticPredicateTy::Match;
return DiagnosticPredicateTy::NoMatch;
return DiagnosticPredicate::Match;
return DiagnosticPredicate::NoMatch;
}

bool isCondCode() const { return Kind == k_CondCode; }
Expand Down Expand Up @@ -1319,48 +1321,48 @@ class AArch64Operand : public MCParsedAsmOperand {
template <int ElementWidth, unsigned Class>
DiagnosticPredicate isSVEPredicateVectorRegOfWidth() const {
if (Kind != k_Register || Reg.Kind != RegKind::SVEPredicateVector)
return DiagnosticPredicateTy::NoMatch;
return DiagnosticPredicate::NoMatch;

if (isSVEVectorReg<Class>() && (Reg.ElementWidth == ElementWidth))
return DiagnosticPredicateTy::Match;
return DiagnosticPredicate::Match;

return DiagnosticPredicateTy::NearMatch;
return DiagnosticPredicate::NearMatch;
}

template <int ElementWidth, unsigned Class>
DiagnosticPredicate isSVEPredicateOrPredicateAsCounterRegOfWidth() const {
if (Kind != k_Register || (Reg.Kind != RegKind::SVEPredicateAsCounter &&
Reg.Kind != RegKind::SVEPredicateVector))
return DiagnosticPredicateTy::NoMatch;
return DiagnosticPredicate::NoMatch;

if ((isSVEPredicateAsCounterReg<Class>() ||
isSVEPredicateVectorRegOfWidth<ElementWidth, Class>()) &&
Reg.ElementWidth == ElementWidth)
return DiagnosticPredicateTy::Match;
return DiagnosticPredicate::Match;

return DiagnosticPredicateTy::NearMatch;
return DiagnosticPredicate::NearMatch;
}

template <int ElementWidth, unsigned Class>
DiagnosticPredicate isSVEPredicateAsCounterRegOfWidth() const {
if (Kind != k_Register || Reg.Kind != RegKind::SVEPredicateAsCounter)
return DiagnosticPredicateTy::NoMatch;
return DiagnosticPredicate::NoMatch;

if (isSVEPredicateAsCounterReg<Class>() && (Reg.ElementWidth == ElementWidth))
return DiagnosticPredicateTy::Match;
return DiagnosticPredicate::Match;

return DiagnosticPredicateTy::NearMatch;
return DiagnosticPredicate::NearMatch;
}

template <int ElementWidth, unsigned Class>
DiagnosticPredicate isSVEDataVectorRegOfWidth() const {
if (Kind != k_Register || Reg.Kind != RegKind::SVEDataVector)
return DiagnosticPredicateTy::NoMatch;
return DiagnosticPredicate::NoMatch;

if (isSVEVectorReg<Class>() && Reg.ElementWidth == ElementWidth)
return DiagnosticPredicateTy::Match;
return DiagnosticPredicate::Match;

return DiagnosticPredicateTy::NearMatch;
return DiagnosticPredicate::NearMatch;
}

template <int ElementWidth, unsigned Class,
Expand All @@ -1369,7 +1371,7 @@ class AArch64Operand : public MCParsedAsmOperand {
DiagnosticPredicate isSVEDataVectorRegWithShiftExtend() const {
auto VectorMatch = isSVEDataVectorRegOfWidth<ElementWidth, Class>();
if (!VectorMatch.isMatch())
return DiagnosticPredicateTy::NoMatch;
return DiagnosticPredicate::NoMatch;

// Give a more specific diagnostic when the user has explicitly typed in
// a shift-amount that does not match what is expected, but for which
Expand All @@ -1378,12 +1380,12 @@ class AArch64Operand : public MCParsedAsmOperand {
if (!MatchShift && (ShiftExtendTy == AArch64_AM::UXTW ||
ShiftExtendTy == AArch64_AM::SXTW) &&
!ShiftWidthAlwaysSame && hasShiftExtendAmount() && ShiftWidth == 8)
return DiagnosticPredicateTy::NoMatch;
return DiagnosticPredicate::NoMatch;

if (MatchShift && ShiftExtendTy == getShiftExtendType())
return DiagnosticPredicateTy::Match;
return DiagnosticPredicate::Match;

return DiagnosticPredicateTy::NearMatch;
return DiagnosticPredicate::NearMatch;
}

bool isGPR32as64() const {
Expand Down Expand Up @@ -1420,15 +1422,17 @@ class AArch64Operand : public MCParsedAsmOperand {

template<int64_t Angle, int64_t Remainder>
DiagnosticPredicate isComplexRotation() const {
if (!isImm()) return DiagnosticPredicateTy::NoMatch;
if (!isImm())
return DiagnosticPredicate::NoMatch;

const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return DiagnosticPredicateTy::NoMatch;
if (!CE)
return DiagnosticPredicate::NoMatch;
uint64_t Value = CE->getValue();

if (Value % Angle == Remainder && Value <= 270)
return DiagnosticPredicateTy::Match;
return DiagnosticPredicateTy::NearMatch;
return DiagnosticPredicate::Match;
return DiagnosticPredicate::NearMatch;
}

template <unsigned RegClassID> bool isGPR64() const {
Expand All @@ -1439,12 +1443,12 @@ class AArch64Operand : public MCParsedAsmOperand {
template <unsigned RegClassID, int ExtWidth>
DiagnosticPredicate isGPR64WithShiftExtend() const {
if (Kind != k_Register || Reg.Kind != RegKind::Scalar)
return DiagnosticPredicateTy::NoMatch;
return DiagnosticPredicate::NoMatch;

if (isGPR64<RegClassID>() && getShiftExtendType() == AArch64_AM::LSL &&
getShiftExtendAmount() == Log2_32(ExtWidth / 8))
return DiagnosticPredicateTy::Match;
return DiagnosticPredicateTy::NearMatch;
return DiagnosticPredicate::Match;
return DiagnosticPredicate::NearMatch;
}

/// Is this a vector list with the type implicit (presumably attached to the
Expand Down Expand Up @@ -1479,10 +1483,10 @@ class AArch64Operand : public MCParsedAsmOperand {
bool Res =
isTypedVectorList<VectorKind, NumRegs, NumElements, ElementWidth>();
if (!Res)
return DiagnosticPredicateTy::NoMatch;
return DiagnosticPredicate::NoMatch;
if (!AArch64MCRegisterClasses[RegClass].contains(VectorList.RegNum))
return DiagnosticPredicateTy::NearMatch;
return DiagnosticPredicateTy::Match;
return DiagnosticPredicate::NearMatch;
return DiagnosticPredicate::Match;
}

template <RegKind VectorKind, unsigned NumRegs, unsigned Stride,
Expand All @@ -1491,21 +1495,21 @@ class AArch64Operand : public MCParsedAsmOperand {
bool Res = isTypedVectorList<VectorKind, NumRegs, /*NumElements*/ 0,
ElementWidth, Stride>();
if (!Res)
return DiagnosticPredicateTy::NoMatch;
return DiagnosticPredicate::NoMatch;
if ((VectorList.RegNum < (AArch64::Z0 + Stride)) ||
((VectorList.RegNum >= AArch64::Z16) &&
(VectorList.RegNum < (AArch64::Z16 + Stride))))
return DiagnosticPredicateTy::Match;
return DiagnosticPredicateTy::NoMatch;
return DiagnosticPredicate::Match;
return DiagnosticPredicate::NoMatch;
}

template <int Min, int Max>
DiagnosticPredicate isVectorIndex() const {
if (Kind != k_VectorIndex)
return DiagnosticPredicateTy::NoMatch;
return DiagnosticPredicate::NoMatch;
if (VectorIndex.Val >= Min && VectorIndex.Val <= Max)
return DiagnosticPredicateTy::Match;
return DiagnosticPredicateTy::NearMatch;
return DiagnosticPredicate::Match;
return DiagnosticPredicate::NearMatch;
}

bool isToken() const override { return Kind == k_Token; }
Expand All @@ -1531,7 +1535,7 @@ class AArch64Operand : public MCParsedAsmOperand {

template <unsigned ImmEnum> DiagnosticPredicate isExactFPImm() const {
if (Kind != k_FPImm)
return DiagnosticPredicateTy::NoMatch;
return DiagnosticPredicate::NoMatch;

if (getFPImmIsExact()) {
// Lookup the immediate from table of supported immediates.
Expand All @@ -1546,19 +1550,19 @@ class AArch64Operand : public MCParsedAsmOperand {
llvm_unreachable("FP immediate is not exact");

if (getFPImm().bitwiseIsEqual(RealVal))
return DiagnosticPredicateTy::Match;
return DiagnosticPredicate::Match;
}

return DiagnosticPredicateTy::NearMatch;
return DiagnosticPredicate::NearMatch;
}

template <unsigned ImmA, unsigned ImmB>
DiagnosticPredicate isExactFPImm() const {
DiagnosticPredicate Res = DiagnosticPredicateTy::NoMatch;
DiagnosticPredicate Res = DiagnosticPredicate::NoMatch;
if ((Res = isExactFPImm<ImmA>()))
return DiagnosticPredicateTy::Match;
return DiagnosticPredicate::Match;
if ((Res = isExactFPImm<ImmB>()))
return DiagnosticPredicateTy::Match;
return DiagnosticPredicate::Match;
return Res;
}

Expand Down Expand Up @@ -1741,12 +1745,12 @@ class AArch64Operand : public MCParsedAsmOperand {
template <MatrixKind Kind, unsigned EltSize, unsigned RegClass>
DiagnosticPredicate isMatrixRegOperand() const {
if (!isMatrix())
return DiagnosticPredicateTy::NoMatch;
return DiagnosticPredicate::NoMatch;
if (getMatrixKind() != Kind ||
!AArch64MCRegisterClasses[RegClass].contains(getMatrixReg()) ||
EltSize != getMatrixElementWidth())
return DiagnosticPredicateTy::NearMatch;
return DiagnosticPredicateTy::Match;
return DiagnosticPredicate::NearMatch;
return DiagnosticPredicate::Match;
}

bool isPAuthPCRelLabel16Operand() const {
Expand Down