diff --git a/lib/Target/X86/AsmParser/X86AsmParser.cpp b/lib/Target/X86/AsmParser/X86AsmParser.cpp index ea5528a951a..5a42683a494 100644 --- a/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ b/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -137,6 +137,19 @@ struct X86Operand { bool isImm() const { return Kind == Immediate; } + bool isImmSExt8() const { + // Accept immediates which fit in 8 bits when sign extended, and + // non-absolute immediates. + if (!isImm()) + return false; + + if (!getImm().isAbsolute()) + return true; + + int64_t Value = getImm().getConstant(); + return Value == (int64_t) (int8_t) Value; + } + bool isMem() const { return Kind == Memory; } bool isReg() const { return Kind == Register; } @@ -151,6 +164,12 @@ struct X86Operand { Inst.addOperand(MCOperand::CreateMCValue(getImm())); } + void addImmSExt8Operands(MCInst &Inst, unsigned N) { + // FIXME: Support user customization of the render method. + 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!"); diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index c21cad98df0..80f03e8318c 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -212,9 +212,15 @@ def piclabel: Operand { // A couple of more descriptive operand definitions. // 16-bits but only 8 bits are significant. -def i16i8imm : Operand; +def i16i8imm : Operand { + let ParserMatchClass = "ImmSExt8"; + let ParserMatchSuperClass = "Imm"; +} // 32-bits but only 8 bits are significant. -def i32i8imm : Operand; +def i32i8imm : Operand { + let ParserMatchClass = "ImmSExt8"; + let ParserMatchSuperClass = "Imm"; +} // Branch targets have OtherVT type and print as pc-relative values. def brtarget : Operand { diff --git a/test/MC/AsmParser/x86_instructions.s b/test/MC/AsmParser/x86_instructions.s index ffd2dde0f1f..57d9decaf23 100644 --- a/test/MC/AsmParser/x86_instructions.s +++ b/test/MC/AsmParser/x86_instructions.s @@ -16,3 +16,17 @@ 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) + +// FIXME: Check that this matches SUB32ri8 +// RUN: grep {MCInst(opcode=.*, operands=.reg:19, reg:0, val:1.)} %t + subl $1, %eax + +// FIXME: Check that this matches SUB32ri8 +// RUN: grep {MCInst(opcode=.*, operands=.reg:19, reg:0, val:-1.)} %t + subl $-1, %eax + +// FIXME: Check that this matches SUB32ri +// RUN: grep {MCInst(opcode=.*, operands=.reg:19, reg:0, val:256.)} %t + subl $256, %eax + + diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index aafc09fcd6e..f6458541105 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -289,6 +289,12 @@ struct ClassInfo { /// N) for the Nth user defined class. unsigned Kind; + /// SuperClassKind - The super class kind for user classes. + unsigned SuperClassKind; + + /// SuperClass - The super class, or 0. + ClassInfo *SuperClass; + /// Name - The full class name, suitable for use in an enum. std::string Name; @@ -308,27 +314,40 @@ struct ClassInfo { /// MCInst; this is not valid for Token kinds. std::string RenderMethod; + /// isUserClass() - Check if this is a user defined class. + bool isUserClass() const { + return Kind >= UserClass0; + } + + /// getRootClass - Return the root class of this one. + const ClassInfo *getRootClass() const { + const ClassInfo *CI = this; + while (CI->SuperClass) + CI = CI->SuperClass; + return CI; + } + /// operator< - Compare two classes. bool operator<(const ClassInfo &RHS) const { - // Incompatible kinds are comparable. - if (Kind != RHS.Kind) + // Incompatible kinds are comparable for classes in disjoint hierarchies. + if (Kind != RHS.Kind && getRootClass() != RHS.getRootClass()) return Kind < RHS.Kind; switch (Kind) { case Invalid: assert(0 && "Invalid kind!"); case Token: - // Tokens are always comparable. + // Tokens are comparable by value. // // FIXME: Compare by enum value. return ValueName < RHS.ValueName; - case Register: - // FIXME: Compare by subset relation. - return false; - default: - // FIXME: Allow user defined relation. + // This class preceeds the RHS if the RHS is a super class. + for (ClassInfo *Parent = SuperClass; Parent; Parent = Parent->SuperClass) + if (Parent == &RHS) + return true; + return false; } } @@ -525,6 +544,7 @@ unsigned AsmMatcherInfo::getUserClassKind(const StringRef &Name) { ClassInfo * AsmMatcherInfo::getOperandClass(const StringRef &Token, const CodeGenInstruction::OperandInfo &OI) { + unsigned SuperClass = ClassInfo::Invalid; std::string ClassName; if (OI.Rec->isSubClassOf("RegisterClass")) { ClassName = "Reg"; @@ -536,17 +556,24 @@ AsmMatcherInfo::getOperandClass(const StringRef &Token, PrintError(OI.Rec->getLoc(), "operand has no match class!"); ClassName = "Invalid"; } + + // Determine the super class. + try { + std::string SuperClassName = + OI.Rec->getValueAsString("ParserMatchSuperClass"); + SuperClass = getUserClassKind(SuperClassName); + } catch(...) { } } ClassInfo *&Entry = OperandClasses[ClassName]; if (!Entry) { Entry = new ClassInfo(); - // FIXME: Hack. if (ClassName == "Reg") { Entry->Kind = ClassInfo::Register; } else { Entry->Kind = getUserClassKind(ClassName); + Entry->SuperClassKind = SuperClass; } Entry->ClassName = ClassName; Entry->Name = "MCK_" + ClassName; @@ -622,6 +649,27 @@ void AsmMatcherInfo::BuildInfo(CodeGenTarget &Target) { Instructions.push_back(II.take()); } + + // Bind user super classes. + std::map UserClasses; + for (unsigned i = 0, e = Classes.size(); i != e; ++i) { + ClassInfo &CI = *Classes[i]; + if (CI.isUserClass()) + UserClasses[CI.Kind] = &CI; + } + + for (unsigned i = 0, e = Classes.size(); i != e; ++i) { + ClassInfo &CI = *Classes[i]; + if (CI.isUserClass() && CI.SuperClassKind != ClassInfo::Invalid) { + CI.SuperClass = UserClasses[CI.SuperClassKind]; + assert(CI.SuperClass && "Missing super class definition!"); + } else { + CI.SuperClass = 0; + } + } + + // Reorder classes so that classes preceed super classes. + std::sort(Classes.begin(), Classes.end(), less_ptr()); } static void EmitConvertToMCInst(CodeGenTarget &Target, @@ -790,8 +838,22 @@ static void EmitClassifyOperand(CodeGenTarget &Target, ClassInfo &CI = **it; if (CI.Kind != ClassInfo::Token) { - OS << " if (Operand." << CI.PredicateMethod << "())\n"; + OS << " // '" << CI.ClassName << "' class"; + if (CI.SuperClass) { + OS << ", subclass of '" << CI.SuperClass->ClassName << "'"; + assert(CI < *CI.SuperClass && "Invalid class relation!"); + } + OS << "\n"; + + OS << " if (Operand." << CI.PredicateMethod << "()) {\n"; + + // Validate subclass relationships. + if (CI.SuperClass) + OS << " assert(Operand." << CI.SuperClass->PredicateMethod + << "() && \"Invalid class relationship!\");\n"; + OS << " return " << CI.Name << ";\n\n"; + OS << " }"; } } OS << " return InvalidMatchClass;\n";