[AsmParser] Add DiagnosticString to AsmOperands in tablegen

This adds a DiagnosticString member to the AsmOperand tablegen class, so
that the diagnostic text to be used when an assembly operand is
incorrect can be stored in the tablegen description of the operand,
rather than in a separate switch statement in the AsmParser.

If DiagnosticString is used for any operands, tablegen will emit a
getMatchKindDiag function, to map from diagnostic enums to strings.

Differential revision: https://reviews.llvm.org/D31606

llvm-svn: 314803
This commit is contained in:
Oliver Stannard 2017-10-03 14:34:57 +00:00
parent 085a23f187
commit 41dfac3eb2
2 changed files with 51 additions and 2 deletions

View File

@ -677,6 +677,10 @@ class AsmOperandClass {
// diagnostic. The target AsmParser maps these codes to text.
string DiagnosticType = "";
/// A diagnostic message to emit when an invalid value is provided for this
/// operand.
string DiagnosticString = "";
/// Set to 1 if this operand is optional and not always required. Typically,
/// the AsmParser will emit an error when it finishes parsing an
/// instruction if it hasn't matched all the operands yet. However, this

View File

@ -205,6 +205,9 @@ struct ClassInfo {
/// For custom match classes: the diagnostic kind for when the predicate fails.
std::string DiagnosticType;
/// For custom match classes: the diagnostic string for when the predicate fails.
std::string DiagnosticString;
/// Is this operand optional and not always required.
bool IsOptional;
@ -1357,11 +1360,17 @@ void AsmMatcherInfo::buildOperandClasses() {
if (StringInit *SI = dyn_cast<StringInit>(PRMName))
CI->ParserMethod = SI->getValue();
// Get the diagnostic type or leave it as empty.
// Get the parse method name or leave it as empty.
// Get the diagnostic type and string or leave them as empty.
Init *DiagnosticType = Rec->getValueInit("DiagnosticType");
if (StringInit *SI = dyn_cast<StringInit>(DiagnosticType))
CI->DiagnosticType = SI->getValue();
Init *DiagnosticString = Rec->getValueInit("DiagnosticString");
if (StringInit *SI = dyn_cast<StringInit>(DiagnosticString))
CI->DiagnosticString = SI->getValue();
// If we have a DiagnosticString, we need a DiagnosticType for use within
// the matcher.
if (!CI->DiagnosticString.empty() && CI->DiagnosticType.empty())
CI->DiagnosticType = CI->ClassName;
Init *IsOptional = Rec->getValueInit("IsOptional");
if (BitInit *BI = dyn_cast<BitInit>(IsOptional))
@ -2188,6 +2197,38 @@ static void emitMatchClassEnumeration(CodeGenTarget &Target,
OS << "}\n\n";
}
/// emitMatchClassDiagStrings - Emit a function to get the diagnostic text to be
/// used when an assembly operand does not match the expected operand class.
static void emitOperandMatchErrorDiagStrings(AsmMatcherInfo &Info, raw_ostream &OS) {
// If the target does not use DiagnosticString for any operands, don't emit
// an unused function.
if (std::all_of(
Info.Classes.begin(), Info.Classes.end(),
[](const ClassInfo &CI) { return CI.DiagnosticString.empty(); }))
return;
OS << "static const char *getMatchKindDiag(" << Info.Target.getName()
<< "AsmParser::" << Info.Target.getName()
<< "MatchResultTy MatchResult) {\n";
OS << " switch (MatchResult) {\n";
for (const auto &CI: Info.Classes) {
if (!CI.DiagnosticString.empty()) {
assert(!CI.DiagnosticType.empty() &&
"DiagnosticString set without DiagnosticType");
OS << " case " << Info.Target.getName()
<< "AsmParser::Match_" << CI.DiagnosticType << ":\n";
OS << " return \"" << CI.DiagnosticString << "\";\n";
}
}
OS << " default:\n";
OS << " return nullptr;\n";
OS << " }\n";
OS << "}\n\n";
}
/// emitValidateOperandClass - Emit the function to validate an operand class.
static void emitValidateOperandClass(AsmMatcherInfo &Info,
raw_ostream &OS) {
@ -2914,6 +2955,10 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
// Emit the enumeration for classes which participate in matching.
emitMatchClassEnumeration(Target, Info.Classes, OS);
// Emit a function to get the user-visible string to describe an operand
// match failure in diagnostics.
emitOperandMatchErrorDiagStrings(Info, OS);
// Emit the routine to match token strings to their match class.
emitMatchTokenString(Target, Info.Classes, OS);