mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-01 00:33:09 +00:00
TableGen: AsmMatcher support for better operand diagnostics.
"Invalid operand" may be a completely correct diagnostic, but it's often insufficiently specific to really help identify and fix the problem in assembly source. Allow a target to specify a more-specific diagnostic kind for each AsmOperandClass derived definition and use that to provide more detailed diagnostics when an operant of that class resulted in a match failure. rdar://8987109 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@159050 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
009f7afbeb
commit
4dbfdfba6c
@ -523,6 +523,11 @@ class AsmOperandClass {
|
|||||||
/// to immediates or registers and are very instruction specific (as flags to
|
/// to immediates or registers and are very instruction specific (as flags to
|
||||||
/// set in a processor register, coprocessor number, ...).
|
/// set in a processor register, coprocessor number, ...).
|
||||||
string ParserMethod = ?;
|
string ParserMethod = ?;
|
||||||
|
|
||||||
|
// The diagnostic type to present when referencing this operand in a
|
||||||
|
// match failure error message. By default, use a generic "invalid operand"
|
||||||
|
// diagnostic. The target AsmParser maps these codes to text.
|
||||||
|
string DiagnosticType = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
def ImmAsmOperand : AsmOperandClass {
|
def ImmAsmOperand : AsmOperandClass {
|
||||||
|
@ -186,6 +186,8 @@ struct ClassInfo {
|
|||||||
/// For register classes, the records for all the registers in this class.
|
/// For register classes, the records for all the registers in this class.
|
||||||
std::set<Record*> Registers;
|
std::set<Record*> Registers;
|
||||||
|
|
||||||
|
/// For custom match classes, he diagnostic kind for when the predicate fails.
|
||||||
|
std::string DiagnosticType;
|
||||||
public:
|
public:
|
||||||
/// isRegisterClass() - Check if this is a register class.
|
/// isRegisterClass() - Check if this is a register class.
|
||||||
bool isRegisterClass() const {
|
bool isRegisterClass() const {
|
||||||
@ -593,6 +595,9 @@ public:
|
|||||||
/// Map of Predicate records to their subtarget information.
|
/// Map of Predicate records to their subtarget information.
|
||||||
std::map<Record*, SubtargetFeatureInfo*> SubtargetFeatures;
|
std::map<Record*, SubtargetFeatureInfo*> SubtargetFeatures;
|
||||||
|
|
||||||
|
/// Map of AsmOperandClass records to their class information.
|
||||||
|
std::map<Record*, ClassInfo*> AsmOperandClasses;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Map of token to class information which has already been constructed.
|
/// Map of token to class information which has already been constructed.
|
||||||
std::map<std::string, ClassInfo*> TokenClasses;
|
std::map<std::string, ClassInfo*> TokenClasses;
|
||||||
@ -600,9 +605,6 @@ private:
|
|||||||
/// Map of RegisterClass records to their class information.
|
/// Map of RegisterClass records to their class information.
|
||||||
std::map<Record*, ClassInfo*> RegisterClassClasses;
|
std::map<Record*, ClassInfo*> RegisterClassClasses;
|
||||||
|
|
||||||
/// Map of AsmOperandClass records to their class information.
|
|
||||||
std::map<Record*, ClassInfo*> AsmOperandClasses;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// getTokenClass - Lookup or create the class for the given token.
|
/// getTokenClass - Lookup or create the class for the given token.
|
||||||
ClassInfo *getTokenClass(StringRef Token);
|
ClassInfo *getTokenClass(StringRef Token);
|
||||||
@ -960,6 +962,7 @@ ClassInfo *AsmMatcherInfo::getTokenClass(StringRef Token) {
|
|||||||
Entry->PredicateMethod = "<invalid>";
|
Entry->PredicateMethod = "<invalid>";
|
||||||
Entry->RenderMethod = "<invalid>";
|
Entry->RenderMethod = "<invalid>";
|
||||||
Entry->ParserMethod = "";
|
Entry->ParserMethod = "";
|
||||||
|
Entry->DiagnosticType = "";
|
||||||
Classes.push_back(Entry);
|
Classes.push_back(Entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1085,6 +1088,8 @@ buildRegisterClasses(SmallPtrSet<Record*, 16> &SingletonRegisters) {
|
|||||||
CI->PredicateMethod = ""; // unused
|
CI->PredicateMethod = ""; // unused
|
||||||
CI->RenderMethod = "addRegOperands";
|
CI->RenderMethod = "addRegOperands";
|
||||||
CI->Registers = *it;
|
CI->Registers = *it;
|
||||||
|
// FIXME: diagnostic type.
|
||||||
|
CI->DiagnosticType = "";
|
||||||
Classes.push_back(CI);
|
Classes.push_back(CI);
|
||||||
RegisterSetClasses.insert(std::make_pair(*it, CI));
|
RegisterSetClasses.insert(std::make_pair(*it, CI));
|
||||||
}
|
}
|
||||||
@ -1200,6 +1205,12 @@ void AsmMatcherInfo::buildOperandClasses() {
|
|||||||
if (StringInit *SI = dynamic_cast<StringInit*>(PRMName))
|
if (StringInit *SI = dynamic_cast<StringInit*>(PRMName))
|
||||||
CI->ParserMethod = SI->getValue();
|
CI->ParserMethod = SI->getValue();
|
||||||
|
|
||||||
|
// Get the diagnostic type or leave it as empty.
|
||||||
|
// Get the parse method name or leave it as empty.
|
||||||
|
Init *DiagnosticType = (*it)->getValueInit("DiagnosticType");
|
||||||
|
if (StringInit *SI = dynamic_cast<StringInit*>(DiagnosticType))
|
||||||
|
CI->DiagnosticType = SI->getValue();
|
||||||
|
|
||||||
AsmOperandClasses[*it] = CI;
|
AsmOperandClasses[*it] = CI;
|
||||||
Classes.push_back(CI);
|
Classes.push_back(CI);
|
||||||
}
|
}
|
||||||
@ -1802,19 +1813,21 @@ static void emitMatchClassEnumeration(CodeGenTarget &Target,
|
|||||||
/// emitValidateOperandClass - Emit the function to validate an operand class.
|
/// emitValidateOperandClass - Emit the function to validate an operand class.
|
||||||
static void emitValidateOperandClass(AsmMatcherInfo &Info,
|
static void emitValidateOperandClass(AsmMatcherInfo &Info,
|
||||||
raw_ostream &OS) {
|
raw_ostream &OS) {
|
||||||
OS << "static bool validateOperandClass(MCParsedAsmOperand *GOp, "
|
OS << "static unsigned validateOperandClass(MCParsedAsmOperand *GOp, "
|
||||||
<< "MatchClassKind Kind) {\n";
|
<< "MatchClassKind Kind) {\n";
|
||||||
OS << " " << Info.Target.getName() << "Operand &Operand = *("
|
OS << " " << Info.Target.getName() << "Operand &Operand = *("
|
||||||
<< Info.Target.getName() << "Operand*)GOp;\n";
|
<< Info.Target.getName() << "Operand*)GOp;\n";
|
||||||
|
|
||||||
// The InvalidMatchClass is not to match any operand.
|
// The InvalidMatchClass is not to match any operand.
|
||||||
OS << " if (Kind == InvalidMatchClass)\n";
|
OS << " if (Kind == InvalidMatchClass)\n";
|
||||||
OS << " return false;\n\n";
|
OS << " return MCTargetAsmParser::Match_InvalidOperand;\n\n";
|
||||||
|
|
||||||
// Check for Token operands first.
|
// Check for Token operands first.
|
||||||
|
// FIXME: Use a more specific diagnostic type.
|
||||||
OS << " if (Operand.isToken())\n";
|
OS << " if (Operand.isToken())\n";
|
||||||
OS << " return isSubclass(matchTokenString(Operand.getToken()), Kind);"
|
OS << " return isSubclass(matchTokenString(Operand.getToken()), Kind) ?\n"
|
||||||
<< "\n\n";
|
<< " MCTargetAsmParser::Match_Success :\n"
|
||||||
|
<< " MCTargetAsmParser::Match_InvalidOperand;\n\n";
|
||||||
|
|
||||||
// Check for register operands, including sub-classes.
|
// Check for register operands, including sub-classes.
|
||||||
OS << " if (Operand.isReg()) {\n";
|
OS << " if (Operand.isReg()) {\n";
|
||||||
@ -1828,8 +1841,9 @@ static void emitValidateOperandClass(AsmMatcherInfo &Info,
|
|||||||
<< it->first->getName() << ": OpKind = " << it->second->Name
|
<< it->first->getName() << ": OpKind = " << it->second->Name
|
||||||
<< "; break;\n";
|
<< "; break;\n";
|
||||||
OS << " }\n";
|
OS << " }\n";
|
||||||
OS << " return isSubclass(OpKind, Kind);\n";
|
OS << " return isSubclass(OpKind, Kind) ? "
|
||||||
OS << " }\n\n";
|
<< "MCTargetAsmParser::Match_Success :\n "
|
||||||
|
<< " MCTargetAsmParser::Match_InvalidOperand;\n }\n\n";
|
||||||
|
|
||||||
// Check the user classes. We don't care what order since we're only
|
// Check the user classes. We don't care what order since we're only
|
||||||
// actually matching against one of them.
|
// actually matching against one of them.
|
||||||
@ -1841,13 +1855,18 @@ static void emitValidateOperandClass(AsmMatcherInfo &Info,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
OS << " // '" << CI.ClassName << "' class\n";
|
OS << " // '" << CI.ClassName << "' class\n";
|
||||||
OS << " if (Kind == " << CI.Name
|
OS << " if (Kind == " << CI.Name << ") {\n";
|
||||||
<< " && Operand." << CI.PredicateMethod << "()) {\n";
|
OS << " if (Operand." << CI.PredicateMethod << "())\n";
|
||||||
OS << " return true;\n";
|
OS << " return MCTargetAsmParser::Match_Success;\n";
|
||||||
|
if (!CI.DiagnosticType.empty())
|
||||||
|
OS << " return " << Info.Target.getName() << "AsmParser::Match_"
|
||||||
|
<< CI.DiagnosticType << ";\n";
|
||||||
OS << " }\n\n";
|
OS << " }\n\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
OS << " return false;\n";
|
// Generic fallthrough match failure case for operands that don't have
|
||||||
|
// specialized diagnostic types.
|
||||||
|
OS << " return MCTargetAsmParser::Match_InvalidOperand;\n";
|
||||||
OS << "}\n\n";
|
OS << "}\n\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1963,6 +1982,26 @@ static void emitSubtargetFeatureFlagEnumeration(AsmMatcherInfo &Info,
|
|||||||
OS << "};\n\n";
|
OS << "};\n\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// emitOperandDiagnosticTypes - Emit the operand matching diagnostic types.
|
||||||
|
static void emitOperandDiagnosticTypes(AsmMatcherInfo &Info, raw_ostream &OS) {
|
||||||
|
// Get the set of diagnostic types from all of the operand classes.
|
||||||
|
std::set<StringRef> Types;
|
||||||
|
for (std::map<Record*, ClassInfo*>::const_iterator
|
||||||
|
I = Info.AsmOperandClasses.begin(),
|
||||||
|
E = Info.AsmOperandClasses.end(); I != E; ++I) {
|
||||||
|
if (!I->second->DiagnosticType.empty())
|
||||||
|
Types.insert(I->second->DiagnosticType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Types.empty()) return;
|
||||||
|
|
||||||
|
// Now emit the enum entries.
|
||||||
|
for (std::set<StringRef>::const_iterator I = Types.begin(), E = Types.end();
|
||||||
|
I != E; ++I)
|
||||||
|
OS << " Match_" << *I << ",\n";
|
||||||
|
OS << " END_OPERAND_DIAGNOSTIC_TYPES\n";
|
||||||
|
}
|
||||||
|
|
||||||
/// emitGetSubtargetFeatureName - Emit the helper function to get the
|
/// emitGetSubtargetFeatureName - Emit the helper function to get the
|
||||||
/// user-level name for a subtarget feature.
|
/// user-level name for a subtarget feature.
|
||||||
static void emitGetSubtargetFeatureName(AsmMatcherInfo &Info, raw_ostream &OS) {
|
static void emitGetSubtargetFeatureName(AsmMatcherInfo &Info, raw_ostream &OS) {
|
||||||
@ -2394,6 +2433,13 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
|
|||||||
|
|
||||||
OS << "#endif // GET_ASSEMBLER_HEADER_INFO\n\n";
|
OS << "#endif // GET_ASSEMBLER_HEADER_INFO\n\n";
|
||||||
|
|
||||||
|
// Emit the operand match diagnostic enum names.
|
||||||
|
OS << "\n#ifdef GET_OPERAND_DIAGNOSTIC_TYPES\n";
|
||||||
|
OS << "#undef GET_OPERAND_DIAGNOSTIC_TYPES\n\n";
|
||||||
|
emitOperandDiagnosticTypes(Info, OS);
|
||||||
|
OS << "#endif // GET_OPERAND_DIAGNOSTIC_TYPES\n\n";
|
||||||
|
|
||||||
|
|
||||||
OS << "\n#ifdef GET_REGISTER_MATCHER\n";
|
OS << "\n#ifdef GET_REGISTER_MATCHER\n";
|
||||||
OS << "#undef GET_REGISTER_MATCHER\n\n";
|
OS << "#undef GET_REGISTER_MATCHER\n\n";
|
||||||
|
|
||||||
@ -2605,13 +2651,20 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
|
|||||||
OS << " OperandsValid = (it->Classes[i] == " <<"InvalidMatchClass);\n";
|
OS << " OperandsValid = (it->Classes[i] == " <<"InvalidMatchClass);\n";
|
||||||
OS << " break;\n";
|
OS << " break;\n";
|
||||||
OS << " }\n";
|
OS << " }\n";
|
||||||
OS << " if (validateOperandClass(Operands[i+1], "
|
OS << " unsigned Diag = validateOperandClass(Operands[i+1],\n";
|
||||||
"(MatchClassKind)it->Classes[i]))\n";
|
OS.indent(43);
|
||||||
|
OS << "(MatchClassKind)it->Classes[i]);\n";
|
||||||
|
OS << " if (Diag == Match_Success)\n";
|
||||||
OS << " continue;\n";
|
OS << " continue;\n";
|
||||||
OS << " // If this operand is broken for all of the instances of this\n";
|
OS << " // If this operand is broken for all of the instances of this\n";
|
||||||
OS << " // mnemonic, keep track of it so we can report loc info.\n";
|
OS << " // mnemonic, keep track of it so we can report loc info.\n";
|
||||||
OS << " if (it == MnemonicRange.first || ErrorInfo <= i+1)\n";
|
OS << " // If we already had a match that only failed due to a\n";
|
||||||
|
OS << " // target predicate, that diagnostic is preferred.\n";
|
||||||
|
OS << " if (!HadMatchOtherThanPredicate &&\n";
|
||||||
|
OS << " (it == MnemonicRange.first || ErrorInfo <= i+1)) {\n";
|
||||||
OS << " ErrorInfo = i+1;\n";
|
OS << " ErrorInfo = i+1;\n";
|
||||||
|
OS << " RetCode = Diag;\n";
|
||||||
|
OS << " }\n";
|
||||||
OS << " // Otherwise, just reject this instance of the mnemonic.\n";
|
OS << " // Otherwise, just reject this instance of the mnemonic.\n";
|
||||||
OS << " OperandsValid = false;\n";
|
OS << " OperandsValid = false;\n";
|
||||||
OS << " break;\n";
|
OS << " break;\n";
|
||||||
|
Loading…
Reference in New Issue
Block a user