Index: llvm/trunk/lib/Target/X86/AsmParser/X86AsmParser.cpp =================================================================== --- llvm/trunk/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ llvm/trunk/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -59,6 +59,7 @@ const MCInstrInfo &MII; ParseInstructionInfo *InstInfo; std::unique_ptr Instrumentation; + bool Code16GCC; private: SMLoc consumeToken() { @@ -68,6 +69,19 @@ return Result; } + unsigned MatchInstruction(const OperandVector &Operands, MCInst &Inst, + uint64_t &ErrorInfo, bool matchingInlineAsm, + unsigned VariantID = 0) { + // In Code16GCC mode, match as 32-bit. + if (Code16GCC) + SwitchMode(X86::Mode32Bit); + unsigned rv = MatchInstructionImpl(Operands, Inst, ErrorInfo, + matchingInlineAsm, VariantID); + if (Code16GCC) + SwitchMode(X86::Mode16Bit); + return rv; + } + enum InfixCalculatorTok { IC_OR = 0, IC_XOR, @@ -794,7 +808,8 @@ public: X86AsmParser(const MCSubtargetInfo &sti, MCAsmParser &Parser, const MCInstrInfo &mii, const MCTargetOptions &Options) - : MCTargetAsmParser(Options, sti), MII(mii), InstInfo(nullptr) { + : MCTargetAsmParser(Options, sti), MII(mii), InstInfo(nullptr), + Code16GCC(false) { // Initialize the set of available features. setAvailableFeatures(ComputeAvailableFeatures(getSTI().getFeatureBits())); @@ -983,20 +998,20 @@ } std::unique_ptr X86AsmParser::DefaultMemSIOperand(SMLoc Loc) { - unsigned basereg = - is64BitMode() ? X86::RSI : (is32BitMode() ? X86::ESI : X86::SI); + bool Parse32 = is32BitMode() || Code16GCC; + unsigned Basereg = is64BitMode() ? X86::RSI : (Parse32 ? X86::ESI : X86::SI); const MCExpr *Disp = MCConstantExpr::create(0, getContext()); return X86Operand::CreateMem(getPointerWidth(), /*SegReg=*/0, Disp, - /*BaseReg=*/basereg, /*IndexReg=*/0, /*Scale=*/1, + /*BaseReg=*/Basereg, /*IndexReg=*/0, /*Scale=*/1, Loc, Loc, 0); } std::unique_ptr X86AsmParser::DefaultMemDIOperand(SMLoc Loc) { - unsigned basereg = - is64BitMode() ? X86::RDI : (is32BitMode() ? X86::EDI : X86::DI); + bool Parse32 = is32BitMode() || Code16GCC; + unsigned Basereg = is64BitMode() ? X86::RDI : (Parse32 ? X86::EDI : X86::DI); const MCExpr *Disp = MCConstantExpr::create(0, getContext()); return X86Operand::CreateMem(getPointerWidth(), /*SegReg=*/0, Disp, - /*BaseReg=*/basereg, /*IndexReg=*/0, /*Scale=*/1, + /*BaseReg=*/Basereg, /*IndexReg=*/0, /*Scale=*/1, Loc, Loc, 0); } @@ -1672,8 +1687,9 @@ // The offset operator will have an 'r' constraint, thus we need to create // register operand to ensure proper matching. Just pick a GPR based on // the size of a pointer. - unsigned RegNo = - is64BitMode() ? X86::RBX : (is32BitMode() ? X86::EBX : X86::BX); + bool Parse32 = is32BitMode() || Code16GCC; + unsigned RegNo = is64BitMode() ? X86::RBX : (Parse32 ? X86::EBX : X86::BX); + return X86Operand::CreateReg(RegNo, Start, End, /*GetAddress=*/true, OffsetOfLoc, Identifier, Info.OpDecl); } @@ -2585,9 +2601,8 @@ MCInst Inst; // First, try a direct match. - switch (MatchInstructionImpl(Operands, Inst, - ErrorInfo, MatchingInlineAsm, - isParsingIntelSyntax())) { + switch (MatchInstruction(Operands, Inst, ErrorInfo, MatchingInlineAsm, + isParsingIntelSyntax())) { default: llvm_unreachable("Unexpected match result!"); case Match_Success: // Some instructions need post-processing to, for example, tweak which @@ -2638,8 +2653,8 @@ for (unsigned I = 0, E = array_lengthof(Match); I != E; ++I) { Tmp.back() = Suffixes[I]; - Match[I] = MatchInstructionImpl(Operands, Inst, ErrorInfoIgnore, - MatchingInlineAsm, isParsingIntelSyntax()); + Match[I] = MatchInstruction(Operands, Inst, ErrorInfoIgnore, + MatchingInlineAsm, isParsingIntelSyntax()); // If this returned as a missing feature failure, remember that. if (Match[I] == Match_MissingFeature) ErrorInfoMissingFeature = ErrorInfoIgnore; @@ -2785,9 +2800,8 @@ UnsizedMemOp->Mem.Size = Size; uint64_t ErrorInfoIgnore; unsigned LastOpcode = Inst.getOpcode(); - unsigned M = - MatchInstructionImpl(Operands, Inst, ErrorInfoIgnore, - MatchingInlineAsm, isParsingIntelSyntax()); + unsigned M = MatchInstruction(Operands, Inst, ErrorInfoIgnore, + MatchingInlineAsm, isParsingIntelSyntax()); if (Match.empty() || LastOpcode != Inst.getOpcode()) Match.push_back(M); @@ -2805,9 +2819,8 @@ // operation. There shouldn't be any ambiguity in our mnemonic table, so try // matching with the unsized operand. if (Match.empty()) { - Match.push_back(MatchInstructionImpl(Operands, Inst, ErrorInfo, - MatchingInlineAsm, - isParsingIntelSyntax())); + Match.push_back(MatchInstruction( + Operands, Inst, ErrorInfo, MatchingInlineAsm, isParsingIntelSyntax())); // If this returned as a missing feature failure, remember that. if (Match.back() == Match_MissingFeature) ErrorInfoMissingFeature = ErrorInfo; @@ -2967,12 +2980,21 @@ /// ::= .code16 | .code32 | .code64 bool X86AsmParser::ParseDirectiveCode(StringRef IDVal, SMLoc L) { MCAsmParser &Parser = getParser(); + Code16GCC = false; if (IDVal == ".code16") { Parser.Lex(); if (!is16BitMode()) { SwitchMode(X86::Mode16Bit); getParser().getStreamer().EmitAssemblerFlag(MCAF_Code16); } + } else if (IDVal == ".code16gcc") { + // .code16gcc parses as if in 32-bit mode, but emits code in 16-bit mode. + Parser.Lex(); + Code16GCC = true; + if (!is16BitMode()) { + SwitchMode(X86::Mode16Bit); + getParser().getStreamer().EmitAssemblerFlag(MCAF_Code16); + } } else if (IDVal == ".code32") { Parser.Lex(); if (!is32BitMode()) { Index: llvm/trunk/test/MC/X86/code16gcc.s =================================================================== --- llvm/trunk/test/MC/X86/code16gcc.s +++ llvm/trunk/test/MC/X86/code16gcc.s @@ -0,0 +1,67 @@ +// RUN: llvm-mc -triple i386-unknown-unknown-unknown --show-encoding %s | FileCheck %s + + .code16gcc + //CHECK: .code16 + nop + //CHECK: nop # encoding: [0x90] + lodsb + //CHECK: lodsb (%esi), %al # encoding: [0x67,0xac] + lodsb (%si), %al + //CHECK: lodsb (%si), %al # encoding: [0xac] + lodsb (%esi), %al + //CHECK: lodsb (%esi), %al # encoding: [0x67,0xac] + lodsl %gs:(%esi) + //CHECK: lodsl %gs:(%esi), %eax # encoding: [0x66,0x65,0x67,0xad] + lods (%esi), %ax + //CHECK: lodsw (%esi), %ax # encoding: [0x67,0xad] + stosw + //CHECK: stosw %ax, %es:(%edi) # encoding: [0x67,0xab] + stos %eax, (%edi) + //CHECK: stosl %eax, %es:(%edi) # encoding: [0x66,0x67,0xab] + stosb %al, %es:(%edi) + //CHECK: stosb %al, %es:(%edi) # encoding: [0x67,0xaa] + scas %es:(%edi), %al + //CHECK: scasb %es:(%edi), %al # encoding: [0x67,0xae] + scas %es:(%di), %ax + //CHECK: scasw %es:(%di), %ax # encoding: [0xaf] + cmpsb + //CHECK: cmpsb %es:(%edi), (%esi) # encoding: [0x67,0xa6] + cmpsw (%edi), (%esi) + //CHECK: cmpsw %es:(%edi), (%esi) # encoding: [0x67,0xa7] + cmpsl %es:(%edi), %ss:(%esi) + //CHECK: cmpsl %es:(%edi), %ss:(%esi) # encoding: [0x66,0x36,0x67,0xa7] + movsb (%esi), (%edi) + //CHECK: movsb (%esi), %es:(%edi) # encoding: [0x67,0xa4] + movsl %gs:(%esi), (%edi) + //CHECK: movsl %gs:(%esi), %es:(%edi) # encoding: [0x66,0x65,0x67,0xa5] + outsb + //CHECK: outsb (%esi), %dx # encoding: [0x67,0x6e] + outsw %fs:(%esi), %dx + //CHECK: outsw %fs:(%esi), %dx # encoding: [0x64,0x67,0x6f] + insw %dx, (%di) + //CHECK: insw %dx, %es:(%di) # encoding: [0x6d] + call $0x7ace,$0x7ace + //CHECK: lcalll $31438, $31438 # encoding: [0x66,0x9a,0xce,0x7a,0x00,0x00,0xce,0x7a] + ret + //CHECK: retl # encoding: [0x66,0xc3] + pop %ss + //CHECK: popl %ss # encoding: [0x66,0x17] + enter $0x7ace,$0x7f + //CHECK: enter $31438, $127 # encoding: [0xc8,0xce,0x7a,0x7f] + leave + //CHECK: leave # encoding: [0xc9] + push %ss + //CHECK: pushl %ss # encoding: [0x66,0x16] + pop %ss + //CHECK: popl %ss # encoding: [0x66,0x17] + popa + //CHECK: popal # encoding: [0x66,0x61] + pushf + //CHECK: pushfl # encoding: [0x66,0x9c] + popf + //CHECK: popfl # encoding: [0x66,0x9d] + pushw 4 + //CHECK: pushw 4 # encoding: [0xff,0x36,0x04,0x00] + + +