mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-26 13:10:34 +00:00
refactor/cleanup MatchableInfo by eliminating the Tokens array,
merging it into a Token field in Operand, and moving the first token to an explicit mnemonic field. These were parallel arrays before (except for the mnemonic) which kept confusing me. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@118024 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
3ff57094a7
commit
d19ec05e07
@ -93,82 +93,6 @@ static cl::opt<std::string>
|
||||
MatchPrefix("match-prefix", cl::init(""),
|
||||
cl::desc("Only match instructions with the given prefix"));
|
||||
|
||||
/// TokenizeAsmString - Tokenize a simplified assembly string.
|
||||
static void TokenizeAsmString(StringRef AsmString,
|
||||
SmallVectorImpl<StringRef> &Tokens) {
|
||||
unsigned Prev = 0;
|
||||
bool InTok = true;
|
||||
for (unsigned i = 0, e = AsmString.size(); i != e; ++i) {
|
||||
switch (AsmString[i]) {
|
||||
case '[':
|
||||
case ']':
|
||||
case '*':
|
||||
case '!':
|
||||
case ' ':
|
||||
case '\t':
|
||||
case ',':
|
||||
if (InTok) {
|
||||
Tokens.push_back(AsmString.slice(Prev, i));
|
||||
InTok = false;
|
||||
}
|
||||
if (!isspace(AsmString[i]) && AsmString[i] != ',')
|
||||
Tokens.push_back(AsmString.substr(i, 1));
|
||||
Prev = i + 1;
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
if (InTok) {
|
||||
Tokens.push_back(AsmString.slice(Prev, i));
|
||||
InTok = false;
|
||||
}
|
||||
++i;
|
||||
assert(i != AsmString.size() && "Invalid quoted character");
|
||||
Tokens.push_back(AsmString.substr(i, 1));
|
||||
Prev = i + 1;
|
||||
break;
|
||||
|
||||
case '$': {
|
||||
// If this isn't "${", treat like a normal token.
|
||||
if (i + 1 == AsmString.size() || AsmString[i + 1] != '{') {
|
||||
if (InTok) {
|
||||
Tokens.push_back(AsmString.slice(Prev, i));
|
||||
InTok = false;
|
||||
}
|
||||
Prev = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (InTok) {
|
||||
Tokens.push_back(AsmString.slice(Prev, i));
|
||||
InTok = false;
|
||||
}
|
||||
|
||||
StringRef::iterator End =
|
||||
std::find(AsmString.begin() + i, AsmString.end(), '}');
|
||||
assert(End != AsmString.end() && "Missing brace in operand reference!");
|
||||
size_t EndPos = End - AsmString.begin();
|
||||
Tokens.push_back(AsmString.slice(i, EndPos+1));
|
||||
Prev = EndPos + 1;
|
||||
i = EndPos;
|
||||
break;
|
||||
}
|
||||
|
||||
case '.':
|
||||
if (InTok) {
|
||||
Tokens.push_back(AsmString.slice(Prev, i));
|
||||
}
|
||||
Prev = i;
|
||||
InTok = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
InTok = true;
|
||||
}
|
||||
}
|
||||
if (InTok && Prev != AsmString.size())
|
||||
Tokens.push_back(AsmString.substr(Prev));
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
class AsmMatcherInfo;
|
||||
@ -324,14 +248,16 @@ public:
|
||||
/// instruction or alias which is capable of being matched.
|
||||
struct MatchableInfo {
|
||||
struct Operand {
|
||||
/// Token - This is the token that the operand came from.
|
||||
StringRef Token;
|
||||
|
||||
/// The unique class instance this operand should match.
|
||||
ClassInfo *Class;
|
||||
|
||||
/// The original operand this corresponds to, if any.
|
||||
const CGIOperandList::OperandInfo *OperandInfo;
|
||||
|
||||
Operand(ClassInfo *C, const CGIOperandList::OperandInfo *OpInfo)
|
||||
: Class(C), OperandInfo(OpInfo) {}
|
||||
explicit Operand(StringRef T) : Token(T), Class(0), OperandInfo(0) {}
|
||||
};
|
||||
|
||||
/// InstrName - The target name for this instruction.
|
||||
@ -344,9 +270,10 @@ struct MatchableInfo {
|
||||
/// removed).
|
||||
std::string AsmString;
|
||||
|
||||
/// Tokens - The tokenized assembly pattern that this instruction matches.
|
||||
SmallVector<StringRef, 4> Tokens;
|
||||
|
||||
/// Mnemonic - This is the first token of the matched instruction, its
|
||||
/// mnemonic.
|
||||
StringRef Mnemonic;
|
||||
|
||||
/// AsmOperands - The textual operands that this instruction matches,
|
||||
/// including literal tokens for the mnemonic, etc.
|
||||
SmallVector<Operand, 4> AsmOperands;
|
||||
@ -382,16 +309,16 @@ struct MatchableInfo {
|
||||
/// and perform a bunch of validity checking.
|
||||
bool Validate(StringRef CommentDelimiter, bool Hack) const;
|
||||
|
||||
/// getSingletonRegisterForToken - If the specified token is a singleton
|
||||
/// getSingletonRegisterForAsmOperand - If the specified token is a singleton
|
||||
/// register, return the Record for it, otherwise return null.
|
||||
Record *getSingletonRegisterForToken(unsigned i,
|
||||
const AsmMatcherInfo &Info) const;
|
||||
Record *getSingletonRegisterForAsmOperand(unsigned i,
|
||||
const AsmMatcherInfo &Info) const;
|
||||
|
||||
/// operator< - Compare two matchables.
|
||||
bool operator<(const MatchableInfo &RHS) const {
|
||||
// The primary comparator is the instruction mnemonic.
|
||||
if (Tokens[0] != RHS.Tokens[0])
|
||||
return Tokens[0] < RHS.Tokens[0];
|
||||
if (Mnemonic != RHS.Mnemonic)
|
||||
return Mnemonic < RHS.Mnemonic;
|
||||
|
||||
if (AsmOperands.size() != RHS.AsmOperands.size())
|
||||
return AsmOperands.size() < RHS.AsmOperands.size();
|
||||
@ -413,7 +340,7 @@ struct MatchableInfo {
|
||||
/// strictly superior match).
|
||||
bool CouldMatchAmiguouslyWith(const MatchableInfo &RHS) {
|
||||
// The primary comparator is the instruction mnemonic.
|
||||
if (Tokens[0] != RHS.Tokens[0])
|
||||
if (Mnemonic != RHS.Mnemonic)
|
||||
return false;
|
||||
|
||||
// The number of operands is unambiguous.
|
||||
@ -448,6 +375,9 @@ struct MatchableInfo {
|
||||
}
|
||||
|
||||
void dump();
|
||||
|
||||
private:
|
||||
void TokenizeAsmString(const AsmMatcherInfo &Info);
|
||||
};
|
||||
|
||||
/// SubtargetFeatureInfo - Helper class for storing information on a subtarget
|
||||
@ -535,20 +465,13 @@ public:
|
||||
}
|
||||
|
||||
void MatchableInfo::dump() {
|
||||
errs() << InstrName << " -- " << "flattened:\"" << AsmString << '\"'
|
||||
<< ", tokens:[";
|
||||
for (unsigned i = 0, e = Tokens.size(); i != e; ++i) {
|
||||
errs() << Tokens[i];
|
||||
if (i + 1 != e)
|
||||
errs() << ", ";
|
||||
}
|
||||
errs() << "]\n";
|
||||
errs() << InstrName << " -- " << "flattened:\"" << AsmString << "\"\n";
|
||||
|
||||
for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) {
|
||||
Operand &Op = AsmOperands[i];
|
||||
errs() << " op[" << i << "] = " << Op.Class->ClassName << " - ";
|
||||
if (Op.Class->Kind == ClassInfo::Token) {
|
||||
errs() << '\"' << Tokens[i] << "\"\n";
|
||||
errs() << '\"' << Op.Token << "\"\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -568,7 +491,7 @@ void MatchableInfo::Initialize(const AsmMatcherInfo &Info,
|
||||
// TODO: Eventually support asmparser for Variant != 0.
|
||||
AsmString = CodeGenInstruction::FlattenAsmStringVariants(AsmString, 0);
|
||||
|
||||
TokenizeAsmString(AsmString, Tokens);
|
||||
TokenizeAsmString(Info);
|
||||
|
||||
// Compute the require features.
|
||||
std::vector<Record*> Predicates =TheDef->getValueAsListOfDefs("Predicates");
|
||||
@ -578,12 +501,98 @@ void MatchableInfo::Initialize(const AsmMatcherInfo &Info,
|
||||
RequiredFeatures.push_back(Feature);
|
||||
|
||||
// Collect singleton registers, if used.
|
||||
for (unsigned i = 0, e = Tokens.size(); i != e; ++i) {
|
||||
if (Record *Reg = getSingletonRegisterForToken(i, Info))
|
||||
for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) {
|
||||
if (Record *Reg = getSingletonRegisterForAsmOperand(i, Info))
|
||||
SingletonRegisters.insert(Reg);
|
||||
}
|
||||
}
|
||||
|
||||
/// TokenizeAsmString - Tokenize a simplified assembly string.
|
||||
void MatchableInfo::TokenizeAsmString(const AsmMatcherInfo &Info) {
|
||||
StringRef String = AsmString;
|
||||
unsigned Prev = 0;
|
||||
bool InTok = true;
|
||||
for (unsigned i = 0, e = String.size(); i != e; ++i) {
|
||||
switch (String[i]) {
|
||||
case '[':
|
||||
case ']':
|
||||
case '*':
|
||||
case '!':
|
||||
case ' ':
|
||||
case '\t':
|
||||
case ',':
|
||||
if (InTok) {
|
||||
AsmOperands.push_back(Operand(String.slice(Prev, i)));
|
||||
InTok = false;
|
||||
}
|
||||
if (!isspace(String[i]) && String[i] != ',')
|
||||
AsmOperands.push_back(Operand(String.substr(i, 1)));
|
||||
Prev = i + 1;
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
if (InTok) {
|
||||
AsmOperands.push_back(Operand(String.slice(Prev, i)));
|
||||
InTok = false;
|
||||
}
|
||||
++i;
|
||||
assert(i != String.size() && "Invalid quoted character");
|
||||
AsmOperands.push_back(Operand(String.substr(i, 1)));
|
||||
Prev = i + 1;
|
||||
break;
|
||||
|
||||
case '$': {
|
||||
// If this isn't "${", treat like a normal token.
|
||||
if (i + 1 == String.size() || String[i + 1] != '{') {
|
||||
if (InTok) {
|
||||
AsmOperands.push_back(Operand(String.slice(Prev, i)));
|
||||
InTok = false;
|
||||
}
|
||||
Prev = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (InTok) {
|
||||
AsmOperands.push_back(Operand(String.slice(Prev, i)));
|
||||
InTok = false;
|
||||
}
|
||||
|
||||
StringRef::iterator End = std::find(String.begin() + i, String.end(),'}');
|
||||
assert(End != String.end() && "Missing brace in operand reference!");
|
||||
size_t EndPos = End - String.begin();
|
||||
AsmOperands.push_back(Operand(String.slice(i, EndPos+1)));
|
||||
Prev = EndPos + 1;
|
||||
i = EndPos;
|
||||
break;
|
||||
}
|
||||
|
||||
case '.':
|
||||
if (InTok)
|
||||
AsmOperands.push_back(Operand(String.slice(Prev, i)));
|
||||
Prev = i;
|
||||
InTok = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
InTok = true;
|
||||
}
|
||||
}
|
||||
if (InTok && Prev != String.size())
|
||||
AsmOperands.push_back(Operand(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?");
|
||||
Mnemonic = AsmOperands[0].Token;
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// getRegisterRecord - Get the register record for \arg name, or 0.
|
||||
static Record *getRegisterRecord(CodeGenTarget &Target, StringRef Name) {
|
||||
@ -623,24 +632,25 @@ bool MatchableInfo::Validate(StringRef CommentDelimiter, bool Hack) const {
|
||||
// Also, check for instructions which reference the operand multiple times;
|
||||
// this implies a constraint we would not honor.
|
||||
std::set<std::string> OperandNames;
|
||||
for (unsigned i = 1, e = Tokens.size(); i < e; ++i) {
|
||||
if (Tokens[i][0] == '$' && Tokens[i].find(':') != StringRef::npos)
|
||||
for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) {
|
||||
StringRef Tok = AsmOperands[i].Token;
|
||||
if (Tok[0] == '$' && Tok.find(':') != StringRef::npos)
|
||||
throw TGError(TheDef->getLoc(),
|
||||
"matchable with operand modifier '" + Tokens[i].str() +
|
||||
"matchable with operand modifier '" + Tok.str() +
|
||||
"' not supported by asm matcher. Mark isCodeGenOnly!");
|
||||
|
||||
// Verify that any operand is only mentioned once.
|
||||
if (Tokens[i][0] == '$' && !OperandNames.insert(Tokens[i]).second) {
|
||||
if (Tok[0] == '$' && !OperandNames.insert(Tok).second) {
|
||||
if (!Hack)
|
||||
throw TGError(TheDef->getLoc(),
|
||||
"ERROR: matchable with tied operand '" + Tokens[i].str() +
|
||||
"ERROR: matchable with tied operand '" + Tok.str() +
|
||||
"' can never be matched!");
|
||||
// FIXME: Should reject these. The ARM backend hits this with $lane in a
|
||||
// bunch of instructions. It is unclear what the right answer is.
|
||||
DEBUG({
|
||||
errs() << "warning: '" << InstrName << "': "
|
||||
<< "ignoring instruction with tied operand '"
|
||||
<< Tokens[i].str() << "'\n";
|
||||
<< Tok.str() << "'\n";
|
||||
});
|
||||
return false;
|
||||
}
|
||||
@ -650,11 +660,11 @@ bool MatchableInfo::Validate(StringRef CommentDelimiter, bool Hack) const {
|
||||
}
|
||||
|
||||
|
||||
/// getSingletonRegisterForToken - If the specified token is a singleton
|
||||
/// getSingletonRegisterForAsmOperand - If the specified token is a singleton
|
||||
/// register, return the register name, otherwise return a null StringRef.
|
||||
Record *MatchableInfo::
|
||||
getSingletonRegisterForToken(unsigned i, const AsmMatcherInfo &Info) const {
|
||||
StringRef Tok = Tokens[i];
|
||||
getSingletonRegisterForAsmOperand(unsigned i, const AsmMatcherInfo &Info) const{
|
||||
StringRef Tok = AsmOperands[i].Token;
|
||||
if (!Tok.startswith(Info.RegisterPrefix))
|
||||
return 0;
|
||||
|
||||
@ -1000,31 +1010,22 @@ void AsmMatcherInfo::BuildInfo() {
|
||||
ie = Matchables.end(); it != ie; ++it) {
|
||||
MatchableInfo *II = *it;
|
||||
|
||||
// The first token of the instruction is the mnemonic, which must be a
|
||||
// simple string, not a $foo variable or a singleton register.
|
||||
assert(!II->Tokens.empty() && "Instruction has no tokens?");
|
||||
StringRef Mnemonic = II->Tokens[0];
|
||||
if (Mnemonic[0] == '$' || II->getSingletonRegisterForToken(0, *this))
|
||||
throw TGError(II->TheDef->getLoc(),
|
||||
"Invalid instruction mnemonic '" + Mnemonic.str() + "'!");
|
||||
|
||||
// Parse the tokens after the mnemonic.
|
||||
for (unsigned i = 1, e = II->Tokens.size(); i != e; ++i) {
|
||||
StringRef Token = II->Tokens[i];
|
||||
for (unsigned i = 0, e = II->AsmOperands.size(); i != e; ++i) {
|
||||
MatchableInfo::Operand &Op = II->AsmOperands[i];
|
||||
StringRef Token = Op.Token;
|
||||
|
||||
// Check for singleton registers.
|
||||
if (Record *RegRecord = II->getSingletonRegisterForToken(i, *this)) {
|
||||
MatchableInfo::Operand Op(RegisterClasses[RegRecord], 0);
|
||||
if (Record *RegRecord = II->getSingletonRegisterForAsmOperand(i, *this)) {
|
||||
Op.Class = RegisterClasses[RegRecord];
|
||||
assert(Op.Class && Op.Class->Registers.size() == 1 &&
|
||||
"Unexpected class for singleton register");
|
||||
II->AsmOperands.push_back(Op);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for simple tokens.
|
||||
if (Token[0] != '$') {
|
||||
II->AsmOperands.push_back(MatchableInfo::Operand(getTokenClass(Token),
|
||||
0));
|
||||
Op.Class = getTokenClass(Token);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1061,8 +1062,8 @@ void AsmMatcherInfo::BuildInfo() {
|
||||
assert(OI && "Unable to find tied operand target!");
|
||||
}
|
||||
|
||||
II->AsmOperands.push_back(MatchableInfo::Operand(getOperandClass(Token,
|
||||
*OI), OI));
|
||||
Op.Class = getOperandClass(Token, *OI);
|
||||
Op.OperandInfo = OI;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1749,7 +1750,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
|
||||
MatchableInfo &II = **it;
|
||||
|
||||
OS << " { " << Target.getName() << "::" << II.InstrName
|
||||
<< ", \"" << II.Tokens[0] << "\""
|
||||
<< ", \"" << II.Mnemonic << "\""
|
||||
<< ", " << II.ConversionFnKind << ", { ";
|
||||
for (unsigned i = 0, e = II.AsmOperands.size(); i != e; ++i) {
|
||||
MatchableInfo::Operand &Op = II.AsmOperands[i];
|
||||
|
Loading…
Reference in New Issue
Block a user