MatchPrefix("match-prefix", cl::init(""),
cl::desc("Only match instructions with the given prefix"));
-
namespace {
- class AsmMatcherInfo;
+class AsmMatcherInfo;
struct SubtargetFeatureInfo;
/// ClassInfo - Helper class for storing the information about a particular
struct AsmOperand {
/// Token - This is the token that the operand came from.
StringRef Token;
-
+
/// The unique class instance this operand should match.
ClassInfo *Class;
/// The operand name this is, if anything.
StringRef SrcOpName;
-
- explicit AsmOperand(StringRef T) : Token(T), Class(0) {}
+
+ /// The suboperand index within SrcOpName, or -1 for the entire operand.
+ int SubOpIdx;
+
+ explicit AsmOperand(StringRef T) : Token(T), Class(0), SubOpIdx(-1) {}
};
-
+
/// ResOperand - This represents a single operand in the result instruction
/// generated by the match. In cases (like addressing modes) where a single
/// assembler operand expands to multiple MCOperands, this represents the
/// generated by calling the render method on the assembly operand. The
/// corresponding AsmOperand is specified by AsmOperandNum.
RenderAsmOperand,
-
+
/// TiedOperand - This represents a result operand that is a duplicate of
/// a previous result operand.
TiedOperand,
-
+
/// ImmOperand - This represents an immediate value that is dumped into
/// the operand.
ImmOperand,
-
+
/// RegOperand - This represents a fixed register that is dumped in.
RegOperand
} Kind;
-
+
union {
/// This is the operand # in the AsmOperands list that this should be
/// copied from.
unsigned AsmOperandNum;
-
+
/// TiedOperandNum - This is the (earlier) result operand that should be
/// copied from.
unsigned TiedOperandNum;
-
+
/// ImmVal - This is the immediate value added to the instruction.
int64_t ImmVal;
-
+
/// Register - This is the register record.
Record *Register;
};
-
- /// OpInfo - This is the information about the instruction operand that is
- /// being populated.
- const CGIOperandList::OperandInfo *OpInfo;
-
- static ResOperand getRenderedOp(unsigned AsmOpNum,
- const CGIOperandList::OperandInfo *Op) {
+
+ /// MINumOperands - The number of MCInst operands populated by this
+ /// operand.
+ unsigned MINumOperands;
+
+ static ResOperand getRenderedOp(unsigned AsmOpNum, unsigned NumOperands) {
ResOperand X;
X.Kind = RenderAsmOperand;
X.AsmOperandNum = AsmOpNum;
- X.OpInfo = Op;
+ X.MINumOperands = NumOperands;
return X;
}
-
- static ResOperand getTiedOp(unsigned TiedOperandNum,
- const CGIOperandList::OperandInfo *Op) {
+
+ static ResOperand getTiedOp(unsigned TiedOperandNum) {
ResOperand X;
X.Kind = TiedOperand;
X.TiedOperandNum = TiedOperandNum;
- X.OpInfo = Op;
+ X.MINumOperands = 1;
return X;
}
-
- static ResOperand getImmOp(int64_t Val,
- const CGIOperandList::OperandInfo *Op) {
+
+ static ResOperand getImmOp(int64_t Val) {
ResOperand X;
X.Kind = ImmOperand;
X.ImmVal = Val;
- X.OpInfo = Op;
+ X.MINumOperands = 1;
return X;
}
-
- static ResOperand getRegOp(Record *Reg,
- const CGIOperandList::OperandInfo *Op) {
+
+ static ResOperand getRegOp(Record *Reg) {
ResOperand X;
X.Kind = RegOperand;
X.Register = Reg;
- X.OpInfo = Op;
+ X.MINumOperands = 1;
return X;
}
-
};
/// TheDef - This is the definition of the instruction or InstAlias that this
/// matchable came from.
Record *const TheDef;
-
+
/// DefRec - This is the definition that it came from.
PointerUnion<const CodeGenInstruction*, const CodeGenInstAlias*> DefRec;
-
+
const CodeGenInstruction *getResultInst() const {
if (DefRec.is<const CodeGenInstruction*>())
return DefRec.get<const CodeGenInstruction*>();
return DefRec.get<const CodeGenInstAlias*>()->ResultInst;
}
-
+
/// ResOperands - This is the operand list that should be built for the result
/// MCInst.
std::vector<ResOperand> ResOperands;
/// Mnemonic - This is the first token of the matched instruction, its
/// mnemonic.
StringRef Mnemonic;
-
+
/// AsmOperands - The textual operands that this instruction matches,
/// annotated with a class and where in the OperandList they were defined.
/// This directly corresponds to the tokenized AsmString after the mnemonic is
/// ConvertToMCInst to convert parsed operands into an MCInst for this
/// function.
std::string ConversionFnKind;
-
+
MatchableInfo(const CodeGenInstruction &CGI)
: TheDef(CGI.TheDef), DefRec(&CGI), AsmString(CGI.AsmString) {
}
MatchableInfo(const CodeGenInstAlias *Alias)
: TheDef(Alias->TheDef), DefRec(Alias), AsmString(Alias->AsmString) {
}
-
+
void Initialize(const AsmMatcherInfo &Info,
SmallPtrSet<Record*, 16> &SingletonRegisters);
-
+
/// 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;
-
+
/// getSingletonRegisterForAsmOperand - If the specified token is a singleton
/// register, return the Record for it, otherwise return null.
Record *getSingletonRegisterForAsmOperand(unsigned i,
- const AsmMatcherInfo &Info) const;
+ const AsmMatcherInfo &Info) const;
+ /// FindAsmOperand - Find the AsmOperand with the specified name and
+ /// suboperand index.
+ 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)
+ return i;
+ return -1;
+ }
+
+ /// FindAsmOperandNamed - Find the first AsmOperand with the specified name.
+ /// This does not check the suboperand index.
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();
return AsmOperands.size() < RHS.AsmOperands.size();
// Compare lexicographically by operand. The matcher validates that other
- // orderings wouldn't be ambiguous using \see CouldMatchAmiguouslyWith().
+ // 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;
return false;
}
- /// CouldMatchAmiguouslyWith - 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 CouldMatchAmiguouslyWith(const MatchableInfo &RHS) {
+ bool CouldMatchAmbiguouslyWith(const MatchableInfo &RHS) {
// The primary comparator is the instruction mnemonic.
if (Mnemonic != RHS.Mnemonic)
return false;
-
+
// The number of operands is unambiguous.
if (AsmOperands.size() != RHS.AsmOperands.size())
return false;
}
void dump();
-
+
private:
void TokenizeAsmString(const AsmMatcherInfo &Info);
};
unsigned Index;
SubtargetFeatureInfo(Record *D, unsigned Idx) : TheDef(D), Index(Idx) {}
-
+
/// \brief The name of the enumerated constant identifying this feature.
std::string getEnumName() const {
return "Feature_" + TheDef->getName();
class AsmMatcherInfo {
public:
+ /// Tracked Records
+ RecordKeeper &Records;
+
/// The tablegen AsmParser record.
Record *AsmParser;
/// Map of Predicate records to their subtarget information.
std::map<Record*, SubtargetFeatureInfo*> SubtargetFeatures;
-
+
private:
/// Map of token to class information which has already been constructed.
std::map<std::string, ClassInfo*> TokenClasses;
ClassInfo *getTokenClass(StringRef Token);
/// getOperandClass - Lookup or create the class for the given operand.
- ClassInfo *getOperandClass(const CGIOperandList::OperandInfo &OI);
+ ClassInfo *getOperandClass(const CGIOperandList::OperandInfo &OI,
+ int SubOpIdx = -1);
/// BuildRegisterClasses - Build the ClassInfo* instances for register
/// classes.
/// operand classes.
void BuildOperandClasses();
- void BuildInstructionOperandReference(MatchableInfo *II,
- StringRef OpName,
- MatchableInfo::AsmOperand &Op);
- void BuildAliasOperandReference(MatchableInfo *II,
- StringRef OpName,
+ void BuildInstructionOperandReference(MatchableInfo *II, StringRef OpName,
+ unsigned AsmOpIdx);
+ void BuildAliasOperandReference(MatchableInfo *II, StringRef OpName,
MatchableInfo::AsmOperand &Op);
-
+
public:
- AsmMatcherInfo(Record *AsmParser, CodeGenTarget &Target);
+ AsmMatcherInfo(Record *AsmParser,
+ CodeGenTarget &Target,
+ RecordKeeper &Records);
/// BuildInfo - Construct the various tables used during matching.
void BuildInfo();
-
+
/// getSubtargetFeature - Lookup or create the subtarget feature info for the
/// given operand.
SubtargetFeatureInfo *getSubtargetFeature(Record *Def) const {
SubtargetFeatures.find(Def);
return I == SubtargetFeatures.end() ? 0 : I->second;
}
+
+ RecordKeeper &getRecords() const {
+ return Records;
+ }
};
}
SmallPtrSet<Record*, 16> &SingletonRegisters) {
// TODO: Eventually support asmparser for Variant != 0.
AsmString = CodeGenInstruction::FlattenAsmStringVariants(AsmString, 0);
-
+
TokenizeAsmString(Info);
-
+
// Compute the require features.
std::vector<Record*> Predicates =TheDef->getValueAsListOfDefs("Predicates");
for (unsigned i = 0, e = Predicates.size(); i != e; ++i)
if (SubtargetFeatureInfo *Feature =
Info.getSubtargetFeature(Predicates[i]))
RequiredFeatures.push_back(Feature);
-
+
// Collect singleton registers, if used.
for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) {
if (Record *Reg = getSingletonRegisterForAsmOperand(i, Info))
AsmOperands.push_back(AsmOperand(String.slice(Prev, i)));
InTok = false;
}
-
+
// If this isn't "${", treat like a normal token.
if (i + 1 == String.size() || String[i + 1] != '{') {
Prev = i;
}
if (InTok && Prev != String.size())
AsmOperands.push_back(AsmOperand(String.substr(Prev)));
-
+
// The first token of the instruction is the mnemonic, which must be a
// simple string, not a $foo variable or a singleton register.
assert(!AsmOperands.empty() && "Instruction has no tokens?");
if (Mnemonic[0] == '$' || getSingletonRegisterForAsmOperand(0, Info))
throw TGError(TheDef->getLoc(),
"Invalid instruction mnemonic '" + Mnemonic.str() + "'!");
-
+
// Remove the first operand, it is tracked in the mnemonic field.
AsmOperands.erase(AsmOperands.begin());
}
-
-
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");
-
+
// Reject any matchables with a newline in them, they should be marked
// isCodeGenOnly if they are pseudo instructions.
if (AsmString.find('\n') != std::string::npos)
throw TGError(TheDef->getLoc(),
"multiline instruction is not valid for the asmparser, "
"mark it isCodeGenOnly");
-
+
// Remove comments from the asm string. We know that the asmstring only
// has one line.
if (!CommentDelimiter.empty() &&
throw TGError(TheDef->getLoc(),
"asmstring for instruction has comment character in it, "
"mark it isCodeGenOnly");
-
+
// Reject matchables with operand modifiers, these aren't something we can
- /// handle, the target should be refactored to use operands instead of
- /// modifiers.
+ // handle, the target should be refactored to use operands instead of
+ // modifiers.
//
// Also, check for instructions which reference the operand multiple times;
// this implies a constraint we would not honor.
throw TGError(TheDef->getLoc(),
"matchable with operand modifier '" + Tok.str() +
"' not supported by asm matcher. Mark isCodeGenOnly!");
-
+
// Verify that any operand is only mentioned once.
// We reject aliases and ignore instructions for now.
if (Tok[0] == '$' && !OperandNames.insert(Tok).second) {
return false;
}
}
-
+
return true;
}
-
/// getSingletonRegisterForAsmOperand - If the specified token is a singleton
/// register, return the register name, otherwise return a null StringRef.
Record *MatchableInfo::
StringRef Tok = AsmOperands[i].Token;
if (!Tok.startswith(Info.RegisterPrefix))
return 0;
-
+
StringRef RegName = Tok.substr(Info.RegisterPrefix.size());
if (const CodeGenRegister *Reg = Info.Target.getRegisterByName(RegName))
return Reg->TheDef;
-
+
// If there is no register prefix (i.e. "%" in "%eax"), then this may
// be some random non-register token, just ignore it.
if (Info.RegisterPrefix.empty())
return 0;
-
+
// Otherwise, we have something invalid prefixed with the register prefix,
// such as %foo.
std::string Err = "unable to find register for '" + RegName.str() +
throw TGError(TheDef->getLoc(), Err);
}
-
static std::string getEnumNameForToken(StringRef Str) {
std::string Res;
case '%': Res += "_PCT_"; break;
case ':': Res += "_COLON_"; break;
case '!': Res += "_EXCLAIM_"; break;
+ case '.': Res += "_DOT_"; break;
default:
if (isalnum(*it))
Res += *it;
}
ClassInfo *
-AsmMatcherInfo::getOperandClass(const CGIOperandList::OperandInfo &OI) {
- if (OI.Rec->isSubClassOf("RegisterClass")) {
- if (ClassInfo *CI = RegisterClassClasses[OI.Rec])
+AsmMatcherInfo::getOperandClass(const CGIOperandList::OperandInfo &OI,
+ int SubOpIdx) {
+ Record *Rec = OI.Rec;
+ if (SubOpIdx != -1)
+ Rec = dynamic_cast<DefInit*>(OI.MIOperandInfo->getArg(SubOpIdx))->getDef();
+
+ if (Rec->isSubClassOf("RegisterClass")) {
+ if (ClassInfo *CI = RegisterClassClasses[Rec])
return CI;
- throw TGError(OI.Rec->getLoc(), "register class has no class info!");
+ throw TGError(Rec->getLoc(), "register class has no class info!");
}
- assert(OI.Rec->isSubClassOf("Operand") && "Unexpected operand!");
- Record *MatchClass = OI.Rec->getValueAsDef("ParserMatchClass");
+ assert(Rec->isSubClassOf("Operand") && "Unexpected operand!");
+ Record *MatchClass = Rec->getValueAsDef("ParserMatchClass");
if (ClassInfo *CI = AsmOperandClasses[MatchClass])
return CI;
- throw TGError(OI.Rec->getLoc(), "operand has no match class!");
+ throw TGError(Rec->getLoc(), "operand has no match class!");
}
void AsmMatcherInfo::
ContainingSet = *it;
continue;
}
-
+
std::set<Record*> Tmp;
std::swap(Tmp, ContainingSet);
std::insert_iterator< std::set<Record*> > II(ContainingSet,
}
}
-AsmMatcherInfo::AsmMatcherInfo(Record *asmParser, CodeGenTarget &target)
- : AsmParser(asmParser), Target(target),
+AsmMatcherInfo::AsmMatcherInfo(Record *asmParser,
+ CodeGenTarget &target,
+ RecordKeeper &records)
+ : Records(records), AsmParser(asmParser), Target(target),
RegisterPrefix(AsmParser->getValueAsString("RegisterPrefix")) {
}
-
void AsmMatcherInfo::BuildInfo() {
// Build information about all of the AssemblerPredicates.
std::vector<Record*> AllPredicates =
// Ignore predicates that are not intended for the assembler.
if (!Pred->getValueAsBit("AssemblerMatcherPredicate"))
continue;
-
+
if (Pred->getName().empty())
throw TGError(Pred->getLoc(), "Predicate has no name!");
-
+
unsigned FeatureNo = SubtargetFeatures.size();
SubtargetFeatures[Pred] = new SubtargetFeatureInfo(Pred, FeatureNo);
assert(FeatureNo < 32 && "Too many subtarget features!");
}
StringRef CommentDelimiter = AsmParser->getValueAsString("CommentDelimiter");
-
+
// Parse the instructions; we need to do this first so that we can gather the
// singleton register classes.
SmallPtrSet<Record*, 16> SingletonRegisters;
// Ignore "codegen only" instructions.
if (CGI.TheDef->getValueAsBit("isCodeGenOnly"))
continue;
-
+
// Validate the operand list to ensure we can handle this instruction.
for (unsigned i = 0, e = CGI.Operands.size(); i != e; ++i) {
const CGIOperandList::OperandInfo &OI = CGI.Operands[i];
-
+
// Validate tied operands.
if (OI.getTiedRegister() != -1) {
- // If we have a tied operand that consists of multiple MCOperands, reject
- // it. We reject aliases and ignore instructions for now.
+ // If we have a tied operand that consists of multiple MCOperands,
+ // reject it. We reject aliases and ignore instructions for now.
if (OI.MINumOperands != 1) {
// FIXME: Should reject these. The ARM backend hits this with $lane
// in a bunch of instructions. It is unclear what the right answer is.
}
}
}
-
+
OwningPtr<MatchableInfo> II(new MatchableInfo(CGI));
II->Initialize(*this, SingletonRegisters);
-
+
// Ignore instructions which shouldn't be matched and diagnose invalid
// instruction definitions with an error.
if (!II->Validate(CommentDelimiter, true))
continue;
-
+
// Ignore "Int_*" and "*_Int" instructions, which are internal aliases.
//
// FIXME: This is a total hack.
if (StringRef(II->TheDef->getName()).startswith("Int_") ||
StringRef(II->TheDef->getName()).endswith("_Int"))
continue;
-
+
Matchables.push_back(II.take());
}
-
+
// Parse all of the InstAlias definitions and stick them in the list of
// matchables.
std::vector<Record*> AllInstAliases =
for (unsigned i = 0, e = AllInstAliases.size(); i != e; ++i) {
CodeGenInstAlias *Alias = new CodeGenInstAlias(AllInstAliases[i], Target);
+ // If the tblgen -match-prefix option is specified (for tblgen hackers),
+ // filter the set of instruction aliases we consider, based on the target
+ // instruction.
+ if (!StringRef(Alias->ResultInst->TheDef->getName()).startswith(
+ MatchPrefix))
+ continue;
+
OwningPtr<MatchableInfo> II(new MatchableInfo(Alias));
-
+
II->Initialize(*this, SingletonRegisters);
-
+
// Validate the alias definitions.
II->Validate(CommentDelimiter, false);
-
+
Matchables.push_back(II.take());
}
MatchableInfo *II = *it;
// Parse the tokens after the mnemonic.
- for (unsigned i = 0, e = II->AsmOperands.size(); i != e; ++i) {
+ // 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];
StringRef Token = Op.Token;
Op.Class = getTokenClass(Token);
continue;
}
-
+
// Otherwise this is an operand reference.
StringRef OperandName;
if (Token[1] == '{')
OperandName = Token.substr(2, Token.size() - 3);
else
OperandName = Token.substr(1);
-
+
if (II->DefRec.is<const CodeGenInstruction*>())
- BuildInstructionOperandReference(II, OperandName, Op);
+ BuildInstructionOperandReference(II, OperandName, i);
else
BuildAliasOperandReference(II, OperandName, Op);
}
-
+
if (II->DefRec.is<const CodeGenInstruction*>())
II->BuildInstructionResultOperands();
else
void AsmMatcherInfo::
BuildInstructionOperandReference(MatchableInfo *II,
StringRef OperandName,
- MatchableInfo::AsmOperand &Op) {
+ unsigned AsmOpIdx) {
const CodeGenInstruction &CGI = *II->DefRec.get<const CodeGenInstruction*>();
const CGIOperandList &Operands = CGI.Operands;
-
+ MatchableInfo::AsmOperand *Op = &II->AsmOperands[AsmOpIdx];
+
// Map this token to an operand.
unsigned Idx;
if (!Operands.hasOperandNamed(OperandName, Idx))
throw TGError(II->TheDef->getLoc(), "error: unable to find operand: '" +
OperandName.str() + "'");
+ // If the instruction operand has multiple suboperands, but the parser
+ // match class for the asm operand is still the default "ImmAsmOperand",
+ // then handle each suboperand separately.
+ if (Op->SubOpIdx == -1 && Operands[Idx].MINumOperands > 1) {
+ Record *Rec = Operands[Idx].Rec;
+ assert(Rec->isSubClassOf("Operand") && "Unexpected operand!");
+ Record *MatchClass = Rec->getValueAsDef("ParserMatchClass");
+ if (MatchClass && MatchClass->getValueAsString("Name") == "Imm") {
+ // Insert remaining suboperands after AsmOpIdx in II->AsmOperands.
+ StringRef Token = Op->Token; // save this in case Op gets moved
+ for (unsigned SI = 1, SE = Operands[Idx].MINumOperands; SI != SE; ++SI) {
+ MatchableInfo::AsmOperand NewAsmOp(Token);
+ NewAsmOp.SubOpIdx = SI;
+ II->AsmOperands.insert(II->AsmOperands.begin()+AsmOpIdx+SI, NewAsmOp);
+ }
+ // Replace Op with first suboperand.
+ Op = &II->AsmOperands[AsmOpIdx]; // update the pointer in case it moved
+ Op->SubOpIdx = 0;
+ }
+ }
+
// Set up the operand class.
- Op.Class = getOperandClass(Operands[Idx]);
+ Op->Class = getOperandClass(Operands[Idx], Op->SubOpIdx);
// If the named operand is tied, canonicalize it to the untied operand.
// For example, something like:
if (OITied != -1) {
// The tied operand index is an MIOperand index, find the operand that
// contains it.
- for (unsigned i = 0, e = Operands.size(); i != e; ++i) {
- if (Operands[i].MIOperandNo == unsigned(OITied)) {
- OperandName = Operands[i].Name;
- break;
- }
- }
+ std::pair<unsigned, unsigned> Idx = Operands.getSubOperandNumber(OITied);
+ OperandName = Operands[Idx.first].Name;
+ Op->SubOpIdx = Idx.second;
}
-
- Op.SrcOpName = OperandName;
+
+ Op->SrcOpName = OperandName;
}
/// BuildAliasOperandReference - When parsing an operand reference out of the
StringRef OperandName,
MatchableInfo::AsmOperand &Op) {
const CodeGenInstAlias &CGA = *II->DefRec.get<const CodeGenInstAlias*>();
-
+
// Set up the operand class.
for (unsigned i = 0, e = CGA.ResultOperands.size(); i != e; ++i)
if (CGA.ResultOperands[i].isRecord() &&
CGA.ResultOperands[i].getName() == OperandName) {
// It's safe to go with the first one we find, because CodeGenInstAlias
// validates that all operands with the same name have the same record.
- unsigned ResultIdx =CGA.getResultInstOperandIndexForResultOperandIndex(i);
- Op.Class = getOperandClass(CGA.ResultInst->Operands[ResultIdx]);
+ unsigned ResultIdx = CGA.ResultInstOperandIndex[i].first;
+ Op.SubOpIdx = CGA.ResultInstOperandIndex[i].second;
+ Op.Class = getOperandClass(CGA.ResultInst->Operands[ResultIdx],
+ Op.SubOpIdx);
Op.SrcOpName = OperandName;
return;
}
void MatchableInfo::BuildInstructionResultOperands() {
const CodeGenInstruction *ResultInst = getResultInst();
-
+
// Loop over all operands of the result instruction, determining how to
// populate them.
for (unsigned i = 0, e = ResultInst->Operands.size(); i != e; ++i) {
// If this is a tied operand, just copy from the previously handled operand.
int TiedOp = OpInfo.getTiedRegister();
if (TiedOp != -1) {
- ResOperands.push_back(ResOperand::getTiedOp(TiedOp, &OpInfo));
+ ResOperands.push_back(ResOperand::getTiedOp(TiedOp));
continue;
}
-
- // Find out what operand from the asmparser that this MCInst operand comes
- // from.
+
+ // Find out what operand from the asmparser this MCInst operand comes from.
int SrcOperand = FindAsmOperandNamed(OpInfo.Name);
+ if (OpInfo.Name.empty() || SrcOperand == -1)
+ throw TGError(TheDef->getLoc(), "Instruction '" +
+ TheDef->getName() + "' has operand '" + OpInfo.Name +
+ "' that doesn't appear in asm string!");
- if (!OpInfo.Name.empty() && SrcOperand != -1) {
- ResOperands.push_back(ResOperand::getRenderedOp(SrcOperand, &OpInfo));
+ // Check if the one AsmOperand populates the entire operand.
+ unsigned NumOperands = OpInfo.MINumOperands;
+ if (AsmOperands[SrcOperand].SubOpIdx == -1) {
+ ResOperands.push_back(ResOperand::getRenderedOp(SrcOperand, NumOperands));
continue;
}
-
- throw TGError(TheDef->getLoc(), "Instruction '" +
- TheDef->getName() + "' has operand '" + OpInfo.Name +
- "' that doesn't appear in asm string!");
+
+ // Add a separate ResOperand for each suboperand.
+ for (unsigned AI = 0; AI < NumOperands; ++AI) {
+ assert(AsmOperands[SrcOperand+AI].SubOpIdx == (int)AI &&
+ AsmOperands[SrcOperand+AI].SrcOpName == OpInfo.Name &&
+ "unexpected AsmOperands for suboperands");
+ ResOperands.push_back(ResOperand::getRenderedOp(SrcOperand + AI, 1));
+ }
}
}
void MatchableInfo::BuildAliasResultOperands() {
const CodeGenInstAlias &CGA = *DefRec.get<const CodeGenInstAlias*>();
const CodeGenInstruction *ResultInst = getResultInst();
-
+
// Loop over all operands of the result instruction, determining how to
// populate them.
unsigned AliasOpNo = 0;
+ unsigned LastOpNo = CGA.ResultInstOperandIndex.size();
for (unsigned i = 0, e = ResultInst->Operands.size(); i != e; ++i) {
- const CGIOperandList::OperandInfo &OpInfo = ResultInst->Operands[i];
-
+ const CGIOperandList::OperandInfo *OpInfo = &ResultInst->Operands[i];
+
// If this is a tied operand, just copy from the previously handled operand.
- int TiedOp = OpInfo.getTiedRegister();
+ int TiedOp = OpInfo->getTiedRegister();
if (TiedOp != -1) {
- ResOperands.push_back(ResOperand::getTiedOp(TiedOp, &OpInfo));
- continue;
- }
-
- // Find out what operand from the asmparser that this MCInst operand comes
- // from.
- switch (CGA.ResultOperands[AliasOpNo].Kind) {
- case CodeGenInstAlias::ResultOperand::K_Record: {
- StringRef Name = CGA.ResultOperands[AliasOpNo++].getName();
- int SrcOperand = FindAsmOperandNamed(Name);
- if (SrcOperand != -1) {
- ResOperands.push_back(ResOperand::getRenderedOp(SrcOperand, &OpInfo));
- continue;
- }
-
- throw TGError(TheDef->getLoc(), "Instruction '" +
- TheDef->getName() + "' has operand '" + OpInfo.Name +
- "' that doesn't appear in asm string!");
- }
- case CodeGenInstAlias::ResultOperand::K_Imm: {
- int64_t ImmVal = CGA.ResultOperands[AliasOpNo++].getImm();
- ResOperands.push_back(ResOperand::getImmOp(ImmVal, &OpInfo));
+ ResOperands.push_back(ResOperand::getTiedOp(TiedOp));
continue;
}
- case CodeGenInstAlias::ResultOperand::K_Reg: {
- Record *Reg = CGA.ResultOperands[AliasOpNo++].getRegister();
- ResOperands.push_back(ResOperand::getRegOp(Reg, &OpInfo));
- continue;
- }
+ // Handle all the suboperands for this operand.
+ const std::string &OpName = OpInfo->Name;
+ for ( ; AliasOpNo < LastOpNo &&
+ CGA.ResultInstOperandIndex[AliasOpNo].first == i; ++AliasOpNo) {
+ int SubIdx = CGA.ResultInstOperandIndex[AliasOpNo].second;
+
+ // Find out what operand from the asmparser that this MCInst operand
+ // comes from.
+ switch (CGA.ResultOperands[AliasOpNo].Kind) {
+ default: assert(0 && "unexpected InstAlias operand kind");
+ case CodeGenInstAlias::ResultOperand::K_Record: {
+ StringRef Name = CGA.ResultOperands[AliasOpNo].getName();
+ int SrcOperand = FindAsmOperand(Name, SubIdx);
+ if (SrcOperand == -1)
+ throw TGError(TheDef->getLoc(), "Instruction '" +
+ TheDef->getName() + "' has operand '" + OpName +
+ "' that doesn't appear in asm string!");
+ unsigned NumOperands = (SubIdx == -1 ? OpInfo->MINumOperands : 1);
+ ResOperands.push_back(ResOperand::getRenderedOp(SrcOperand,
+ NumOperands));
+ break;
+ }
+ case CodeGenInstAlias::ResultOperand::K_Imm: {
+ int64_t ImmVal = CGA.ResultOperands[AliasOpNo].getImm();
+ ResOperands.push_back(ResOperand::getImmOp(ImmVal));
+ break;
+ }
+ case CodeGenInstAlias::ResultOperand::K_Reg: {
+ Record *Reg = CGA.ResultOperands[AliasOpNo].getRegister();
+ ResOperands.push_back(ResOperand::getRegOp(Reg));
+ break;
+ }
+ }
}
}
}
std::string Signature = "Convert";
std::string CaseBody;
raw_string_ostream CaseOS(CaseBody);
-
+
// Compute the convert enum and the case body.
for (unsigned i = 0, e = II.ResOperands.size(); i != e; ++i) {
const MatchableInfo::ResOperand &OpInfo = II.ResOperands[i];
case MatchableInfo::ResOperand::RenderAsmOperand: {
// This comes from something we parsed.
MatchableInfo::AsmOperand &Op = II.AsmOperands[OpInfo.AsmOperandNum];
-
+
// Registers are always converted the same, don't duplicate the
// conversion function based on them.
Signature += "__";
Signature += "Reg";
else
Signature += Op.Class->ClassName;
- Signature += utostr(OpInfo.OpInfo->MINumOperands);
+ Signature += utostr(OpInfo.MINumOperands);
Signature += "_" + itostr(OpInfo.AsmOperandNum);
-
+
CaseOS << " ((" << TargetOperandClass << "*)Operands["
<< (OpInfo.AsmOperandNum+1) << "])->" << Op.Class->RenderMethod
- << "(Inst, " << OpInfo.OpInfo->MINumOperands << ");\n";
+ << "(Inst, " << OpInfo.MINumOperands << ");\n";
break;
}
-
+
case MatchableInfo::ResOperand::TiedOperand: {
// If this operand is tied to a previous one, just copy the MCInst
// operand from the earlier one.We can only tie single MCOperand values.
- //assert(OpInfo.OpInfo->MINumOperands == 1 && "Not a singular MCOperand");
+ //assert(OpInfo.MINumOperands == 1 && "Not a singular MCOperand");
unsigned TiedOp = OpInfo.TiedOperandNum;
assert(i > TiedOp && "Tied operand preceeds its target!");
CaseOS << " Inst.addOperand(Inst.getOperand(" << TiedOp << "));\n";
break;
}
case MatchableInfo::ResOperand::RegOperand: {
- std::string N = getQualifiedName(OpInfo.Register);
- CaseOS << " Inst.addOperand(MCOperand::CreateReg(" << N << "));\n";
- Signature += "__reg" + OpInfo.Register->getName();
- }
+ if (OpInfo.Register == 0) {
+ CaseOS << " Inst.addOperand(MCOperand::CreateReg(0));\n";
+ Signature += "__reg0";
+ } else {
+ std::string N = getQualifiedName(OpInfo.Register);
+ CaseOS << " Inst.addOperand(MCOperand::CreateReg(" << N << "));\n";
+ Signature += "__reg" + OpInfo.Register->getName();
+ }
+ }
}
}
-
+
II.ConversionFnKind = Signature;
// Check if we have already generated this signature.
OS << " }\n";
OS << " }\n\n";
- // Classify user defined operands.
+ // Classify user defined operands. To do so, we need to perform a topological
+ // sort of the superclass relationship graph so that we always match the
+ // narrowest type first.
+
+ // Collect the incoming edge counts for each class.
+ std::map<ClassInfo*, unsigned> IncomingEdges;
for (std::vector<ClassInfo*>::iterator it = Info.Classes.begin(),
ie = Info.Classes.end(); it != ie; ++it) {
ClassInfo &CI = **it;
+ if (!CI.isUserClass())
+ continue;
+
+ for (std::vector<ClassInfo*>::iterator SI = CI.SuperClasses.begin(),
+ SE = CI.SuperClasses.end(); SI != SE; ++SI)
+ ++IncomingEdges[*SI];
+ }
+
+ // Initialize a worklist of classes with no incoming edges.
+ std::vector<ClassInfo*> LeafClasses;
+ for (std::vector<ClassInfo*>::iterator it = Info.Classes.begin(),
+ ie = Info.Classes.end(); it != ie; ++it) {
+ if (!IncomingEdges[*it])
+ LeafClasses.push_back(*it);
+ }
+
+ // Iteratively pop the list, process that class, and update the incoming
+ // edge counts for its super classes. When a superclass reaches zero
+ // incoming edges, push it onto the worklist for processing.
+ while (!LeafClasses.empty()) {
+ ClassInfo &CI = *LeafClasses.back();
+ LeafClasses.pop_back();
+
if (!CI.isUserClass())
continue;
if (i) OS << ", ";
OS << "'" << CI.SuperClasses[i]->ClassName << "'";
assert(CI < *CI.SuperClasses[i] && "Invalid class relation!");
+
+ --IncomingEdges[CI.SuperClasses[i]];
+ if (!IncomingEdges[CI.SuperClasses[i]])
+ LeafClasses.push_back(CI.SuperClasses[i]);
}
}
OS << "\n";
OS << " return " << CI.Name << ";\n";
OS << " }\n\n";
}
+
OS << " return InvalidMatchClass;\n";
OS << "}\n\n";
}
OS << "}\n\n";
}
-
-
/// EmitMatchTokenString - Emit the function to match a token string to the
/// appropriate match class value.
static void EmitMatchTokenString(CodeGenTarget &Target,
unsigned NumFeatures = 0;
for (unsigned i = 0, e = ReqFeatures.size(); i != e; ++i) {
SubtargetFeatureInfo *F = Info.getSubtargetFeature(ReqFeatures[i]);
-
+
if (F == 0)
throw TGError(R->getLoc(), "Predicate '" + ReqFeatures[i]->getName() +
"' is not marked as an AssemblerPredicate!");
-
+
if (NumFeatures)
Result += '|';
-
+
Result += F->getEnumName();
++NumFeatures;
}
-
+
if (NumFeatures > 1)
Result = '(' + Result + ')';
return Result;
/// 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) {
+ // Ignore aliases when match-prefix is set.
+ if (!MatchPrefix.empty())
+ return false;
+
std::vector<Record*> Aliases =
- Records.getAllDerivedDefinitions("MnemonicAlias");
+ Info.getRecords().getAllDerivedDefinitions("MnemonicAlias");
if (Aliases.empty()) return false;
OS << "static void ApplyMnemonicAliases(StringRef &Mnemonic, "
"unsigned Features) {\n";
-
+
// Keep track of all the aliases from a mnemonic. Use an std::map so that the
// iteration order of the map is stable.
std::map<std::string, std::vector<Record*> > AliasesFromMnemonic;
-
+
for (unsigned i = 0, e = Aliases.size(); i != e; ++i) {
Record *R = Aliases[i];
AliasesFromMnemonic[R->getValueAsString("FromMnemonic")].push_back(R);
// emit it last.
std::string MatchCode;
int AliasWithNoPredicate = -1;
-
+
for (unsigned i = 0, e = ToVec.size(); i != e; ++i) {
Record *R = ToVec[i];
std::string FeatureMask = GetAliasRequiredFeatures(R, Info);
-
+
// If this unconditionally matches, remember it for later and diagnose
// duplicates.
if (FeatureMask.empty()) {
"two MnemonicAliases with the same 'from' mnemonic!");
throw TGError(R->getLoc(), "this is the other MnemonicAlias.");
}
-
+
AliasWithNoPredicate = i;
continue;
}
-
+
if (!MatchCode.empty())
MatchCode += "else ";
MatchCode += "if ((Features & " + FeatureMask + ") == "+FeatureMask+")\n";
MatchCode += " Mnemonic = \"" +R->getValueAsString("ToMnemonic")+"\";\n";
}
-
+
if (AliasWithNoPredicate != -1) {
Record *R = ToVec[AliasWithNoPredicate];
if (!MatchCode.empty())
MatchCode += "else\n ";
MatchCode += "Mnemonic = \"" + R->getValueAsString("ToMnemonic")+"\";\n";
}
-
+
MatchCode += "return;";
Cases.push_back(std::make_pair(I->first, MatchCode));
}
-
-
+
StringMatcher("Mnemonic", Cases, OS).Emit();
- OS << "}\n";
-
+ OS << "}\n\n";
+
return true;
}
void AsmMatcherEmitter::run(raw_ostream &OS) {
- CodeGenTarget Target;
+ CodeGenTarget Target(Records);
Record *AsmParser = Target.getAsmParser();
std::string ClassName = AsmParser->getValueAsString("AsmParserClassName");
// Compute the information on the instructions to match.
- AsmMatcherInfo Info(AsmParser, Target);
+ AsmMatcherInfo Info(AsmParser, Target, Records);
Info.BuildInfo();
// Sort the instruction table using the partial order on classes. We use
MatchableInfo &A = *Info.Matchables[i];
MatchableInfo &B = *Info.Matchables[j];
- if (A.CouldMatchAmiguouslyWith(B)) {
+ if (A.CouldMatchAmbiguouslyWith(B)) {
errs() << "warning: ambiguous matchables:\n";
A.dump();
errs() << "\nis incomparable with:\n";
OS << " Match_Success, Match_MnemonicFail, Match_InvalidOperand,\n";
OS << " Match_MissingFeature\n";
OS << " };\n";
- OS << " MatchResultTy MatchInstructionImpl(const "
- << "SmallVectorImpl<MCParsedAsmOperand*>"
- << " &Operands, MCInst &Inst, unsigned &ErrorInfo);\n\n";
+ OS << " bool MnemonicIsValid(StringRef Mnemonic);\n";
+ OS << " MatchResultTy MatchInstructionImpl(\n";
+ OS << " const SmallVectorImpl<MCParsedAsmOperand*> &Operands,\n";
+ OS << " MCInst &Inst, unsigned &ErrorInfo);\n\n";
OS << "#endif // GET_ASSEMBLER_HEADER_INFO\n\n";
-
-
-
OS << "\n#ifdef GET_REGISTER_MATCHER\n";
OS << "#undef GET_REGISTER_MATCHER\n\n";
// Generate the function that remaps for mnemonic aliases.
bool HasMnemonicAliases = EmitMnemonicAliases(OS, Info);
-
+
// Generate the unified function to convert operands into an MCInst.
EmitConvertToMCInst(Target, Info.Matchables, OS);
it != ie; ++it)
MaxNumOperands = std::max(MaxNumOperands, (*it)->AsmOperands.size());
-
// Emit the static match table; unused classes get initalized to 0 which is
// guaranteed to be InvalidMatchClass.
//
OS << "};\n\n";
+ // A method to determine if a mnemonic is in the list.
+ OS << "bool " << Target.getName() << ClassName << "::\n"
+ << "MnemonicIsValid(StringRef Mnemonic) {\n";
+ OS << " // Search the table.\n";
+ OS << " std::pair<const MatchEntry*, const MatchEntry*> MnemonicRange =\n";
+ OS << " std::equal_range(MatchTable, MatchTable+"
+ << Info.Matchables.size() << ", Mnemonic, LessOpcode());\n";
+ OS << " return MnemonicRange.first != MnemonicRange.second;\n";
+ OS << "}\n\n";
+
// Finally, build the match function.
OS << Target.getName() << ClassName << "::MatchResultTy "
<< Target.getName() << ClassName << "::\n"
OS << " // Process all MnemonicAliases to remap the mnemonic.\n";
OS << " ApplyMnemonicAliases(Mnemonic, AvailableFeatures);\n\n";
}
-
+
// Emit code to compute the class list for this operand vector.
OS << " // Eliminate obvious mismatches.\n";
OS << " if (Operands.size() > " << (MaxNumOperands+1) << ") {\n";