diff options
-rw-r--r-- | lib/Target/X86/AsmParser/X86AsmParser.cpp | 200 | ||||
-rw-r--r-- | test/MC/AsmParser/x86_instructions.s | 1 | ||||
-rw-r--r-- | utils/TableGen/AsmMatcherEmitter.cpp | 687 |
3 files changed, 552 insertions, 336 deletions
diff --git a/lib/Target/X86/AsmParser/X86AsmParser.cpp b/lib/Target/X86/AsmParser/X86AsmParser.cpp index 4d7358a..9d85f4d 100644 --- a/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ b/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -26,10 +26,6 @@ class X86ATTAsmParser : public TargetAsmParser { MCAsmParser &Parser; private: - bool MatchInstruction(const StringRef &Name, - SmallVectorImpl<X86Operand> &Operands, - MCInst &Inst); - MCAsmParser &getParser() const { return Parser; } MCAsmLexer &getLexer() const { return Parser.getLexer(); } @@ -47,6 +43,9 @@ private: /// @name Auto-generated Match Functions /// { + bool MatchInstruction(SmallVectorImpl<X86Operand> &Operands, + MCInst &Inst); + bool MatchRegisterName(const StringRef &Name, unsigned &RegNo); /// } @@ -67,6 +66,7 @@ namespace { /// instruction. struct X86Operand { enum { + Token, Register, Immediate, Memory @@ -74,6 +74,11 @@ struct X86Operand { union { struct { + const char *Data; + unsigned Length; + } Tok; + + struct { unsigned RegNo; } Reg; @@ -90,6 +95,11 @@ struct X86Operand { } Mem; }; + StringRef getToken() const { + assert(Kind == Token && "Invalid access!"); + return StringRef(Tok.Data, Tok.Length); + } + unsigned getReg() const { assert(Kind == Register && "Invalid access!"); return Reg.RegNo; @@ -121,18 +131,61 @@ struct X86Operand { return Mem.Scale; } + bool isToken(const StringRef &Str) const { + return Kind == Token && Str == getToken(); + } + + bool isImm() const { return Kind == Immediate; } + + bool isMem() const { return Kind == Memory; } + + bool isReg() const { return Kind == Register; } + + void addRegOperands(MCInst &Inst, unsigned N) { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getReg())); + } + + void addImmOperands(MCInst &Inst, unsigned N) { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateMCValue(getImm())); + } + + void addMemOperands(MCInst &Inst, unsigned N) { + assert((N == 4 || N == 5) && "Invalid number of operands!"); + + Inst.addOperand(MCOperand::CreateReg(getMemBaseReg())); + Inst.addOperand(MCOperand::CreateImm(getMemScale())); + Inst.addOperand(MCOperand::CreateReg(getMemIndexReg())); + Inst.addOperand(MCOperand::CreateMCValue(getMemDisp())); + + // FIXME: What a hack. + if (N == 5) + Inst.addOperand(MCOperand::CreateReg(getMemSegReg())); + } + + static X86Operand CreateToken(StringRef Str) { + X86Operand Res; + Res.Kind = Token; + Res.Tok.Data = Str.data(); + Res.Tok.Length = Str.size(); + return Res; + } + static X86Operand CreateReg(unsigned RegNo) { X86Operand Res; Res.Kind = Register; Res.Reg.RegNo = RegNo; return Res; } + static X86Operand CreateImm(MCValue Val) { X86Operand Res; Res.Kind = Immediate; Res.Imm.Val = Val; return Res; } + static X86Operand CreateMem(unsigned SegReg, MCValue Disp, unsigned BaseReg, unsigned IndexReg, unsigned Scale) { // We should never just have a displacement, that would be an immediate. @@ -326,7 +379,9 @@ bool X86ATTAsmParser::ParseMemOperand(X86Operand &Op) { } bool X86ATTAsmParser::ParseInstruction(const StringRef &Name, MCInst &Inst) { - SmallVector<X86Operand, 3> Operands; + SmallVector<X86Operand, 4> Operands; + + Operands.push_back(X86Operand::CreateToken(Name)); SMLoc Loc = getLexer().getTok().getLoc(); if (getLexer().isNot(AsmToken::EndOfStatement)) { @@ -345,7 +400,7 @@ bool X86ATTAsmParser::ParseInstruction(const StringRef &Name, MCInst &Inst) { } } - if (!MatchInstruction(Name, Operands, Inst)) + if (!MatchInstruction(Operands, Inst)) return false; // FIXME: We should give nicer diagnostics about the exact failure. @@ -362,137 +417,4 @@ extern "C" void LLVMInitializeX86AsmParser() { RegisterAsmParser<X86ATTAsmParser> Y(TheX86_64Target); } -// FIXME: These should come from tblgen? - -static bool -Match_X86_Op_REG(const X86Operand &Op, MCOperand *MCOps, unsigned NumOps) { - assert(NumOps == 1 && "Invalid number of ops!"); - - // FIXME: Match correct registers. - if (Op.Kind != X86Operand::Register) - return true; - - MCOps[0] = MCOperand::CreateReg(Op.getReg()); - return false; -} - -static bool -Match_X86_Op_IMM(const X86Operand &Op, MCOperand *MCOps, unsigned NumOps) { - assert(NumOps == 1 && "Invalid number of ops!"); - - // FIXME: We need to check widths. - if (Op.Kind != X86Operand::Immediate) - return true; - - MCOps[0] = MCOperand::CreateMCValue(Op.getImm()); - return false; -} - -static bool Match_X86_Op_LMEM(const X86Operand &Op, - MCOperand *MCOps, - unsigned NumMCOps) { - assert(NumMCOps == 4 && "Invalid number of ops!"); - - if (Op.Kind != X86Operand::Memory) - return true; - - MCOps[0] = MCOperand::CreateReg(Op.getMemBaseReg()); - MCOps[1] = MCOperand::CreateImm(Op.getMemScale()); - MCOps[2] = MCOperand::CreateReg(Op.getMemIndexReg()); - MCOps[3] = MCOperand::CreateMCValue(Op.getMemDisp()); - - return false; -} - -static bool Match_X86_Op_MEM(const X86Operand &Op, - MCOperand *MCOps, - unsigned NumMCOps) { - assert(NumMCOps == 5 && "Invalid number of ops!"); - - if (Match_X86_Op_LMEM(Op, MCOps, 4)) - return true; - - MCOps[4] = MCOperand::CreateReg(Op.getMemSegReg()); - - return false; -} - -#define REG(name) \ - static bool Match_X86_Op_##name(const X86Operand &Op, \ - MCOperand *MCOps, \ - unsigned NumMCOps) { \ - return Match_X86_Op_REG(Op, MCOps, NumMCOps); \ - } - -REG(GR64) -REG(GR32) -REG(GR16) -REG(GR8) - -#define IMM(name) \ - static bool Match_X86_Op_##name(const X86Operand &Op, \ - MCOperand *MCOps, \ - unsigned NumMCOps) { \ - return Match_X86_Op_IMM(Op, MCOps, NumMCOps); \ - } - -IMM(brtarget) -IMM(brtarget8) -IMM(i16i8imm) -IMM(i16imm) -IMM(i32i8imm) -IMM(i32imm) -IMM(i32imm_pcrel) -IMM(i64i32imm) -IMM(i64i32imm_pcrel) -IMM(i64i8imm) -IMM(i64imm) -IMM(i8imm) - -#define LMEM(name) \ - static bool Match_X86_Op_##name(const X86Operand &Op, \ - MCOperand *MCOps, \ - unsigned NumMCOps) { \ - return Match_X86_Op_LMEM(Op, MCOps, NumMCOps); \ - } - -LMEM(lea32mem) -LMEM(lea64_32mem) -LMEM(lea64mem) - -#define MEM(name) \ - static bool Match_X86_Op_##name(const X86Operand &Op, \ - MCOperand *MCOps, \ - unsigned NumMCOps) { \ - return Match_X86_Op_MEM(Op, MCOps, NumMCOps); \ - } - -MEM(f128mem) -MEM(f32mem) -MEM(f64mem) -MEM(f80mem) -MEM(i128mem) -MEM(i16mem) -MEM(i32mem) -MEM(i64mem) -MEM(i8mem) -MEM(sdmem) -MEM(ssmem) - -#define DUMMY(name) \ - static bool Match_X86_Op_##name(const X86Operand &Op, \ - MCOperand *MCOps, \ - unsigned NumMCOps) { \ - return true; \ - } - -DUMMY(FR32) -DUMMY(FR64) -DUMMY(GR32_NOREX) -DUMMY(GR8_NOREX) -DUMMY(RST) -DUMMY(VR128) -DUMMY(VR64) -DUMMY(i8mem_NOREX) - #include "X86GenAsmMatcher.inc" diff --git a/test/MC/AsmParser/x86_instructions.s b/test/MC/AsmParser/x86_instructions.s index 7dbe939..f648112 100644 --- a/test/MC/AsmParser/x86_instructions.s +++ b/test/MC/AsmParser/x86_instructions.s @@ -16,4 +16,3 @@ movl %eax, 10(%ebp, %ebx, 4) // RUN: grep {MCInst(opcode=.*, operands=.reg:0, imm:4, reg:21, val:10, reg:0, reg:19.)} %t movl %eax, 10(, %ebx, 4) -
\ No newline at end of file diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index 3d0739f..f2adc00 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -10,17 +10,87 @@ // This tablegen backend emits a target specifier matcher for converting parsed // assembly operands in the MCInst structures. // +// The input to the target specific matcher is a list of literal tokens and +// operands. The target specific parser should generally eliminate any syntax +// which is not relevant for matching; for example, comma tokens should have +// already been consumed and eliminated by the parser. Most instructions will +// end up with a single literal token (the instruction name) and some number of +// operands. +// +// Some example inputs, for X86: +// 'addl' (immediate ...) (register ...) +// 'add' (immediate ...) (memory ...) +// 'call' '*' %epc +// +// The assembly matcher is responsible for converting this input into a precise +// machine instruction (i.e., an instruction with a well defined encoding). This +// mapping has several properties which complicate matching: +// +// - It may be ambiguous; many architectures can legally encode particular +// variants of an instruction in different ways (for example, using a smaller +// encoding for small immediates). Such ambiguities should never be +// arbitrarily resolved by the assembler, the assembler is always responsible +// for choosing the "best" available instruction. +// +// - It may depend on the subtarget or the assembler context. Instructions +// which are invalid for the current mode, but otherwise unambiguous (e.g., +// an SSE instruction in a file being assembled for i486) should be accepted +// and rejected by the assembler front end. However, if the proper encoding +// for an instruction is dependent on the assembler context then the matcher +// is responsible for selecting the correct machine instruction for the +// current mode. +// +// The core matching algorithm attempts to exploit the regularity in most +// instruction sets to quickly determine the set of possibly matching +// instructions, and the simplify the generated code. Additionally, this helps +// to ensure that the ambiguities are intentionally resolved by the user. +// +// The matching is divided into two distinct phases: +// +// 1. Classification: Each operand is mapped to the unique set which (a) +// contains it, and (b) is the largest such subset for which a single +// instruction could match all members. +// +// For register classes, we can generate these subgroups automatically. For +// arbitrary operands, we expect the user to define the classes and their +// relations to one another (for example, 8-bit signed immediates as a +// subset of 32-bit immediates). +// +// By partitioning the operands in this way, we guarantee that for any +// tuple of classes, any single instruction must match either all or none +// of the sets of operands which could classify to that tuple. +// +// In addition, the subset relation amongst classes induces a partial order +// on such tuples, which we use to resolve ambiguities. +// +// FIXME: What do we do if a crazy case shows up where this is the wrong +// resolution? +// +// 2. The input can now be treated as a tuple of classes (static tokens are +// simple singleton sets). Each such tuple should generally map to a single +// instruction (we currently ignore cases where this isn't true, whee!!!), +// which we can emit a simple matcher for. +// //===----------------------------------------------------------------------===// #include "AsmMatcherEmitter.h" #include "CodeGenTarget.h" #include "Record.h" +#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include <set> #include <list> using namespace llvm; +namespace { + cl::opt<std::string> + MatchOneInstr("match-one-instr", cl::desc("Match only the named instruction"), + cl::init("")); +} + /// FlattenVariants - Flatten an .td file assembly string by selecting the /// variant at index \arg N. static std::string FlattenVariants(const std::string &AsmString, @@ -33,7 +103,8 @@ static std::string FlattenVariants(const std::string &AsmString, size_t VariantsStart = 0; for (size_t e = Cur.size(); VariantsStart != e; ++VariantsStart) if (Cur[VariantsStart] == '{' && - (VariantsStart == 0 || Cur[VariantsStart-1] != '$')) + (VariantsStart == 0 || (Cur[VariantsStart-1] != '$' && + Cur[VariantsStart-1] != '\\'))) break; // Add the prefix to the result. @@ -47,7 +118,7 @@ static std::string FlattenVariants(const std::string &AsmString, size_t VariantsEnd = VariantsStart; unsigned NestedBraces = 1; for (size_t e = Cur.size(); VariantsEnd != e; ++VariantsEnd) { - if (Cur[VariantsEnd] == '}') { + if (Cur[VariantsEnd] == '}' && Cur[VariantsEnd-1] != '\\') { if (--NestedBraces == 0) break; } else if (Cur[VariantsEnd] == '{') @@ -69,274 +140,498 @@ static std::string FlattenVariants(const std::string &AsmString, } /// TokenizeAsmString - Tokenize a simplified assembly string. -static void TokenizeAsmString(const std::string &AsmString, +static void TokenizeAsmString(const 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(StringRef(&AsmString[Prev], i - Prev)); + Tokens.push_back(AsmString.slice(Prev, i)); InTok = false; } - if (AsmString[i] == '*' || AsmString[i] == '!') - Tokens.push_back(StringRef(&AsmString[i], 1)); + 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; + } default: InTok = true; } } if (InTok && Prev != AsmString.size()) - Tokens.push_back(StringRef(&AsmString[Prev], AsmString.size() - Prev)); + Tokens.push_back(AsmString.substr(Prev)); } -void AsmMatcherEmitter::run(raw_ostream &OS) { - CodeGenTarget Target; - const std::vector<CodeGenRegister> &Registers = Target.getRegisters(); - Record *AsmParser = Target.getAsmParser(); - std::string ClassName = AsmParser->getValueAsString("AsmParserClassName"); +static bool IsAssemblerInstruction(const StringRef &Name, + const CodeGenInstruction &CGI, + const SmallVectorImpl<StringRef> &Tokens) { + // Ignore psuedo ops. + // + // FIXME: This is a hack. + if (const RecordVal *Form = CGI.TheDef->getValue("Form")) + if (Form->getValue()->getAsString() == "Pseudo") + return false; + + // Ignore "PHI" node. + // + // FIXME: This is also a hack. + if (Name == "PHI") + return false; + + // Ignore instructions with no .s string. + // + // FIXME: What are these? + if (CGI.AsmString.empty()) + return false; + + // FIXME: Hack; ignore any instructions with a newline in them. + if (std::find(CGI.AsmString.begin(), + CGI.AsmString.end(), '\n') != CGI.AsmString.end()) + return false; + + // Ignore instructions with attributes, these are always fake instructions for + // simplifying codegen. + // + // FIXME: Is this true? + // + // Also, we ignore instructions which reference the operand multiple times; + // this implies a constraint we would not currently honor. These are + // currently always fake instructions for simplifying codegen. + // + // FIXME: Encode this assumption in the .td, so we can error out here. + std::set<std::string> OperandNames; + for (unsigned i = 1, e = Tokens.size(); i < e; ++i) { + if (Tokens[i][0] == '$' && + std::find(Tokens[i].begin(), + Tokens[i].end(), ':') != Tokens[i].end()) { + DEBUG({ + errs() << "warning: '" << Name << "': " + << "ignoring instruction; operand with attribute '" + << Tokens[i] << "', \n"; + }); + return false; + } - std::string Namespace = Registers[0].TheDef->getValueAsString("Namespace"); + if (Tokens[i][0] == '$' && !OperandNames.insert(Tokens[i]).second) { + DEBUG({ + errs() << "warning: '" << Name << "': " + << "ignoring instruction; tied operand '" + << Tokens[i] << "', \n"; + }); + return false; + } + } - EmitSourceFileHeader("Assembly Matcher Source Fragment", OS); + return true; +} - // Emit the function to match a register name to number. +namespace { - OS << "bool " << Target.getName() << ClassName - << "::MatchRegisterName(const StringRef &Name, unsigned &RegNo) {\n"; +struct OperandListLess { + bool operator()(const + std::pair<const CodeGenInstruction::OperandInfo*, unsigned> & + A, + const + std::pair<const CodeGenInstruction::OperandInfo*, unsigned> & + B) { + return A.first->MIOperandNo < B.first->MIOperandNo; + } + +}; - // FIXME: TableGen should have a fast string matcher generator. - for (unsigned i = 0, e = Registers.size(); i != e; ++i) { - const CodeGenRegister &Reg = Registers[i]; - if (Reg.TheDef->getValueAsString("AsmName").empty()) - continue; +struct InstructionInfo { + struct Operand { + enum { + Token, + Class + } Kind; - OS << " if (Name == \"" - << Reg.TheDef->getValueAsString("AsmName") << "\")\n" - << " return RegNo=" << i + 1 << ", false;\n"; + struct ClassData { + /// Operand - The tablegen operand this class corresponds to. + const CodeGenInstruction::OperandInfo *Operand; + + /// ClassName - The name of this operand's class. + std::string ClassName; + + /// PredicateMethod - The name of the operand method to test whether the + /// operand matches this class. + std::string PredicateMethod; + + /// RenderMethod - The name of the operand method to add this operand to + /// an MCInst. + std::string RenderMethod; + } AsClass; + }; + + /// InstrName - The target name for this instruction. + std::string InstrName; + + /// Instr - The instruction this matches. + const CodeGenInstruction *Instr; + + /// AsmString - The assembly string for this instruction (with variants + /// removed). + std::string AsmString; + + /// Tokens - The tokenized assembly pattern that this instruction matches. + SmallVector<StringRef, 4> Tokens; + + /// Operands - The operands that this instruction matches. + SmallVector<Operand, 4> Operands; + + /// ConversionFn - The name of the conversion function to convert parsed + /// operands into an MCInst for this function. + std::string ConversionFn; + + /// 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: + void dump(); +}; + +} + +void InstructionInfo::dump() { + errs() << InstrName << " -- " << "flattened:\"" << AsmString << '\"' + << ", tokens:["; + for (unsigned i = 0, e = Tokens.size(); i != e; ++i) { + errs() << Tokens[i]; + if (i + 1 != e) + errs() << ", "; } - OS << " return true;\n"; - OS << "}\n"; + errs() << "]\n"; - // Emit the function to match instructions. - std::vector<const CodeGenInstruction*> NumberedInstructions; - Target.getInstructionsByEnumValue(NumberedInstructions); + for (unsigned i = 0, e = Operands.size(); i != e; ++i) { + Operand &Op = Operands[i]; + errs() << " op[" << i << "] = "; + if (Op.Kind == Operand::Token) { + errs() << '\"' << Tokens[i] << "\"\n"; + continue; + } - std::list<std::string> MatchFns; + assert(Op.Kind == Operand::Class && "Invalid kind!"); + const CodeGenInstruction::OperandInfo &OI = *Op.AsClass.Operand; + errs() << OI.Name << " " << OI.Rec->getName() + << " (" << OI.MIOperandNo << ", " << OI.MINumOperands << ")\n"; + } +} - OS << "\n"; +static void BuildInstructionInfos(CodeGenTarget &Target, + std::vector<InstructionInfo*> &Infos) { const std::map<std::string, CodeGenInstruction> &Instructions = Target.getInstructions(); + for (std::map<std::string, CodeGenInstruction>::const_iterator it = Instructions.begin(), ie = Instructions.end(); it != ie; ++it) { const CodeGenInstruction &CGI = it->second; - // Ignore psuedo ops. - // - // FIXME: This is a hack. - if (const RecordVal *Form = CGI.TheDef->getValue("Form")) - if (Form->getValue()->getAsString() == "Pseudo") - continue; - - // Ignore "PHI" node. - // - // FIXME: This is also a hack. - if (it->first == "PHI") + if (!MatchOneInstr.empty() && it->first != MatchOneInstr) continue; - // Ignore instructions with no .s string. - // - // FIXME: What are these? - if (CGI.AsmString.empty()) - continue; + OwningPtr<InstructionInfo> II(new InstructionInfo); + + II->InstrName = it->first; + II->Instr = &it->second; + II->AsmString = FlattenVariants(CGI.AsmString, 0); + + TokenizeAsmString(II->AsmString, II->Tokens); - // FIXME: Hack; ignore "lock". - if (StringRef(CGI.AsmString).startswith("lock")) + // Ignore instructions which shouldn't be matched. + if (!IsAssemblerInstruction(it->first, CGI, II->Tokens)) continue; - std::string Flattened = FlattenVariants(CGI.AsmString, 0); - SmallVector<StringRef, 8> Tokens; + for (unsigned i = 0, e = II->Tokens.size(); i != e; ++i) { + StringRef Token = II->Tokens[i]; + + // Check for simple tokens. + if (Token[0] != '$') { + InstructionInfo::Operand Op; + Op.Kind = InstructionInfo::Operand::Token; + II->Operands.push_back(Op); + continue; + } - TokenizeAsmString(Flattened, Tokens); + // Otherwise this is an operand reference. + InstructionInfo::Operand Op; + Op.Kind = InstructionInfo::Operand::Class; - DEBUG({ - outs() << it->first << " -- flattened:\"" - << Flattened << "\", tokens:["; - for (unsigned i = 0, e = Tokens.size(); i != e; ++i) { - outs() << Tokens[i]; - if (i + 1 != e) - outs() << ", "; - } - outs() << "]\n"; + StringRef OperandName; + if (Token[1] == '{') + OperandName = Token.substr(2, Token.size() - 3); + else + OperandName = Token.substr(1); + + // Map this token to an operand. FIXME: Move elsewhere. + unsigned Idx; + try { + Idx = CGI.getOperandNamed(OperandName); + } catch(...) { + errs() << "error: unable to find operand: '" << OperandName << "'!\n"; + break; + } - for (unsigned i = 0, e = CGI.OperandList.size(); i != e; ++i) { - const CodeGenInstruction::OperandInfo &OI = CGI.OperandList[i]; - outs() << " op[" << i << "] = " << OI.Name - << " " << OI.Rec->getName() - << " (" << OI.MIOperandNo << ", " << OI.MINumOperands << ")\n"; + const CodeGenInstruction::OperandInfo &OI = CGI.OperandList[Idx]; + Op.AsClass.Operand = &OI; + + if (OI.Rec->isSubClassOf("RegisterClass")) { + Op.AsClass.ClassName = "Reg"; + Op.AsClass.PredicateMethod = "isReg"; + Op.AsClass.RenderMethod = "addRegOperands"; + } else if (OI.Rec->isSubClassOf("Operand")) { + // FIXME: This should not be hard coded. + const RecordVal *RV = OI.Rec->getValue("Type"); + + // FIXME: Yet another total hack. + if (RV->getValue()->getAsString() == "iPTR" || + OI.Rec->getName() == "lea32mem" || + OI.Rec->getName() == "lea64_32mem") { + Op.AsClass.ClassName = "Mem"; + Op.AsClass.PredicateMethod = "isMem"; + Op.AsClass.RenderMethod = "addMemOperands"; + } else { + Op.AsClass.ClassName = "Imm"; + Op.AsClass.PredicateMethod = "isImm"; + Op.AsClass.RenderMethod = "addImmOperands"; } - }); + } else { + OI.Rec->dump(); + assert(0 && "Unexpected instruction operand record!"); + } - // FIXME: Ignore prefixes with non-literal tokens. - if (std::find(Tokens[0].begin(), Tokens[0].end(), '$') != Tokens[0].end()) { - DEBUG({ - errs() << "warning: '" << it->first << "': " - << "ignoring non-literal token '" << Tokens[0] << "', \n"; - }); - continue; + II->Operands.push_back(Op); } - // Ignore instructions with subreg specifiers, these are always fake - // instructions for simplifying codegen. - // - // FIXME: Is this true? - // - // Also, we ignore instructions which reference the operand multiple times; - // this implies a constraint we would not currently honor. These are - // currently always fake instructions for simplifying codegen. - // - // FIXME: Encode this assumption in the .td, so we can error out here. - std::set<std::string> OperandNames; - unsigned HasSubreg = 0, HasDuplicate = 0; - for (unsigned i = 1, e = Tokens.size(); i < e; ++i) { - if (Tokens[i][0] == '$' && - std::find(Tokens[i].begin(), - Tokens[i].end(), ':') != Tokens[i].end()) - HasSubreg = i; - if (Tokens[i][0] == '$' && !OperandNames.insert(Tokens[i]).second) - HasDuplicate = i; - } - if (HasSubreg) { - DEBUG({ - errs() << "warning: '" << it->first << "': " - << "ignoring instruction; operand with subreg attribute '" - << Tokens[HasSubreg] << "', \n"; - }); - continue; - } else if (HasDuplicate) { - DEBUG({ - errs() << "warning: '" << it->first << "': " - << "ignoring instruction; tied operand '" - << Tokens[HasSubreg] << "', \n"; - }); + // If we broke out, ignore the instruction. + if (II->Operands.size() != II->Tokens.size()) continue; - } - std::string FnName = "Match_" + Target.getName() + "_Inst_" + it->first; - MatchFns.push_back(FnName); - - OS << "static bool " << FnName - << "(const StringRef &Name," - << " SmallVectorImpl<X86Operand> &Operands," - << " MCInst &Inst) {\n\n"; + Infos.push_back(II.take()); + } +} - OS << " // Match name.\n"; - OS << " if (Name != \"" << Tokens[0] << "\")\n"; - OS << " return true;\n\n"; - - OS << " // Match number of operands.\n"; - OS << " if (Operands.size() != " << Tokens.size() - 1 << ")\n"; - OS << " return true;\n\n"; +static void ConstructConversionFunctions(CodeGenTarget &Target, + std::vector<InstructionInfo*> &Infos, + raw_ostream &OS) { + // Function we have already generated. + std::set<std::string> GeneratedFns; + + for (std::vector<InstructionInfo*>::const_iterator it = Infos.begin(), + ie = Infos.end(); it != ie; ++it) { + InstructionInfo &II = **it; + + // Order the (class) operands by the order to convert them into an MCInst. + SmallVector<std::pair<unsigned, unsigned>, 4> MIOperandList; + for (unsigned i = 0, e = II.Operands.size(); i != e; ++i) { + InstructionInfo::Operand &Op = II.Operands[i]; + if (Op.Kind == InstructionInfo::Operand::Class) + MIOperandList.push_back(std::make_pair(Op.AsClass.Operand->MIOperandNo, + i)); + } + std::sort(MIOperandList.begin(), MIOperandList.end()); - // Compute the total number of MCOperands. - // - // FIXME: Isn't this somewhere else? + // Compute the total number of operands. unsigned NumMIOperands = 0; - for (unsigned i = 0, e = CGI.OperandList.size(); i != e; ++i) { - const CodeGenInstruction::OperandInfo &OI = CGI.OperandList[i]; + for (unsigned i = 0, e = II.Instr->OperandList.size(); i != e; ++i) { + const CodeGenInstruction::OperandInfo &OI = II.Instr->OperandList[i]; NumMIOperands = std::max(NumMIOperands, OI.MIOperandNo + OI.MINumOperands); } - std::set<unsigned> MatchedOperands; - // This the list of operands we need to fill in. - if (NumMIOperands) - OS << " MCOperand Ops[" << NumMIOperands << "];\n\n"; - - unsigned ParsedOpIdx = 0; - for (unsigned i = 1, e = Tokens.size(); i < e; ++i) { - // FIXME: Can only match simple operands. - if (Tokens[i][0] != '$') { - OS << " // FIXME: unable to match token: '" << Tokens[i] << "'!\n"; - OS << " return true;\n\n"; - continue; - } - - // Map this token to an operand. FIXME: Move elsewhere. + // Build the conversion function signature. + std::string Signature = "Convert"; + unsigned CurIndex = 0; + for (unsigned i = 0, e = MIOperandList.size(); i != e; ++i) { + InstructionInfo::Operand &Op = II.Operands[MIOperandList[i].second]; + assert(CurIndex <= Op.AsClass.Operand->MIOperandNo && + "Duplicate match for instruction operand!"); + + // Save the conversion index, for use by the matcher. + II.OrderedClassOperands.push_back(MIOperandList[i].second); + + // Skip operands which weren't matched by anything, this occurs when the + // .td file encodes "implicit" operands as explicit ones. + // + // FIXME: This should be removed from the MCInst structure. + for (; CurIndex != Op.AsClass.Operand->MIOperandNo; ++CurIndex) + Signature += "Imp"; - unsigned Idx; - try { - Idx = CGI.getOperandNamed(Tokens[i].substr(1)); - } catch(...) { - OS << " // FIXME: unable to find operand: '" << Tokens[i] << "'!\n"; - OS << " return true;\n\n"; - continue; - } + Signature += Op.AsClass.ClassName; + Signature += utostr(Op.AsClass.Operand->MINumOperands); + CurIndex += Op.AsClass.Operand->MINumOperands; + } - // FIXME: Each match routine should always end up filling the same number - // of operands, we should just check that the number matches what the - // match routine expects here instead of passing it. We can do this once - // we start generating the class match functions. - const CodeGenInstruction::OperandInfo &OI = CGI.OperandList[Idx]; + // Add any trailing implicit operands. + for (; CurIndex != NumMIOperands; ++CurIndex) + Signature += "Imp"; - // Track that we have matched these operands. - // - // FIXME: Verify that we don't parse something to the same operand twice. - for (unsigned j = 0; j != OI.MINumOperands; ++j) - MatchedOperands.insert(OI.MIOperandNo + j); - - OS << " // Match '" << Tokens[i] << "' (parsed operand " << ParsedOpIdx - << ") to machine operands [" << OI.MIOperandNo << ", " - << OI.MIOperandNo + OI.MINumOperands << ").\n"; - OS << " if (Match_" << Target.getName() - << "_Op_" << OI.Rec->getName() << "(" - << "Operands[" << ParsedOpIdx << "], " - << "&Ops[" << OI.MIOperandNo << "], " - << OI.MINumOperands << "))\n"; - OS << " return true;\n\n"; - - ++ParsedOpIdx; - } + // Save the conversion function, for use by the matcher. + II.ConversionFn = Signature; - // Generate code to construct the MCInst. - - OS << " // Construct MCInst.\n"; - OS << " Inst.setOpcode(" << Target.getName() << "::" - << it->first << ");\n"; - for (unsigned i = 0, e = NumMIOperands; i != e; ++i) { - // FIXME: Oops! Ignore this for now, the instruction should print ok. If - // we need to evaluate the constraints. - if (!MatchedOperands.count(i)) { - OS << "\n"; - OS << " // FIXME: Nothing matched Ops[" << i << "]!\n"; - OS << " Ops[" << i << "] = MCOperand::CreateReg(0);\n"; - OS << "\n"; - } + // Check if we have already generated this function. + if (!GeneratedFns.insert(Signature).second) + continue; - OS << " Inst.addOperand(Ops[" << i << "]);\n"; + // If not, emit it now. + // + // FIXME: There should be no need to pass the number of operands to fill; + // this should always be implicit in the class. + OS << "static bool " << Signature << "(MCInst &Inst, unsigned Opcode"; + for (unsigned i = 0, e = MIOperandList.size(); i != e; ++i) + OS << ", " << Target.getName() << "Operand Op" << i; + OS << ") {\n"; + OS << " Inst.setOpcode(Opcode);\n"; + CurIndex = 0; + for (unsigned i = 0, e = MIOperandList.size(); i != e; ++i) { + InstructionInfo::Operand &Op = II.Operands[MIOperandList[i].second]; + + // Add the implicit operands. + for (; CurIndex != Op.AsClass.Operand->MIOperandNo; ++CurIndex) + OS << " Inst.addOperand(MCOperand::CreateReg(0));\n"; + + OS << " Op" << i << "." << Op.AsClass.RenderMethod + << "(Inst, " << Op.AsClass.Operand->MINumOperands << ");\n"; + CurIndex += Op.AsClass.Operand->MINumOperands; } - OS << "\n"; + + // And add trailing implicit operands. + for (; CurIndex != NumMIOperands; ++CurIndex) + OS << " Inst.addOperand(MCOperand::CreateReg(0));\n"; + OS << " return false;\n"; OS << "}\n\n"; } +} + +void AsmMatcherEmitter::run(raw_ostream &OS) { + CodeGenTarget Target; + const std::vector<CodeGenRegister> &Registers = Target.getRegisters(); + Record *AsmParser = Target.getAsmParser(); + std::string ClassName = AsmParser->getValueAsString("AsmParserClassName"); - // Generate the top level match function. + std::string Namespace = Registers[0].TheDef->getValueAsString("Namespace"); + + EmitSourceFileHeader("Assembly Matcher Source Fragment", OS); + + // Emit the function to match a register name to number. OS << "bool " << Target.getName() << ClassName - << "::MatchInstruction(const StringRef &Name, " + << "::MatchRegisterName(const StringRef &Name, unsigned &RegNo) {\n"; + + // FIXME: TableGen should have a fast string matcher generator. + for (unsigned i = 0, e = Registers.size(); i != e; ++i) { + const CodeGenRegister &Reg = Registers[i]; + if (Reg.TheDef->getValueAsString("AsmName").empty()) + continue; + + OS << " if (Name == \"" + << Reg.TheDef->getValueAsString("AsmName") << "\")\n" + << " return RegNo=" << i + 1 << ", false;\n"; + } + OS << " return true;\n"; + OS << "}\n\n"; + + std::vector<InstructionInfo*> Infos; + BuildInstructionInfos(Target, Infos); + +#undef DEBUG_TYPE +#define DEBUG_TYPE "instruction_info" + DEBUG({ + for (std::vector<InstructionInfo*>::iterator it = Infos.begin(), + ie = Infos.end(); it != ie; ++it) + (*it)->dump(); + }); +#undef DEBUG_TYPE +#define DEBUG_TYPE "" + + // 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. + + // Generate the terminal actions to convert operands into an MCInst. We still + // 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); + + // Build a very stupid version of the match function which just checks each + // instruction in order. + + OS << "bool " << Target.getName() << ClassName + << "::MatchInstruction(" << "SmallVectorImpl<" << Target.getName() << "Operand> &Operands, " << "MCInst &Inst) {\n"; - for (std::list<std::string>::iterator it = MatchFns.begin(), - ie = MatchFns.end(); it != ie; ++it) { - OS << " if (!" << *it << "(Name, Operands, Inst))\n"; - OS << " return false;\n\n"; + + for (std::vector<InstructionInfo*>::const_iterator it = Infos.begin(), + ie = Infos.end(); it != ie; ++it) { + InstructionInfo &II = **it; + + // The parser is expected to arrange things so that each "token" matches + // exactly one target specific operand. + OS << " if (Operands.size() == " << II.Operands.size(); + for (unsigned i = 0, e = II.Operands.size(); i != e; ++i) { + InstructionInfo::Operand &Op = II.Operands[i]; + + OS << " &&\n"; + OS << " "; + + if (Op.Kind == InstructionInfo::Operand::Token) + OS << "Operands[" << i << "].isToken(\"" << II.Tokens[i] << "\")"; + else + OS << "Operands[" << i << "]." + << Op.AsClass.PredicateMethod << "()"; + } + OS << ")\n"; + OS << " return " << II.ConversionFn << "(Inst, " + << Target.getName() << "::" << II.InstrName; + for (unsigned i = 0, e = II.OrderedClassOperands.size(); i != e; ++i) + OS << ", Operands[" << II.OrderedClassOperands[i] << "]"; + OS << ");\n\n"; } OS << " return true;\n"; |