//
//===----------------------------------------------------------------------===//
-#include "AsmMatcherEmitter.h"
#include "CodeGenTarget.h"
-#include "StringMatcher.h"
#include "StringToOffsetTable.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/StringMatcher.h"
+#include "llvm/TableGen/TableGenBackend.h"
+#include <cassert>
#include <map>
#include <set>
using namespace llvm;
class AsmMatcherInfo;
struct SubtargetFeatureInfo;
+class AsmMatcherEmitter {
+ RecordKeeper &Records;
+public:
+ AsmMatcherEmitter(RecordKeeper &R) : Records(R) {}
+
+ void run(raw_ostream &o);
+};
+
/// ClassInfo - Helper class for storing the information about a particular
/// class of operands which can be matched.
struct ClassInfo {
/// For register classes, the records for all the registers in this class.
std::set<Record*> Registers;
+ /// For custom match classes, he diagnostic kind for when the predicate fails.
+ std::string DiagnosticType;
public:
/// isRegisterClass() - Check if this is a register class.
bool isRegisterClass() const {
/// Map of Predicate records to their subtarget information.
std::map<Record*, SubtargetFeatureInfo*> SubtargetFeatures;
+ /// Map of AsmOperandClass records to their class information.
+ std::map<Record*, ClassInfo*> AsmOperandClasses;
+
private:
/// Map of token to class information which has already been constructed.
std::map<std::string, ClassInfo*> TokenClasses;
/// Map of RegisterClass records to their class information.
std::map<Record*, ClassInfo*> RegisterClassClasses;
- /// Map of AsmOperandClass records to their class information.
- std::map<Record*, ClassInfo*> AsmOperandClasses;
-
private:
/// getTokenClass - Lookup or create the class for the given token.
ClassInfo *getTokenClass(StringRef Token);
}
};
-}
+} // End anonymous namespace
void MatchableInfo::dump() {
errs() << TheDef->getName() << " -- " << "flattened:\"" << AsmString <<"\"\n";
throw TGError(TheDef->getLoc(),
"Instruction '" + TheDef->getName() + "' has no tokens");
Mnemonic = AsmOperands[0].Token;
+ if (Mnemonic.empty())
+ throw TGError(TheDef->getLoc(),
+ "Missing instruction mnemonic");
// FIXME : Check and raise an error if it is a register.
if (Mnemonic[0] == '$')
throw TGError(TheDef->getLoc(),
Entry->PredicateMethod = "<invalid>";
Entry->RenderMethod = "<invalid>";
Entry->ParserMethod = "";
+ Entry->DiagnosticType = "";
Classes.push_back(Entry);
}
CI->PredicateMethod = ""; // unused
CI->RenderMethod = "addRegOperands";
CI->Registers = *it;
+ // FIXME: diagnostic type.
+ CI->DiagnosticType = "";
Classes.push_back(CI);
RegisterSetClasses.insert(std::make_pair(*it, CI));
}
if (StringInit *SI = dynamic_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.
+ Init *DiagnosticType = (*it)->getValueInit("DiagnosticType");
+ if (StringInit *SI = dynamic_cast<StringInit*>(DiagnosticType))
+ CI->DiagnosticType = SI->getValue();
+
AsmOperandClasses[*it] = CI;
Classes.push_back(CI);
}
/// emitValidateOperandClass - Emit the function to validate an operand class.
static void emitValidateOperandClass(AsmMatcherInfo &Info,
raw_ostream &OS) {
- OS << "static bool validateOperandClass(MCParsedAsmOperand *GOp, "
+ OS << "static unsigned validateOperandClass(MCParsedAsmOperand *GOp, "
<< "MatchClassKind Kind) {\n";
OS << " " << Info.Target.getName() << "Operand &Operand = *("
<< Info.Target.getName() << "Operand*)GOp;\n";
// The InvalidMatchClass is not to match any operand.
OS << " if (Kind == InvalidMatchClass)\n";
- OS << " return false;\n\n";
+ OS << " return MCTargetAsmParser::Match_InvalidOperand;\n\n";
// Check for Token operands first.
+ // FIXME: Use a more specific diagnostic type.
OS << " if (Operand.isToken())\n";
- OS << " return isSubclass(matchTokenString(Operand.getToken()), Kind);"
- << "\n\n";
-
- // Check for register operands, including sub-classes.
- OS << " if (Operand.isReg()) {\n";
- OS << " MatchClassKind OpKind;\n";
- OS << " switch (Operand.getReg()) {\n";
- OS << " default: OpKind = InvalidMatchClass; break;\n";
- for (std::map<Record*, ClassInfo*>::iterator
- it = Info.RegisterClasses.begin(), ie = Info.RegisterClasses.end();
- it != ie; ++it)
- OS << " case " << Info.Target.getName() << "::"
- << it->first->getName() << ": OpKind = " << it->second->Name
- << "; break;\n";
- OS << " }\n";
- OS << " return isSubclass(OpKind, Kind);\n";
- OS << " }\n\n";
+ OS << " return isSubclass(matchTokenString(Operand.getToken()), Kind) ?\n"
+ << " MCTargetAsmParser::Match_Success :\n"
+ << " MCTargetAsmParser::Match_InvalidOperand;\n\n";
// Check the user classes. We don't care what order since we're only
// actually matching against one of them.
continue;
OS << " // '" << CI.ClassName << "' class\n";
- OS << " if (Kind == " << CI.Name
- << " && Operand." << CI.PredicateMethod << "()) {\n";
- OS << " return true;\n";
+ OS << " if (Kind == " << CI.Name << ") {\n";
+ OS << " if (Operand." << CI.PredicateMethod << "())\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 << " return false;\n";
+ // Check for register operands, including sub-classes.
+ OS << " if (Operand.isReg()) {\n";
+ OS << " MatchClassKind OpKind;\n";
+ OS << " switch (Operand.getReg()) {\n";
+ OS << " default: OpKind = InvalidMatchClass; break;\n";
+ for (std::map<Record*, ClassInfo*>::iterator
+ it = Info.RegisterClasses.begin(), ie = Info.RegisterClasses.end();
+ it != ie; ++it)
+ OS << " case " << Info.Target.getName() << "::"
+ << it->first->getName() << ": OpKind = " << it->second->Name
+ << "; break;\n";
+ OS << " }\n";
+ OS << " return isSubclass(OpKind, Kind) ? "
+ << "MCTargetAsmParser::Match_Success :\n "
+ << " MCTargetAsmParser::Match_InvalidOperand;\n }\n\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";
}
+/// 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
/// user-level name for a subtarget feature.
static void emitGetSubtargetFeatureName(AsmMatcherInfo &Info, raw_ostream &OS) {
// Write the output.
- EmitSourceFileHeader("Assembly Matcher Source Fragment", OS);
-
// Information for the class declaration.
OS << "\n#ifdef GET_ASSEMBLER_HEADER\n";
OS << "#undef GET_ASSEMBLER_HEADER\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 << "#undef GET_REGISTER_MATCHER\n\n";
emitSubtargetFeatureFlagEnumeration(Info, OS);
// Emit the function to match a register name to number.
- emitMatchRegisterName(Target, AsmParser, OS);
+ // This should be omitted for Mips target
+ if (AsmParser->getValueAsBit("ShouldEmitMatchRegisterName"))
+ emitMatchRegisterName(Target, AsmParser, OS);
OS << "#endif // GET_REGISTER_MATCHER\n\n";
-
- OS << "\n#ifdef GET_MATCHER_IMPLEMENTATION\n";
- OS << "#undef GET_MATCHER_IMPLEMENTATION\n\n";
+ OS << "\n#ifdef GET_SUBTARGET_FEATURE_NAME\n";
+ OS << "#undef GET_SUBTARGET_FEATURE_NAME\n\n";
// Generate the helper function to get the names for subtarget features.
emitGetSubtargetFeatureName(Info, OS);
+ OS << "#endif // GET_SUBTARGET_FEATURE_NAME\n\n";
+
+ OS << "\n#ifdef GET_MATCHER_IMPLEMENTATION\n";
+ OS << "#undef GET_MATCHER_IMPLEMENTATION\n\n";
+
// Generate the function that remaps for mnemonic aliases.
bool HasMnemonicAliases = emitMnemonicAliases(OS, Info);
OS << " bool HadMatchOtherThanFeatures = false;\n";
OS << " bool HadMatchOtherThanPredicate = false;\n";
OS << " unsigned RetCode = Match_InvalidOperand;\n";
+ OS << " unsigned MissingFeatures = ~0U;\n";
OS << " // Set ErrorInfo to the operand that mismatches if it is\n";
OS << " // wrong for all instances of the instruction.\n";
OS << " ErrorInfo = ~0U;\n";
OS << " for (unsigned i = 0; i != " << MaxNumOperands << "; ++i) {\n";
OS << " if (i + 1 >= Operands.size()) {\n";
OS << " OperandsValid = (it->Classes[i] == " <<"InvalidMatchClass);\n";
+ OS << " if (!OperandsValid) ErrorInfo = i + 1;\n";
OS << " break;\n";
OS << " }\n";
- OS << " if (validateOperandClass(Operands[i+1], "
- "(MatchClassKind)it->Classes[i]))\n";
+ OS << " unsigned Diag = validateOperandClass(Operands[i+1],\n";
+ OS.indent(43);
+ OS << "(MatchClassKind)it->Classes[i]);\n";
+ OS << " if (Diag == Match_Success)\n";
OS << " continue;\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 << " 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 << " // InvalidOperand is the default. Prefer specificity.\n";
+ OS << " if (Diag != Match_InvalidOperand)\n";
+ OS << " RetCode = Diag;\n";
+ OS << " }\n";
OS << " // Otherwise, just reject this instance of the mnemonic.\n";
OS << " OperandsValid = false;\n";
OS << " break;\n";
OS << " if ((AvailableFeatures & it->RequiredFeatures) "
<< "!= it->RequiredFeatures) {\n";
OS << " HadMatchOtherThanFeatures = true;\n";
- OS << " ErrorInfo = it->RequiredFeatures & ~AvailableFeatures;\n";
+ OS << " unsigned NewMissingFeatures = it->RequiredFeatures & "
+ "~AvailableFeatures;\n";
+ OS << " if (CountPopulation_32(NewMissingFeatures) <= "
+ "CountPopulation_32(MissingFeatures))\n";
+ OS << " MissingFeatures = NewMissingFeatures;\n";
OS << " continue;\n";
OS << " }\n";
OS << "\n";
OS << " // Okay, we had no match. Try to return a useful error code.\n";
OS << " if (HadMatchOtherThanPredicate || !HadMatchOtherThanFeatures)";
- OS << " return RetCode;\n";
- OS << " assert(ErrorInfo && \"missing feature(s) but what?!\");";
+ OS << " return RetCode;\n";
+ OS << " // Missing feature matches return which features were missing\n";
+ OS << " ErrorInfo = MissingFeatures;\n";
OS << " return Match_MissingFeature;\n";
OS << "}\n\n";
OS << "#endif // GET_MATCHER_IMPLEMENTATION\n\n";
}
+
+namespace llvm {
+
+void EmitAsmMatcher(RecordKeeper &RK, raw_ostream &OS) {
+ emitSourceFileHeader("Assembly Matcher Source Fragment", OS);
+ AsmMatcherEmitter(RK).run(OS);
+}
+
+} // End llvm namespace