llvm-mc/AsmMatcher: Switch to a unified function to convert operands to MCInst,

so that terminal states are as simple as possible.
 - If we were willing to assume that the order that operands get inserted in the
   MCInst is fixed we could actually dispose with this altogether, although it
   might be nice to have the flexibility to change it later.

llvm-svn: 78458
This commit is contained in:
Daniel Dunbar 2009-08-08 05:24:34 +00:00
parent f8ba5e9e6e
commit 713302883e
1 changed files with 73 additions and 42 deletions

View File

@ -81,8 +81,9 @@
#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"
#include <set>
#include <list> #include <list>
#include <map>
#include <set>
using namespace llvm; using namespace llvm;
namespace { namespace {
@ -272,6 +273,8 @@ static bool IsAssemblerInstruction(const StringRef &Name,
namespace { namespace {
/// InstructionInfo - Helper class for storing the necessary information for an
/// instruction which is capable of being matched.
struct InstructionInfo { struct InstructionInfo {
struct Operand { struct Operand {
enum { enum {
@ -312,14 +315,10 @@ struct InstructionInfo {
/// Operands - The operands that this instruction matches. /// Operands - The operands that this instruction matches.
SmallVector<Operand, 4> Operands; SmallVector<Operand, 4> Operands;
/// ConversionFn - The name of the conversion function to convert parsed /// ConversionFnKind - The enum value which is passed to the generated
/// operands into an MCInst for this function. /// ConvertToMCInst to convert parsed operands into an MCInst for this
std::string ConversionFn; /// function.
std::string ConversionFnKind;
/// OrderedClassOperands - The indices of the class operands, ordered by their
/// MIOperandNo order (which is the order they should be passed to the
/// conversion function).
SmallVector<unsigned, 4> OrderedClassOperands;
public: public:
void dump(); void dump();
@ -419,7 +418,12 @@ static void BuildInstructionInfos(CodeGenTarget &Target,
// FIXME: Yet another total hack. // FIXME: Yet another total hack.
if (RV->getValue()->getAsString() == "iPTR" || if (RV->getValue()->getAsString() == "iPTR" ||
OI.Rec->getName() == "i8mem_NOREX" ||
OI.Rec->getName() == "lea32mem" || OI.Rec->getName() == "lea32mem" ||
OI.Rec->getName() == "lea64mem" ||
OI.Rec->getName() == "i128mem" ||
OI.Rec->getName() == "sdmem" ||
OI.Rec->getName() == "ssmem" ||
OI.Rec->getName() == "lea64_32mem") { OI.Rec->getName() == "lea64_32mem") {
Op.AsClass.ClassName = "Mem"; Op.AsClass.ClassName = "Mem";
Op.AsClass.PredicateMethod = "isMem"; Op.AsClass.PredicateMethod = "isMem";
@ -448,9 +452,32 @@ static void BuildInstructionInfos(CodeGenTarget &Target,
static void ConstructConversionFunctions(CodeGenTarget &Target, static void ConstructConversionFunctions(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
// the enum.
std::string ConvertFnBody;
raw_string_ostream CvtOS(ConvertFnBody);
// Function we have already generated. // Function we have already generated.
std::set<std::string> GeneratedFns; std::set<std::string> GeneratedFns;
// Start the unified conversion function.
CvtOS << "static bool ConvertToMCInst(ConversionKind Kind, MCInst &Inst, "
<< "unsigned Opcode,\n"
<< " SmallVectorImpl<"
<< Target.getName() << "Operand> &Operands) {\n";
CvtOS << " Inst.setOpcode(Opcode);\n";
CvtOS << " switch (Kind) {\n";
CvtOS << " default:\n";
// Start the enum, which we will generate inline.
OS << "// Unified function for converting operants to MCInst instances.\n\n";
OS << "namespace {\n\n";
OS << "enum ConversionKind {\n";
for (std::vector<InstructionInfo*>::const_iterator it = Infos.begin(), for (std::vector<InstructionInfo*>::const_iterator it = Infos.begin(),
ie = Infos.end(); it != ie; ++it) { ie = Infos.end(); it != ie; ++it) {
InstructionInfo &II = **it; InstructionInfo &II = **it;
@ -481,8 +508,7 @@ static void ConstructConversionFunctions(CodeGenTarget &Target,
assert(CurIndex <= Op.AsClass.Operand->MIOperandNo && assert(CurIndex <= Op.AsClass.Operand->MIOperandNo &&
"Duplicate match for instruction operand!"); "Duplicate match for instruction operand!");
// Save the conversion index, for use by the matcher. Signature += "_";
II.OrderedClassOperands.push_back(MIOperandList[i].second);
// Skip operands which weren't matched by anything, this occurs when the // Skip operands which weren't matched by anything, this occurs when the
// .td file encodes "implicit" operands as explicit ones. // .td file encodes "implicit" operands as explicit ones.
@ -493,6 +519,8 @@ static void ConstructConversionFunctions(CodeGenTarget &Target,
Signature += Op.AsClass.ClassName; Signature += Op.AsClass.ClassName;
Signature += utostr(Op.AsClass.Operand->MINumOperands); Signature += utostr(Op.AsClass.Operand->MINumOperands);
Signature += "_" + utostr(MIOperandList[i].second);
CurIndex += Op.AsClass.Operand->MINumOperands; CurIndex += Op.AsClass.Operand->MINumOperands;
} }
@ -500,42 +528,53 @@ static void ConstructConversionFunctions(CodeGenTarget &Target,
for (; CurIndex != NumMIOperands; ++CurIndex) for (; CurIndex != NumMIOperands; ++CurIndex)
Signature += "Imp"; Signature += "Imp";
// Save the conversion function, for use by the matcher. II.ConversionFnKind = Signature;
II.ConversionFn = Signature;
// Check if we have already generated this function. // Check if we have already generated this signature.
if (!GeneratedFns.insert(Signature).second) if (!GeneratedFns.insert(Signature).second)
continue; continue;
// If not, emit it now. // If not, emit it now.
//
// FIXME: There should be no need to pass the number of operands to fill; // Add to the enum list.
// this should always be implicit in the class. OS << " " << Signature << ",\n";
OS << "static bool " << Signature << "(MCInst &Inst, unsigned Opcode";
for (unsigned i = 0, e = MIOperandList.size(); i != e; ++i) // And to the convert function.
OS << ", " << Target.getName() << "Operand Op" << i; CvtOS << " case " << Signature << ":\n";
OS << ") {\n";
OS << " Inst.setOpcode(Opcode);\n";
CurIndex = 0; CurIndex = 0;
for (unsigned i = 0, e = MIOperandList.size(); i != e; ++i) { for (unsigned i = 0, e = MIOperandList.size(); i != e; ++i) {
InstructionInfo::Operand &Op = II.Operands[MIOperandList[i].second]; InstructionInfo::Operand &Op = II.Operands[MIOperandList[i].second];
// Add the implicit operands. // Add the implicit operands.
for (; CurIndex != Op.AsClass.Operand->MIOperandNo; ++CurIndex) for (; CurIndex != Op.AsClass.Operand->MIOperandNo; ++CurIndex)
OS << " Inst.addOperand(MCOperand::CreateReg(0));\n"; CvtOS << " Inst.addOperand(MCOperand::CreateReg(0));\n";
OS << " Op" << i << "." << Op.AsClass.RenderMethod CvtOS << " Operands[" << MIOperandList[i].second
<< "]." << Op.AsClass.RenderMethod
<< "(Inst, " << Op.AsClass.Operand->MINumOperands << ");\n"; << "(Inst, " << Op.AsClass.Operand->MINumOperands << ");\n";
CurIndex += Op.AsClass.Operand->MINumOperands; CurIndex += Op.AsClass.Operand->MINumOperands;
} }
// And add trailing implicit operands. // And add trailing implicit operands.
for (; CurIndex != NumMIOperands; ++CurIndex) for (; CurIndex != NumMIOperands; ++CurIndex)
OS << " Inst.addOperand(MCOperand::CreateReg(0));\n"; CvtOS << " Inst.addOperand(MCOperand::CreateReg(0));\n";
CvtOS << " break;\n";
OS << " return false;\n";
OS << "}\n\n";
} }
// Finish the convert function.
CvtOS << " }\n";
CvtOS << " return false;\n";
CvtOS << "}\n\n";
// Finish the enum, and drop the convert function after it.
OS << " NumConversionVariants\n";
OS << "};\n\n";
OS << "}\n\n";
OS << CvtOS.str();
} }
/// EmitMatchRegisterName - Emit the function to match a string to the target /// EmitMatchRegisterName - Emit the function to match a string to the target
@ -576,22 +615,16 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
std::vector<InstructionInfo*> Infos; std::vector<InstructionInfo*> Infos;
BuildInstructionInfos(Target, Infos); BuildInstructionInfos(Target, Infos);
#undef DEBUG_TYPE DEBUG_WITH_TYPE("instruction_info", {
#define DEBUG_TYPE "instruction_info"
DEBUG({
for (std::vector<InstructionInfo*>::iterator it = Infos.begin(), for (std::vector<InstructionInfo*>::iterator it = Infos.begin(),
ie = Infos.end(); it != ie; ++it) ie = Infos.end(); it != ie; ++it)
(*it)->dump(); (*it)->dump();
}); });
#undef DEBUG_TYPE
#define DEBUG_TYPE ""
// FIXME: At this point we should be able to totally order Infos, if not then // 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. // we have an ambiguity which the .td file should be forced to resolve.
// Generate the terminal actions to convert operands into an MCInst. We still // Generate the terminal actions to convert operands into an MCInst.
// pass the operands in to these functions individually (as opposed to the
// array) so that we do not need to worry about the operand order.
ConstructConversionFunctions(Target, Infos, OS); ConstructConversionFunctions(Target, Infos, OS);
// Build a very stupid version of the match function which just checks each // Build a very stupid version of the match function which just checks each
@ -622,11 +655,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
<< Op.AsClass.PredicateMethod << "()"; << Op.AsClass.PredicateMethod << "()";
} }
OS << ")\n"; OS << ")\n";
OS << " return " << II.ConversionFn << "(Inst, " OS << " return ConvertToMCInst(" << II.ConversionFnKind << ", Inst, "
<< Target.getName() << "::" << II.InstrName; << Target.getName() << "::" << II.InstrName
for (unsigned i = 0, e = II.OrderedClassOperands.size(); i != e; ++i) << ", Operands);\n\n";
OS << ", Operands[" << II.OrderedClassOperands[i] << "]";
OS << ");\n\n";
} }
OS << " return true;\n"; OS << " return true;\n";