mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-14 11:32:34 +00:00
llvm-mc/AsmParser: Sketch infrastructure for ordering instructions & detecting
ambiguities. - Currently there are 483 ambiguities to resolve. :) git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@78522 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
094da67bd7
commit
606e8ad796
@ -78,6 +78,7 @@
|
||||
#include "Record.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
@ -88,8 +89,8 @@ using namespace llvm;
|
||||
|
||||
namespace {
|
||||
static cl::opt<std::string>
|
||||
MatchOneInstr("match-one-instr", cl::desc("Match only the named instruction"),
|
||||
cl::init(""));
|
||||
MatchPrefix("match-prefix", cl::init(""),
|
||||
cl::desc("Only match instructions with the given prefix"));
|
||||
}
|
||||
|
||||
/// FlattenVariants - Flatten an .td file assembly string by selecting the
|
||||
@ -276,11 +277,16 @@ namespace {
|
||||
/// ClassInfo - Helper class for storing the information about a particular
|
||||
/// class of operands which can be matched.
|
||||
struct ClassInfo {
|
||||
enum {
|
||||
enum ClassInfoKind {
|
||||
Token, ///< The class for a particular token.
|
||||
Register, ///< A register class.
|
||||
User ///< A user defined class.
|
||||
} Kind;
|
||||
UserClass0 ///< The (first) user defined class, subsequent user defined
|
||||
/// classes are UserClass0+1, and so on.
|
||||
};
|
||||
|
||||
/// Kind - The class kind, which is either a predefined kind, or (UserClass0 +
|
||||
/// N) for the Nth user defined class.
|
||||
unsigned Kind;
|
||||
|
||||
/// Name - The class name, suitable for use as an enum.
|
||||
std::string Name;
|
||||
@ -297,6 +303,29 @@ struct ClassInfo {
|
||||
/// RenderMethod - The name of the operand method to add this operand to an
|
||||
/// MCInst; this is not valid for Token kinds.
|
||||
std::string RenderMethod;
|
||||
|
||||
/// operator< - Compare two classes.
|
||||
bool operator<(const ClassInfo &RHS) const {
|
||||
// Incompatible kinds are comparable.
|
||||
if (Kind != RHS.Kind)
|
||||
return Kind < RHS.Kind;
|
||||
|
||||
switch (Kind) {
|
||||
case Token:
|
||||
// Tokens are always comparable.
|
||||
//
|
||||
// FIXME: Compare by enum value.
|
||||
return ValueName < RHS.ValueName;
|
||||
|
||||
case Register:
|
||||
// FIXME: Compare by subset relation.
|
||||
return false;
|
||||
|
||||
default:
|
||||
// FIXME: Allow user defined relation.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// InstructionInfo - Helper class for storing the necessary information for an
|
||||
@ -331,6 +360,38 @@ struct InstructionInfo {
|
||||
/// function.
|
||||
std::string ConversionFnKind;
|
||||
|
||||
/// operator< - Compare two instructions.
|
||||
bool operator<(const InstructionInfo &RHS) const {
|
||||
// Order first by the number of operands (which is unambiguous).
|
||||
if (Operands.size() != RHS.Operands.size())
|
||||
return Operands.size() < RHS.Operands.size();
|
||||
|
||||
// Otherwise, order by lexicographic comparison of tokens and operand kinds
|
||||
// (these can never be ambiguous).
|
||||
for (unsigned i = 0, e = Operands.size(); i != e; ++i)
|
||||
if (Operands[i].Class->Kind != RHS.Operands[i].Class->Kind ||
|
||||
Operands[i].Class->Kind == ClassInfo::Token)
|
||||
if (*Operands[i].Class < *RHS.Operands[i].Class)
|
||||
return true;
|
||||
|
||||
// Finally, order by the component wise comparison of operand classes. We
|
||||
// don't want to rely on the lexigraphic ordering of elements, so we define
|
||||
// only define the ordering when it is unambiguous. That is, when some pair
|
||||
// compares less than and no pair compares greater than.
|
||||
|
||||
// Check that no pair compares greater than.
|
||||
for (unsigned i = 0, e = Operands.size(); i != e; ++i)
|
||||
if (*RHS.Operands[i].Class < *Operands[i].Class)
|
||||
return false;
|
||||
|
||||
// Otherwise, return true if some pair compares less than.
|
||||
for (unsigned i = 0, e = Operands.size(); i != e; ++i)
|
||||
if (*Operands[i].Class < *RHS.Operands[i].Class)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
void dump();
|
||||
};
|
||||
@ -460,7 +521,10 @@ AsmMatcherInfo::getOperandClass(const StringRef &Token,
|
||||
if (ClassName == "Reg") {
|
||||
Entry->Kind = ClassInfo::Register;
|
||||
} else {
|
||||
Entry->Kind = ClassInfo::User;
|
||||
if (ClassName == "Mem")
|
||||
Entry->Kind = ClassInfo::UserClass0;
|
||||
else
|
||||
Entry->Kind = ClassInfo::UserClass0 + 1;
|
||||
}
|
||||
Entry->Name = "MCK_" + ClassName;
|
||||
Entry->ValueName = OI.Rec->getName();
|
||||
@ -479,7 +543,7 @@ void AsmMatcherInfo::BuildInfo(CodeGenTarget &Target) {
|
||||
it != ie; ++it) {
|
||||
const CodeGenInstruction &CGI = it->second;
|
||||
|
||||
if (!MatchOneInstr.empty() && it->first != MatchOneInstr)
|
||||
if (!StringRef(it->first).startswith(MatchPrefix))
|
||||
continue;
|
||||
|
||||
OwningPtr<InstructionInfo> II(new InstructionInfo);
|
||||
@ -537,9 +601,9 @@ void AsmMatcherInfo::BuildInfo(CodeGenTarget &Target) {
|
||||
}
|
||||
}
|
||||
|
||||
static void ConstructConversionFunctions(CodeGenTarget &Target,
|
||||
std::vector<InstructionInfo*> &Infos,
|
||||
raw_ostream &OS) {
|
||||
static void EmitConvertToMCInst(CodeGenTarget &Target,
|
||||
std::vector<InstructionInfo*> &Infos,
|
||||
raw_ostream &OS) {
|
||||
// Write the convert function to a separate stream, so we can drop it after
|
||||
// the enum.
|
||||
std::string ConvertFnBody;
|
||||
@ -902,6 +966,10 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
|
||||
AsmMatcherInfo Info;
|
||||
Info.BuildInfo(Target);
|
||||
|
||||
// Sort the instruction table using the partial order on classes.
|
||||
std::sort(Info.Instructions.begin(), Info.Instructions.end(),
|
||||
less_ptr<InstructionInfo>());
|
||||
|
||||
DEBUG_WITH_TYPE("instruction_info", {
|
||||
for (std::vector<InstructionInfo*>::iterator
|
||||
it = Info.Instructions.begin(), ie = Info.Instructions.end();
|
||||
@ -909,11 +977,35 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
|
||||
(*it)->dump();
|
||||
});
|
||||
|
||||
// FIXME: At this point we should be able to totally order Infos, if not then
|
||||
// we have an ambiguity which the .td file should be forced to resolve.
|
||||
// Check for ambiguous instructions.
|
||||
unsigned NumAmbiguous = 0;
|
||||
for (std::vector<InstructionInfo*>::const_iterator it =
|
||||
Info.Instructions.begin(), ie = Info.Instructions.end() - 1;
|
||||
it != ie;) {
|
||||
InstructionInfo &II = **it;
|
||||
++it;
|
||||
|
||||
// Generate the terminal actions to convert operands into an MCInst.
|
||||
ConstructConversionFunctions(Target, Info.Instructions, OS);
|
||||
InstructionInfo &Next = **it;
|
||||
|
||||
if (!(II < Next)){
|
||||
DEBUG_WITH_TYPE("ambiguous_instrs", {
|
||||
errs() << "warning: ambiguous instruction match:\n";
|
||||
II.dump();
|
||||
errs() << "\nis incomparable with:\n";
|
||||
Next.dump();
|
||||
errs() << "\n\n";
|
||||
});
|
||||
++NumAmbiguous;
|
||||
}
|
||||
}
|
||||
if (NumAmbiguous)
|
||||
DEBUG_WITH_TYPE("ambiguous_instrs", {
|
||||
errs() << "warning: " << NumAmbiguous
|
||||
<< " ambiguous instructions!\n";
|
||||
});
|
||||
|
||||
// Generate the unified function to convert operands into an MCInst.
|
||||
EmitConvertToMCInst(Target, Info.Instructions, OS);
|
||||
|
||||
// Emit the enumeration for classes which participate in matching.
|
||||
EmitMatchClassEnumeration(Target, Info.Classes, OS);
|
||||
|
Loading…
Reference in New Issue
Block a user