mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-10 02:29:32 +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 "Record.h"
|
||||||
#include "llvm/ADT/OwningPtr.h"
|
#include "llvm/ADT/OwningPtr.h"
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
|
#include "llvm/ADT/STLExtras.h"
|
||||||
#include "llvm/ADT/StringExtras.h"
|
#include "llvm/ADT/StringExtras.h"
|
||||||
#include "llvm/Support/CommandLine.h"
|
#include "llvm/Support/CommandLine.h"
|
||||||
#include "llvm/Support/Debug.h"
|
#include "llvm/Support/Debug.h"
|
||||||
@ -88,8 +89,8 @@ using namespace llvm;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
static cl::opt<std::string>
|
static cl::opt<std::string>
|
||||||
MatchOneInstr("match-one-instr", cl::desc("Match only the named instruction"),
|
MatchPrefix("match-prefix", cl::init(""),
|
||||||
cl::init(""));
|
cl::desc("Only match instructions with the given prefix"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// FlattenVariants - Flatten an .td file assembly string by selecting the
|
/// 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
|
/// ClassInfo - Helper class for storing the information about a particular
|
||||||
/// class of operands which can be matched.
|
/// class of operands which can be matched.
|
||||||
struct ClassInfo {
|
struct ClassInfo {
|
||||||
enum {
|
enum ClassInfoKind {
|
||||||
Token, ///< The class for a particular token.
|
Token, ///< The class for a particular token.
|
||||||
Register, ///< A register class.
|
Register, ///< A register class.
|
||||||
User ///< A user defined class.
|
UserClass0 ///< The (first) user defined class, subsequent user defined
|
||||||
} Kind;
|
/// 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.
|
/// Name - The class name, suitable for use as an enum.
|
||||||
std::string Name;
|
std::string Name;
|
||||||
@ -297,6 +303,29 @@ struct ClassInfo {
|
|||||||
/// RenderMethod - The name of the operand method to add this operand to an
|
/// RenderMethod - The name of the operand method to add this operand to an
|
||||||
/// MCInst; this is not valid for Token kinds.
|
/// MCInst; this is not valid for Token kinds.
|
||||||
std::string RenderMethod;
|
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
|
/// InstructionInfo - Helper class for storing the necessary information for an
|
||||||
@ -331,6 +360,38 @@ struct InstructionInfo {
|
|||||||
/// function.
|
/// function.
|
||||||
std::string ConversionFnKind;
|
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:
|
public:
|
||||||
void dump();
|
void dump();
|
||||||
};
|
};
|
||||||
@ -460,7 +521,10 @@ AsmMatcherInfo::getOperandClass(const StringRef &Token,
|
|||||||
if (ClassName == "Reg") {
|
if (ClassName == "Reg") {
|
||||||
Entry->Kind = ClassInfo::Register;
|
Entry->Kind = ClassInfo::Register;
|
||||||
} else {
|
} else {
|
||||||
Entry->Kind = ClassInfo::User;
|
if (ClassName == "Mem")
|
||||||
|
Entry->Kind = ClassInfo::UserClass0;
|
||||||
|
else
|
||||||
|
Entry->Kind = ClassInfo::UserClass0 + 1;
|
||||||
}
|
}
|
||||||
Entry->Name = "MCK_" + ClassName;
|
Entry->Name = "MCK_" + ClassName;
|
||||||
Entry->ValueName = OI.Rec->getName();
|
Entry->ValueName = OI.Rec->getName();
|
||||||
@ -479,7 +543,7 @@ void AsmMatcherInfo::BuildInfo(CodeGenTarget &Target) {
|
|||||||
it != ie; ++it) {
|
it != ie; ++it) {
|
||||||
const CodeGenInstruction &CGI = it->second;
|
const CodeGenInstruction &CGI = it->second;
|
||||||
|
|
||||||
if (!MatchOneInstr.empty() && it->first != MatchOneInstr)
|
if (!StringRef(it->first).startswith(MatchPrefix))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
OwningPtr<InstructionInfo> II(new InstructionInfo);
|
OwningPtr<InstructionInfo> II(new InstructionInfo);
|
||||||
@ -537,9 +601,9 @@ void AsmMatcherInfo::BuildInfo(CodeGenTarget &Target) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ConstructConversionFunctions(CodeGenTarget &Target,
|
static void EmitConvertToMCInst(CodeGenTarget &Target,
|
||||||
std::vector<InstructionInfo*> &Infos,
|
std::vector<InstructionInfo*> &Infos,
|
||||||
raw_ostream &OS) {
|
raw_ostream &OS) {
|
||||||
// Write the convert function to a separate stream, so we can drop it after
|
// Write the convert function to a separate stream, so we can drop it after
|
||||||
// the enum.
|
// the enum.
|
||||||
std::string ConvertFnBody;
|
std::string ConvertFnBody;
|
||||||
@ -902,6 +966,10 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
|
|||||||
AsmMatcherInfo Info;
|
AsmMatcherInfo Info;
|
||||||
Info.BuildInfo(Target);
|
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", {
|
DEBUG_WITH_TYPE("instruction_info", {
|
||||||
for (std::vector<InstructionInfo*>::iterator
|
for (std::vector<InstructionInfo*>::iterator
|
||||||
it = Info.Instructions.begin(), ie = Info.Instructions.end();
|
it = Info.Instructions.begin(), ie = Info.Instructions.end();
|
||||||
@ -909,11 +977,35 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
|
|||||||
(*it)->dump();
|
(*it)->dump();
|
||||||
});
|
});
|
||||||
|
|
||||||
// FIXME: At this point we should be able to totally order Infos, if not then
|
// Check for ambiguous instructions.
|
||||||
// we have an ambiguity which the .td file should be forced to resolve.
|
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.
|
InstructionInfo &Next = **it;
|
||||||
ConstructConversionFunctions(Target, Info.Instructions, OS);
|
|
||||||
|
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.
|
// Emit the enumeration for classes which participate in matching.
|
||||||
EmitMatchClassEnumeration(Target, Info.Classes, OS);
|
EmitMatchClassEnumeration(Target, Info.Classes, OS);
|
||||||
|
Loading…
Reference in New Issue
Block a user