aboutsummaryrefslogtreecommitdiff
path: root/utils/TableGen/AsmMatcherEmitter.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2012-08-15 19:34:23 +0000
committerDimitry Andric <dim@FreeBSD.org>2012-08-15 19:34:23 +0000
commit58b69754af0cbff56b1cfce9be9392e4451f6628 (patch)
treeeacfc83d988e4b9d11114387ae7dc41243f2a363 /utils/TableGen/AsmMatcherEmitter.cpp
parent0378662f5bd3dbe8305a485b0282bceb8b52f465 (diff)
downloadsrc-58b69754af0cbff56b1cfce9be9392e4451f6628.tar.gz
src-58b69754af0cbff56b1cfce9be9392e4451f6628.zip
Notes
Diffstat (limited to 'utils/TableGen/AsmMatcherEmitter.cpp')
-rw-r--r--utils/TableGen/AsmMatcherEmitter.cpp458
1 files changed, 331 insertions, 127 deletions
diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp
index dc92a6c218e9..026d47f4bd77 100644
--- a/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/utils/TableGen/AsmMatcherEmitter.cpp
@@ -96,9 +96,7 @@
//
//===----------------------------------------------------------------------===//
-#include "AsmMatcherEmitter.h"
#include "CodeGenTarget.h"
-#include "StringMatcher.h"
#include "StringToOffsetTable.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/PointerUnion.h"
@@ -111,6 +109,9 @@
#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;
@@ -123,6 +124,14 @@ namespace {
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 {
@@ -177,6 +186,8 @@ 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 {
@@ -385,7 +396,7 @@ struct MatchableInfo {
/// ResOperands - This is the operand list that should be built for the result
/// MCInst.
- std::vector<ResOperand> ResOperands;
+ SmallVector<ResOperand, 8> ResOperands;
/// AsmString - The assembly string for this instruction (with variants
/// removed), e.g. "movsx $src, $dst".
@@ -399,7 +410,7 @@ struct MatchableInfo {
/// annotated with a class and where in the OperandList they were defined.
/// This directly corresponds to the tokenized AsmString after the mnemonic is
/// removed.
- SmallVector<AsmOperand, 4> AsmOperands;
+ SmallVector<AsmOperand, 8> AsmOperands;
/// Predicates - The required subtarget features to match this instruction.
SmallVector<SubtargetFeatureInfo*, 4> RequiredFeatures;
@@ -419,13 +430,17 @@ struct MatchableInfo {
AsmString(Alias->AsmString) {
}
- void Initialize(const AsmMatcherInfo &Info,
+ // Two-operand aliases clone from the main matchable, but mark the second
+ // operand as a tied operand of the first for purposes of the assembler.
+ void formTwoOperandAlias(StringRef Constraint);
+
+ void initialize(const AsmMatcherInfo &Info,
SmallPtrSet<Record*, 16> &SingletonRegisters,
int AsmVariantNo, std::string &RegisterPrefix);
- /// Validate - Return true if this matchable is a valid thing to match against
+ /// validate - Return true if this matchable is a valid thing to match against
/// and perform a bunch of validity checking.
- bool Validate(StringRef CommentDelimiter, bool Hack) const;
+ bool validate(StringRef CommentDelimiter, bool Hack) const;
/// extractSingletonRegisterForAsmOperand - Extract singleton register,
/// if present, from specified token.
@@ -433,9 +448,9 @@ struct MatchableInfo {
extractSingletonRegisterForAsmOperand(unsigned i, const AsmMatcherInfo &Info,
std::string &RegisterPrefix);
- /// FindAsmOperand - Find the AsmOperand with the specified name and
+ /// findAsmOperand - Find the AsmOperand with the specified name and
/// suboperand index.
- int FindAsmOperand(StringRef N, int SubOpIdx) const {
+ int findAsmOperand(StringRef N, int SubOpIdx) const {
for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i)
if (N == AsmOperands[i].SrcOpName &&
SubOpIdx == AsmOperands[i].SubOpIdx)
@@ -443,17 +458,17 @@ struct MatchableInfo {
return -1;
}
- /// FindAsmOperandNamed - Find the first AsmOperand with the specified name.
+ /// findAsmOperandNamed - Find the first AsmOperand with the specified name.
/// This does not check the suboperand index.
- int FindAsmOperandNamed(StringRef N) const {
+ int findAsmOperandNamed(StringRef N) const {
for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i)
if (N == AsmOperands[i].SrcOpName)
return i;
return -1;
}
- void BuildInstructionResultOperands();
- void BuildAliasResultOperands();
+ void buildInstructionResultOperands();
+ void buildAliasResultOperands();
/// operator< - Compare two matchables.
bool operator<(const MatchableInfo &RHS) const {
@@ -465,7 +480,7 @@ struct MatchableInfo {
return AsmOperands.size() < RHS.AsmOperands.size();
// Compare lexicographically by operand. The matcher validates that other
- // orderings wouldn't be ambiguous using \see CouldMatchAmbiguouslyWith().
+ // orderings wouldn't be ambiguous using \see couldMatchAmbiguouslyWith().
for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) {
if (*AsmOperands[i].Class < *RHS.AsmOperands[i].Class)
return true;
@@ -476,10 +491,10 @@ struct MatchableInfo {
return false;
}
- /// CouldMatchAmbiguouslyWith - Check whether this matchable could
+ /// couldMatchAmbiguouslyWith - Check whether this matchable could
/// ambiguously match the same set of operands as \arg RHS (without being a
/// strictly superior match).
- bool CouldMatchAmbiguouslyWith(const MatchableInfo &RHS) {
+ bool couldMatchAmbiguouslyWith(const MatchableInfo &RHS) {
// The primary comparator is the instruction mnemonic.
if (Mnemonic != RHS.Mnemonic)
return false;
@@ -518,7 +533,7 @@ struct MatchableInfo {
void dump();
private:
- void TokenizeAsmString(const AsmMatcherInfo &Info);
+ void tokenizeAsmString(const AsmMatcherInfo &Info);
};
/// SubtargetFeatureInfo - Helper class for storing information on a subtarget
@@ -543,7 +558,7 @@ struct OperandMatchEntry {
MatchableInfo* MI;
ClassInfo *CI;
- static OperandMatchEntry Create(MatchableInfo* mi, ClassInfo *ci,
+ static OperandMatchEntry create(MatchableInfo* mi, ClassInfo *ci,
unsigned opMask) {
OperandMatchEntry X;
X.OperandMask = opMask;
@@ -580,6 +595,9 @@ public:
/// 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;
@@ -587,9 +605,6 @@ private:
/// 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);
@@ -599,17 +614,17 @@ private:
int SubOpIdx);
ClassInfo *getOperandClass(Record *Rec, int SubOpIdx);
- /// BuildRegisterClasses - Build the ClassInfo* instances for register
+ /// buildRegisterClasses - Build the ClassInfo* instances for register
/// classes.
- void BuildRegisterClasses(SmallPtrSet<Record*, 16> &SingletonRegisters);
+ void buildRegisterClasses(SmallPtrSet<Record*, 16> &SingletonRegisters);
- /// BuildOperandClasses - Build the ClassInfo* instances for user defined
+ /// buildOperandClasses - Build the ClassInfo* instances for user defined
/// operand classes.
- void BuildOperandClasses();
+ void buildOperandClasses();
- void BuildInstructionOperandReference(MatchableInfo *II, StringRef OpName,
+ void buildInstructionOperandReference(MatchableInfo *II, StringRef OpName,
unsigned AsmOpIdx);
- void BuildAliasOperandReference(MatchableInfo *II, StringRef OpName,
+ void buildAliasOperandReference(MatchableInfo *II, StringRef OpName,
MatchableInfo::AsmOperand &Op);
public:
@@ -617,12 +632,12 @@ public:
CodeGenTarget &Target,
RecordKeeper &Records);
- /// BuildInfo - Construct the various tables used during matching.
- void BuildInfo();
+ /// buildInfo - Construct the various tables used during matching.
+ void buildInfo();
- /// BuildOperandMatchInfo - Build the necessary information to handle user
+ /// buildOperandMatchInfo - Build the necessary information to handle user
/// defined operand parsing methods.
- void BuildOperandMatchInfo();
+ void buildOperandMatchInfo();
/// getSubtargetFeature - Lookup or create the subtarget feature info for the
/// given operand.
@@ -638,7 +653,7 @@ public:
}
};
-}
+} // End anonymous namespace
void MatchableInfo::dump() {
errs() << TheDef->getName() << " -- " << "flattened:\"" << AsmString <<"\"\n";
@@ -650,14 +665,86 @@ void MatchableInfo::dump() {
}
}
-void MatchableInfo::Initialize(const AsmMatcherInfo &Info,
+static std::pair<StringRef, StringRef>
+parseTwoOperandConstraint(StringRef S, SMLoc Loc) {
+ // Split via the '='.
+ std::pair<StringRef, StringRef> Ops = S.split('=');
+ if (Ops.second == "")
+ throw TGError(Loc, "missing '=' in two-operand alias constraint");
+ // Trim whitespace and the leading '$' on the operand names.
+ size_t start = Ops.first.find_first_of('$');
+ if (start == std::string::npos)
+ throw TGError(Loc, "expected '$' prefix on asm operand name");
+ Ops.first = Ops.first.slice(start + 1, std::string::npos);
+ size_t end = Ops.first.find_last_of(" \t");
+ Ops.first = Ops.first.slice(0, end);
+ // Now the second operand.
+ start = Ops.second.find_first_of('$');
+ if (start == std::string::npos)
+ throw TGError(Loc, "expected '$' prefix on asm operand name");
+ Ops.second = Ops.second.slice(start + 1, std::string::npos);
+ end = Ops.second.find_last_of(" \t");
+ Ops.first = Ops.first.slice(0, end);
+ return Ops;
+}
+
+void MatchableInfo::formTwoOperandAlias(StringRef Constraint) {
+ // Figure out which operands are aliased and mark them as tied.
+ std::pair<StringRef, StringRef> Ops =
+ parseTwoOperandConstraint(Constraint, TheDef->getLoc());
+
+ // Find the AsmOperands that refer to the operands we're aliasing.
+ int SrcAsmOperand = findAsmOperandNamed(Ops.first);
+ int DstAsmOperand = findAsmOperandNamed(Ops.second);
+ if (SrcAsmOperand == -1)
+ throw TGError(TheDef->getLoc(),
+ "unknown source two-operand alias operand '" +
+ Ops.first.str() + "'.");
+ if (DstAsmOperand == -1)
+ throw TGError(TheDef->getLoc(),
+ "unknown destination two-operand alias operand '" +
+ Ops.second.str() + "'.");
+
+ // Find the ResOperand that refers to the operand we're aliasing away
+ // and update it to refer to the combined operand instead.
+ for (unsigned i = 0, e = ResOperands.size(); i != e; ++i) {
+ ResOperand &Op = ResOperands[i];
+ if (Op.Kind == ResOperand::RenderAsmOperand &&
+ Op.AsmOperandNum == (unsigned)SrcAsmOperand) {
+ Op.AsmOperandNum = DstAsmOperand;
+ break;
+ }
+ }
+ // Remove the AsmOperand for the alias operand.
+ AsmOperands.erase(AsmOperands.begin() + SrcAsmOperand);
+ // Adjust the ResOperand references to any AsmOperands that followed
+ // the one we just deleted.
+ for (unsigned i = 0, e = ResOperands.size(); i != e; ++i) {
+ ResOperand &Op = ResOperands[i];
+ switch(Op.Kind) {
+ default:
+ // Nothing to do for operands that don't reference AsmOperands.
+ break;
+ case ResOperand::RenderAsmOperand:
+ if (Op.AsmOperandNum > (unsigned)SrcAsmOperand)
+ --Op.AsmOperandNum;
+ break;
+ case ResOperand::TiedOperand:
+ if (Op.TiedOperandNum > (unsigned)SrcAsmOperand)
+ --Op.TiedOperandNum;
+ break;
+ }
+ }
+}
+
+void MatchableInfo::initialize(const AsmMatcherInfo &Info,
SmallPtrSet<Record*, 16> &SingletonRegisters,
int AsmVariantNo, std::string &RegisterPrefix) {
AsmVariantID = AsmVariantNo;
AsmString =
CodeGenInstruction::FlattenAsmStringVariants(AsmString, AsmVariantNo);
- TokenizeAsmString(Info);
+ tokenizeAsmString(Info);
// Compute the require features.
std::vector<Record*> Predicates =TheDef->getValueAsListOfDefs("Predicates");
@@ -674,8 +761,8 @@ void MatchableInfo::Initialize(const AsmMatcherInfo &Info,
}
}
-/// TokenizeAsmString - Tokenize a simplified assembly string.
-void MatchableInfo::TokenizeAsmString(const AsmMatcherInfo &Info) {
+/// tokenizeAsmString - Tokenize a simplified assembly string.
+void MatchableInfo::tokenizeAsmString(const AsmMatcherInfo &Info) {
StringRef String = AsmString;
unsigned Prev = 0;
bool InTok = true;
@@ -749,6 +836,9 @@ void MatchableInfo::TokenizeAsmString(const AsmMatcherInfo &Info) {
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(),
@@ -758,7 +848,7 @@ void MatchableInfo::TokenizeAsmString(const AsmMatcherInfo &Info) {
AsmOperands.erase(AsmOperands.begin());
}
-bool MatchableInfo::Validate(StringRef CommentDelimiter, bool Hack) const {
+bool MatchableInfo::validate(StringRef CommentDelimiter, bool Hack) const {
// Reject matchables with no .s string.
if (AsmString.empty())
throw TGError(TheDef->getLoc(), "instruction with empty asm string");
@@ -872,6 +962,7 @@ ClassInfo *AsmMatcherInfo::getTokenClass(StringRef Token) {
Entry->PredicateMethod = "<invalid>";
Entry->RenderMethod = "<invalid>";
Entry->ParserMethod = "";
+ Entry->DiagnosticType = "";
Classes.push_back(Entry);
}
@@ -929,7 +1020,7 @@ AsmMatcherInfo::getOperandClass(Record *Rec, int SubOpIdx) {
}
void AsmMatcherInfo::
-BuildRegisterClasses(SmallPtrSet<Record*, 16> &SingletonRegisters) {
+buildRegisterClasses(SmallPtrSet<Record*, 16> &SingletonRegisters) {
const std::vector<CodeGenRegister*> &Registers =
Target.getRegBank().getRegisters();
ArrayRef<CodeGenRegisterClass*> RegClassList =
@@ -997,6 +1088,8 @@ BuildRegisterClasses(SmallPtrSet<Record*, 16> &SingletonRegisters) {
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));
}
@@ -1054,7 +1147,7 @@ BuildRegisterClasses(SmallPtrSet<Record*, 16> &SingletonRegisters) {
}
}
-void AsmMatcherInfo::BuildOperandClasses() {
+void AsmMatcherInfo::buildOperandClasses() {
std::vector<Record*> AsmOperands =
Records.getAllDerivedDefinitions("AsmOperandClass");
@@ -1112,6 +1205,12 @@ void AsmMatcherInfo::BuildOperandClasses() {
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);
}
@@ -1123,11 +1222,11 @@ AsmMatcherInfo::AsmMatcherInfo(Record *asmParser,
: Records(records), AsmParser(asmParser), Target(target) {
}
-/// BuildOperandMatchInfo - Build the necessary information to handle user
+/// buildOperandMatchInfo - Build the necessary information to handle user
/// defined operand parsing methods.
-void AsmMatcherInfo::BuildOperandMatchInfo() {
+void AsmMatcherInfo::buildOperandMatchInfo() {
- /// Map containing a mask with all operands indicies that can be found for
+ /// Map containing a mask with all operands indices that can be found for
/// that class inside a instruction.
std::map<ClassInfo*, unsigned> OpClassMask;
@@ -1152,12 +1251,12 @@ void AsmMatcherInfo::BuildOperandMatchInfo() {
iie = OpClassMask.end(); iit != iie; ++iit) {
unsigned OpMask = iit->second;
ClassInfo *CI = iit->first;
- OperandMatchInfo.push_back(OperandMatchEntry::Create(&II, CI, OpMask));
+ OperandMatchInfo.push_back(OperandMatchEntry::create(&II, CI, OpMask));
}
}
}
-void AsmMatcherInfo::BuildInfo() {
+void AsmMatcherInfo::buildInfo() {
// Build information about all of the AssemblerPredicates.
std::vector<Record*> AllPredicates =
Records.getAllDerivedDefinitions("Predicate");
@@ -1222,11 +1321,11 @@ void AsmMatcherInfo::BuildInfo() {
OwningPtr<MatchableInfo> II(new MatchableInfo(CGI));
- II->Initialize(*this, SingletonRegisters, AsmVariantNo, RegisterPrefix);
+ II->initialize(*this, SingletonRegisters, AsmVariantNo, RegisterPrefix);
// Ignore instructions which shouldn't be matched and diagnose invalid
// instruction definitions with an error.
- if (!II->Validate(CommentDelimiter, true))
+ if (!II->validate(CommentDelimiter, true))
continue;
// Ignore "Int_*" and "*_Int" instructions, which are internal aliases.
@@ -1255,29 +1354,30 @@ void AsmMatcherInfo::BuildInfo() {
OwningPtr<MatchableInfo> II(new MatchableInfo(Alias));
- II->Initialize(*this, SingletonRegisters, AsmVariantNo, RegisterPrefix);
+ II->initialize(*this, SingletonRegisters, AsmVariantNo, RegisterPrefix);
// Validate the alias definitions.
- II->Validate(CommentDelimiter, false);
+ II->validate(CommentDelimiter, false);
Matchables.push_back(II.take());
}
}
// Build info for the register classes.
- BuildRegisterClasses(SingletonRegisters);
+ buildRegisterClasses(SingletonRegisters);
// Build info for the user defined assembly operand classes.
- BuildOperandClasses();
+ buildOperandClasses();
// Build the information about matchables, now that we have fully formed
// classes.
+ std::vector<MatchableInfo*> NewMatchables;
for (std::vector<MatchableInfo*>::iterator it = Matchables.begin(),
ie = Matchables.end(); it != ie; ++it) {
MatchableInfo *II = *it;
// Parse the tokens after the mnemonic.
- // Note: BuildInstructionOperandReference may insert new AsmOperands, so
+ // Note: buildInstructionOperandReference may insert new AsmOperands, so
// don't precompute the loop bound.
for (unsigned i = 0; i != II->AsmOperands.size(); ++i) {
MatchableInfo::AsmOperand &Op = II->AsmOperands[i];
@@ -1310,16 +1410,34 @@ void AsmMatcherInfo::BuildInfo() {
OperandName = Token.substr(1);
if (II->DefRec.is<const CodeGenInstruction*>())
- BuildInstructionOperandReference(II, OperandName, i);
+ buildInstructionOperandReference(II, OperandName, i);
else
- BuildAliasOperandReference(II, OperandName, Op);
+ buildAliasOperandReference(II, OperandName, Op);
}
- if (II->DefRec.is<const CodeGenInstruction*>())
- II->BuildInstructionResultOperands();
- else
- II->BuildAliasResultOperands();
+ if (II->DefRec.is<const CodeGenInstruction*>()) {
+ II->buildInstructionResultOperands();
+ // If the instruction has a two-operand alias, build up the
+ // matchable here. We'll add them in bulk at the end to avoid
+ // confusing this loop.
+ std::string Constraint =
+ II->TheDef->getValueAsString("TwoOperandAliasConstraint");
+ if (Constraint != "") {
+ // Start by making a copy of the original matchable.
+ OwningPtr<MatchableInfo> AliasII(new MatchableInfo(*II));
+
+ // Adjust it to be a two-operand alias.
+ AliasII->formTwoOperandAlias(Constraint);
+
+ // Add the alias to the matchables list.
+ NewMatchables.push_back(AliasII.take());
+ }
+ } else
+ II->buildAliasResultOperands();
}
+ if (!NewMatchables.empty())
+ Matchables.insert(Matchables.end(), NewMatchables.begin(),
+ NewMatchables.end());
// Process token alias definitions and set up the associated superclass
// information.
@@ -1339,10 +1457,10 @@ void AsmMatcherInfo::BuildInfo() {
std::sort(Classes.begin(), Classes.end(), less_ptr<ClassInfo>());
}
-/// BuildInstructionOperandReference - The specified operand is a reference to a
+/// buildInstructionOperandReference - The specified operand is a reference to a
/// named operand such as $src. Resolve the Class and OperandInfo pointers.
void AsmMatcherInfo::
-BuildInstructionOperandReference(MatchableInfo *II,
+buildInstructionOperandReference(MatchableInfo *II,
StringRef OperandName,
unsigned AsmOpIdx) {
const CodeGenInstruction &CGI = *II->DefRec.get<const CodeGenInstruction*>();
@@ -1399,10 +1517,10 @@ BuildInstructionOperandReference(MatchableInfo *II,
Op->SrcOpName = OperandName;
}
-/// BuildAliasOperandReference - When parsing an operand reference out of the
+/// buildAliasOperandReference - When parsing an operand reference out of the
/// matching string (e.g. "movsx $src, $dst"), determine what the class of the
/// operand reference is by looking it up in the result pattern definition.
-void AsmMatcherInfo::BuildAliasOperandReference(MatchableInfo *II,
+void AsmMatcherInfo::buildAliasOperandReference(MatchableInfo *II,
StringRef OperandName,
MatchableInfo::AsmOperand &Op) {
const CodeGenInstAlias &CGA = *II->DefRec.get<const CodeGenInstAlias*>();
@@ -1427,7 +1545,7 @@ void AsmMatcherInfo::BuildAliasOperandReference(MatchableInfo *II,
OperandName.str() + "'");
}
-void MatchableInfo::BuildInstructionResultOperands() {
+void MatchableInfo::buildInstructionResultOperands() {
const CodeGenInstruction *ResultInst = getResultInst();
// Loop over all operands of the result instruction, determining how to
@@ -1443,7 +1561,7 @@ void MatchableInfo::BuildInstructionResultOperands() {
}
// Find out what operand from the asmparser this MCInst operand comes from.
- int SrcOperand = FindAsmOperandNamed(OpInfo.Name);
+ int SrcOperand = findAsmOperandNamed(OpInfo.Name);
if (OpInfo.Name.empty() || SrcOperand == -1)
throw TGError(TheDef->getLoc(), "Instruction '" +
TheDef->getName() + "' has operand '" + OpInfo.Name +
@@ -1466,7 +1584,7 @@ void MatchableInfo::BuildInstructionResultOperands() {
}
}
-void MatchableInfo::BuildAliasResultOperands() {
+void MatchableInfo::buildAliasResultOperands() {
const CodeGenInstAlias &CGA = *DefRec.get<const CodeGenInstAlias*>();
const CodeGenInstruction *ResultInst = getResultInst();
@@ -1495,7 +1613,7 @@ void MatchableInfo::BuildAliasResultOperands() {
switch (CGA.ResultOperands[AliasOpNo].Kind) {
case CodeGenInstAlias::ResultOperand::K_Record: {
StringRef Name = CGA.ResultOperands[AliasOpNo].getName();
- int SrcOperand = FindAsmOperand(Name, SubIdx);
+ int SrcOperand = findAsmOperand(Name, SubIdx);
if (SrcOperand == -1)
throw TGError(TheDef->getLoc(), "Instruction '" +
TheDef->getName() + "' has operand '" + OpName +
@@ -1520,7 +1638,7 @@ void MatchableInfo::BuildAliasResultOperands() {
}
}
-static void EmitConvertToMCInst(CodeGenTarget &Target, StringRef ClassName,
+static void emitConvertToMCInst(CodeGenTarget &Target, StringRef ClassName,
std::vector<MatchableInfo*> &Infos,
raw_ostream &OS) {
// Write the convert function to a separate stream, so we can drop it after
@@ -1661,8 +1779,8 @@ static void EmitConvertToMCInst(CodeGenTarget &Target, StringRef ClassName,
OS << CvtOS.str();
}
-/// EmitMatchClassEnumeration - Emit the enumeration for match class kinds.
-static void EmitMatchClassEnumeration(CodeGenTarget &Target,
+/// emitMatchClassEnumeration - Emit the enumeration for match class kinds.
+static void emitMatchClassEnumeration(CodeGenTarget &Target,
std::vector<ClassInfo*> &Infos,
raw_ostream &OS) {
OS << "namespace {\n\n";
@@ -1692,37 +1810,24 @@ static void EmitMatchClassEnumeration(CodeGenTarget &Target,
OS << "}\n\n";
}
-/// EmitValidateOperandClass - Emit the function to validate an operand class.
-static void EmitValidateOperandClass(AsmMatcherInfo &Info,
+/// 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.
@@ -1734,18 +1839,39 @@ static void EmitValidateOperandClass(AsmMatcherInfo &Info,
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";
}
-/// EmitIsSubclass - Emit the subclass predicate function.
-static void EmitIsSubclass(CodeGenTarget &Target,
+/// emitIsSubclass - Emit the subclass predicate function.
+static void emitIsSubclass(CodeGenTarget &Target,
std::vector<ClassInfo*> &Infos,
raw_ostream &OS) {
OS << "/// isSubclass - Compute whether \\arg A is a subclass of \\arg B.\n";
@@ -1789,9 +1915,9 @@ static void EmitIsSubclass(CodeGenTarget &Target,
OS << "}\n\n";
}
-/// EmitMatchTokenString - Emit the function to match a token string to the
+/// emitMatchTokenString - Emit the function to match a token string to the
/// appropriate match class value.
-static void EmitMatchTokenString(CodeGenTarget &Target,
+static void emitMatchTokenString(CodeGenTarget &Target,
std::vector<ClassInfo*> &Infos,
raw_ostream &OS) {
// Construct the match list.
@@ -1813,9 +1939,9 @@ static void EmitMatchTokenString(CodeGenTarget &Target,
OS << "}\n\n";
}
-/// EmitMatchRegisterName - Emit the function to match a string to the target
+/// emitMatchRegisterName - Emit the function to match a string to the target
/// specific register enum.
-static void EmitMatchRegisterName(CodeGenTarget &Target, Record *AsmParser,
+static void emitMatchRegisterName(CodeGenTarget &Target, Record *AsmParser,
raw_ostream &OS) {
// Construct the match list.
std::vector<StringMatcher::StringPair> Matches;
@@ -1839,9 +1965,9 @@ static void EmitMatchRegisterName(CodeGenTarget &Target, Record *AsmParser,
OS << "}\n\n";
}
-/// EmitSubtargetFeatureFlagEnumeration - Emit the subtarget feature flag
+/// emitSubtargetFeatureFlagEnumeration - Emit the subtarget feature flag
/// definitions.
-static void EmitSubtargetFeatureFlagEnumeration(AsmMatcherInfo &Info,
+static void emitSubtargetFeatureFlagEnumeration(AsmMatcherInfo &Info,
raw_ostream &OS) {
OS << "// Flags for subtarget features that participate in "
<< "instruction matching.\n";
@@ -1856,9 +1982,48 @@ static void EmitSubtargetFeatureFlagEnumeration(AsmMatcherInfo &Info,
OS << "};\n\n";
}
-/// EmitComputeAvailableFeatures - Emit the function to compute the list of
+/// 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) {
+ OS << "// User-level names for subtarget features that participate in\n"
+ << "// instruction matching.\n"
+ << "static const char *getSubtargetFeatureName(unsigned Val) {\n"
+ << " switch(Val) {\n";
+ for (std::map<Record*, SubtargetFeatureInfo*>::const_iterator
+ it = Info.SubtargetFeatures.begin(),
+ ie = Info.SubtargetFeatures.end(); it != ie; ++it) {
+ SubtargetFeatureInfo &SFI = *it->second;
+ // FIXME: Totally just a placeholder name to get the algorithm working.
+ OS << " case " << SFI.getEnumName() << ": return \""
+ << SFI.TheDef->getValueAsString("PredicateName") << "\";\n";
+ }
+ OS << " default: return \"(unknown)\";\n";
+ OS << " }\n}\n\n";
+}
+
+/// emitComputeAvailableFeatures - Emit the function to compute the list of
/// available features given a subtarget.
-static void EmitComputeAvailableFeatures(AsmMatcherInfo &Info,
+static void emitComputeAvailableFeatures(AsmMatcherInfo &Info,
raw_ostream &OS) {
std::string ClassName =
Info.AsmParser->getValueAsString("AsmParserClassName");
@@ -1933,9 +2098,9 @@ static std::string GetAliasRequiredFeatures(Record *R,
return Result;
}
-/// EmitMnemonicAliases - If the target has any MnemonicAlias<> definitions,
+/// emitMnemonicAliases - If the target has any MnemonicAlias<> definitions,
/// emit a function for them and return true, otherwise return false.
-static bool EmitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info) {
+static bool emitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info) {
// Ignore aliases when match-prefix is set.
if (!MatchPrefix.empty())
return false;
@@ -2023,7 +2188,7 @@ static const char *getMinimalTypeForRange(uint64_t Range) {
return "uint8_t";
}
-static void EmitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
+static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
const AsmMatcherInfo &Info, StringRef ClassName) {
// Emit the static custom operand parsing table;
OS << "namespace {\n";
@@ -2193,7 +2358,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
// Compute the information on the instructions to match.
AsmMatcherInfo Info(AsmParser, Target, Records);
- Info.BuildInfo();
+ Info.buildInfo();
// Sort the instruction table using the partial order on classes. We use
// stable_sort to ensure that ambiguous instructions are still
@@ -2216,7 +2381,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
MatchableInfo &A = *Info.Matchables[i];
MatchableInfo &B = *Info.Matchables[j];
- if (A.CouldMatchAmbiguouslyWith(B)) {
+ if (A.couldMatchAmbiguouslyWith(B)) {
errs() << "warning: ambiguous matchables:\n";
A.dump();
errs() << "\nis incomparable with:\n";
@@ -2232,12 +2397,10 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
});
// Compute the information on the custom operand parsing.
- Info.BuildOperandMatchInfo();
+ Info.buildOperandMatchInfo();
// 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";
@@ -2270,41 +2433,55 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
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";
// Emit the subtarget feature enumeration.
- EmitSubtargetFeatureFlagEnumeration(Info, OS);
+ emitSubtargetFeatureFlagEnumeration(Info, OS);
// Emit the function to match a register name to number.
- EmitMatchRegisterName(Target, AsmParser, OS);
+ emitMatchRegisterName(Target, AsmParser, OS);
OS << "#endif // GET_REGISTER_MATCHER\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);
+ bool HasMnemonicAliases = emitMnemonicAliases(OS, Info);
// Generate the unified function to convert operands into an MCInst.
- EmitConvertToMCInst(Target, ClassName, Info.Matchables, OS);
+ emitConvertToMCInst(Target, ClassName, Info.Matchables, OS);
// Emit the enumeration for classes which participate in matching.
- EmitMatchClassEnumeration(Target, Info.Classes, OS);
+ emitMatchClassEnumeration(Target, Info.Classes, OS);
// Emit the routine to match token strings to their match class.
- EmitMatchTokenString(Target, Info.Classes, OS);
+ emitMatchTokenString(Target, Info.Classes, OS);
// Emit the subclass predicate routine.
- EmitIsSubclass(Target, Info.Classes, OS);
+ emitIsSubclass(Target, Info.Classes, OS);
// Emit the routine to validate an operand against a match class.
- EmitValidateOperandClass(Info, OS);
+ emitValidateOperandClass(Info, OS);
// Emit the available features compute function.
- EmitComputeAvailableFeatures(Info, OS);
+ emitComputeAvailableFeatures(Info, OS);
size_t MaxNumOperands = 0;
@@ -2415,8 +2592,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
<< Target.getName() << ClassName << "::\n"
<< "MatchInstructionImpl(const SmallVectorImpl<MCParsedAsmOperand*>"
<< " &Operands,\n";
- OS << " MCInst &Inst, unsigned &ErrorInfo,\n";
- OS << " unsigned VariantID) {\n";
+ OS << " MCInst &Inst, unsigned &ErrorInfo, ";
+ OS << "unsigned VariantID) {\n";
// Emit code to get the available features.
OS << " // Get the current feature set.\n";
@@ -2444,6 +2621,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
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";
@@ -2471,15 +2649,25 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
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";
@@ -2491,6 +2679,11 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " if ((AvailableFeatures & it->RequiredFeatures) "
<< "!= it->RequiredFeatures) {\n";
OS << " HadMatchOtherThanFeatures = true;\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";
@@ -2524,12 +2717,23 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " // Okay, we had no match. Try to return a useful error code.\n";
OS << " if (HadMatchOtherThanPredicate || !HadMatchOtherThanFeatures)";
- OS << " return RetCode;\n";
+ 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";
if (Info.OperandMatchInfo.size())
- EmitCustomOperandParsing(OS, Target, Info, ClassName);
+ emitCustomOperandParsing(OS, Target, Info, ClassName);
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