have tblgen detect when an instruction would have matched, but

failed because a subtarget feature was not enabled.  Use this to
remove a bunch of hacks from the X86AsmParser for rejecting things
like popfl in 64-bit mode.  Previously these hacks weren't needed,
but were important to get a message better than "invalid instruction"
when used in the wrong mode.

This also fixes bugs where pushal would not be rejected correctly in
32-bit mode (just pusha).

llvm-svn: 113166
This commit is contained in:
Chris Lattner 2010-09-06 20:08:02 +00:00
parent 22bb9cb511
commit 68f7c5b750
2 changed files with 55 additions and 40 deletions

View File

@ -615,28 +615,13 @@ X86Operand *X86ATTAsmParser::ParseMemOperand(unsigned SegReg, SMLoc MemStart) {
bool X86ATTAsmParser::
ParseInstruction(StringRef Name, SMLoc NameLoc,
SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
// The various flavors of pushf and popf use Requires<In32BitMode> and
// Requires<In64BitMode>, but the assembler doesn't yet implement that.
// For now, just do a manual check to prevent silent misencoding.
if (Is64Bit) {
if (Name == "popfl")
return Error(NameLoc, "popfl cannot be encoded in 64-bit mode");
if (Name == "pushfl")
return Error(NameLoc, "pushfl cannot be encoded in 64-bit mode");
if (Name == "pusha")
return Error(NameLoc, "pusha cannot be encoded in 64-bit mode");
} else {
if (Name == "popfq")
return Error(NameLoc, "popfq cannot be encoded in 32-bit mode");
if (Name == "pushfq")
return Error(NameLoc, "pushfq cannot be encoded in 32-bit mode");
}
// The "Jump if rCX Zero" form jcxz is not allowed in 64-bit mode and
// the form jrcxz is not allowed in 32-bit mode.
if (Is64Bit) {
if (Name == "jcxz")
return Error(NameLoc, "jcxz cannot be encoded in 64-bit mode");
// FIXME: We can do jcxz/jecxz, we just don't have the encoding right yet.
if (Name == "jcxz" || Name == "jecxz")
return Error(NameLoc, Name + " cannot be encoded in 64-bit mode");
} else {
if (Name == "jrcxz")
return Error(NameLoc, "jrcxz cannot be encoded in 32-bit mode");
@ -881,8 +866,15 @@ X86ATTAsmParser::MatchInstruction(SMLoc IDLoc,
assert(!Operands.empty() && "Unexpect empty operand list!");
// First, try a direct match.
if (MatchInstructionImpl(Operands, Inst) == Match_Success)
switch (MatchInstructionImpl(Operands, Inst)) {
case Match_Success:
return false;
case Match_MissingFeature:
Error(IDLoc, "instruction requires a CPU feature not currently enabled");
return true;
default:
break;
}
// FIXME: Ideally, we would only attempt suffix matches for things which are
// valid prefixes, and we could just infer the right unambiguous
@ -901,13 +893,13 @@ X86ATTAsmParser::MatchInstruction(SMLoc IDLoc,
// Check for the various suffix matches.
Tmp[Base.size()] = 'b';
bool MatchB = MatchInstructionImpl(Operands, Inst) != Match_Success;
MatchResultTy MatchB = MatchInstructionImpl(Operands, Inst);
Tmp[Base.size()] = 'w';
bool MatchW = MatchInstructionImpl(Operands, Inst) != Match_Success;
MatchResultTy MatchW = MatchInstructionImpl(Operands, Inst);
Tmp[Base.size()] = 'l';
bool MatchL = MatchInstructionImpl(Operands, Inst) != Match_Success;
MatchResultTy MatchL = MatchInstructionImpl(Operands, Inst);
Tmp[Base.size()] = 'q';
bool MatchQ = MatchInstructionImpl(Operands, Inst) != Match_Success;
MatchResultTy MatchQ = MatchInstructionImpl(Operands, Inst);
// Restore the old token.
Op->setTokenValue(Base);
@ -915,23 +907,26 @@ X86ATTAsmParser::MatchInstruction(SMLoc IDLoc,
// If exactly one matched, then we treat that as a successful match (and the
// instruction will already have been filled in correctly, since the failing
// matches won't have modified it).
if (MatchB + MatchW + MatchL + MatchQ == 3)
unsigned NumSuccessfulMatches =
(MatchB == Match_Success) + (MatchW == Match_Success) +
(MatchL == Match_Success) + (MatchQ == Match_Success);
if (NumSuccessfulMatches == 1)
return false;
// Otherwise, the match failed.
// Otherwise, the match failed, try to produce a decent error message.
// If we had multiple suffix matches, then identify this as an ambiguous
// match.
if (MatchB + MatchW + MatchL + MatchQ != 4) {
if (NumSuccessfulMatches > 1) {
char MatchChars[4];
unsigned NumMatches = 0;
if (!MatchB)
if (MatchB == Match_Success)
MatchChars[NumMatches++] = 'b';
if (!MatchW)
if (MatchW == Match_Success)
MatchChars[NumMatches++] = 'w';
if (!MatchL)
if (MatchL == Match_Success)
MatchChars[NumMatches++] = 'l';
if (!MatchQ)
if (MatchQ == Match_Success)
MatchChars[NumMatches++] = 'q';
SmallString<126> Msg;
@ -946,11 +941,26 @@ X86ATTAsmParser::MatchInstruction(SMLoc IDLoc,
}
OS << ")";
Error(IDLoc, OS.str());
} else {
// FIXME: We should give nicer diagnostics about the exact failure.
Error(IDLoc, "unrecognized instruction");
return true;
}
unsigned NumMatchFailures =
(MatchB == Match_Fail) + (MatchW == Match_Fail) +
(MatchL == Match_Fail) + (MatchQ == Match_Fail);
// If one instruction matched with a missing feature, report this as a
// missing feature.
if ((MatchB == Match_MissingFeature) + (MatchW == Match_MissingFeature) +
(MatchL == Match_MissingFeature) + (MatchQ == Match_MissingFeature) == 1&&
NumMatchFailures == 3) {
Error(IDLoc, "instruction requires a CPU feature not currently enabled");
return true;
}
// If all of these were an outright failure, report it in a useless way.
// FIXME: We should give nicer diagnostics about the exact failure.
Error(IDLoc, "unrecognized instruction");
return true;
}

View File

@ -1549,7 +1549,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " unsigned ComputeAvailableFeatures(const " <<
Target.getName() << "Subtarget *Subtarget) const;\n";
OS << " enum MatchResultTy {\n";
OS << " Match_Success, Match_Fail\n";
OS << " Match_Success, Match_Fail, Match_MissingFeature\n";
OS << " };\n";
OS << " MatchResultTy MatchInstructionImpl(const SmallVectorImpl<MCParsedAsmOperand*>"
<< " &Operands, MCInst &Inst);\n\n";
@ -1678,21 +1678,24 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
// Emit code to search the table.
OS << " // Search the table.\n";
OS << " bool HadMatchOtherThanFeatures = false;\n";
OS << " for (const MatchEntry *it = MatchTable, "
<< "*ie = MatchTable + " << Info.Instructions.size()
<< "; it != ie; ++it) {\n";
// Emit check that the required features are available.
OS << " if ((AvailableFeatures & it->RequiredFeatures) "
<< "!= it->RequiredFeatures)\n";
OS << " continue;\n";
// Emit check that the subclasses match.
for (unsigned i = 0; i != MaxNumOperands; ++i) {
OS << " if (!IsSubclass(Classes["
<< i << "], it->Classes[" << i << "]))\n";
OS << " continue;\n";
}
// Emit check that the required features are available.
OS << " if ((AvailableFeatures & it->RequiredFeatures) "
<< "!= it->RequiredFeatures) {\n";
OS << " HadMatchOtherThanFeatures = true;\n";
OS << " continue;\n";
OS << " }\n";
OS << "\n";
OS << " ConvertToMCInst(it->ConvertFn, Inst, it->Opcode, Operands);\n";
@ -1706,6 +1709,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " return Match_Success;\n";
OS << " }\n\n";
OS << " // Okay, we had no match. Try to return a useful error code.\n";
OS << " if (HadMatchOtherThanFeatures) return Match_MissingFeature;\n";
OS << " return Match_Fail;\n";
OS << "}\n\n";