diff --git a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp --- a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -78,6 +78,7 @@ class X86AsmParser : public MCTargetAsmParser { ParseInstructionInfo *InstInfo; bool Code16GCC; + unsigned ForcedDataPrefix = 0; enum VEXEncoding { VEXEncoding_Default, @@ -3085,13 +3086,18 @@ if (getLexer().isNot(AsmToken::EndOfStatement)) { StringRef Next = Parser.getTok().getString(); - // Parse data32 call as calll. - if (Next == "call" || Next == "callw") { - getLexer().Lex(); - Name = "calll"; - PatchedName = Name; - isPrefix = false; - } + getLexer().Lex(); + // data32 effectively changes the instruction suffix. + // TODO Generalize. + if (Next == "callw") + Next = "calll"; + if (Next == "ljmpw") + Next = "ljmpl"; + + Name = Next; + PatchedName = Name; + ForcedDataPrefix = X86::Mode32Bit; + isPrefix = false; } } @@ -3779,11 +3785,19 @@ if (Prefixes) Inst.setFlags(Prefixes); + // In 16-bit mode, if data32 is specified, temporarily switch to 32-bit mode + // when matching the instruction. + if (ForcedDataPrefix == X86::Mode32Bit) + SwitchMode(X86::Mode32Bit); // First, try a direct match. FeatureBitset MissingFeatures; unsigned OriginalError = MatchInstruction(Operands, Inst, ErrorInfo, MissingFeatures, MatchingInlineAsm, isParsingIntelSyntax()); + if (ForcedDataPrefix == X86::Mode32Bit) { + SwitchMode(X86::Mode16Bit); + ForcedDataPrefix = 0; + } switch (OriginalError) { default: llvm_unreachable("Unexpected match result!"); case Match_Success: diff --git a/llvm/test/MC/X86/data-prefix-fail.s b/llvm/test/MC/X86/data-prefix-fail.s --- a/llvm/test/MC/X86/data-prefix-fail.s +++ b/llvm/test/MC/X86/data-prefix-fail.s @@ -7,10 +7,8 @@ // ERR64: error: 'data32' is not supported in 64-bit mode // ERR32: error: redundant data32 prefix -// 16: data32 -// 16: encoding: [0x66] -// 16: lgdtw 0 -// 16: encoding: [0x0f,0x01,0x16,0x00,0x00] +// 16: lgdtl 0 +// 16-SAME: encoding: [0x66,0x0f,0x01,0x16,0x00,0x00] data32 lgdt 0 // 64: data16 diff --git a/llvm/test/MC/X86/x86-16.s b/llvm/test/MC/X86/x86-16.s --- a/llvm/test/MC/X86/x86-16.s +++ b/llvm/test/MC/X86/x86-16.s @@ -553,6 +553,11 @@ data32 call a data32 callw a +// CHECK: ljmpl $1, $2 +// CHECK-NEXT: ljmpl $1, $2 +data32 ljmp $1, $2 +data32 ljmpw $1, $2 + // CHECK: incb %al # encoding: [0xfe,0xc0] incb %al @@ -972,10 +977,8 @@ // CHECK: encoding: [0x66] data32 -// CHECK: data32 -// CHECK: encoding: [0x66] -// CHECK: lgdtw 4(%eax) -// CHECK: encoding: [0x67,0x0f,0x01,0x50,0x04] +// CHECK: lgdtl 4(%eax) +// CHECK-SAME: encoding: [0x67,0x66,0x0f,0x01,0x50,0x04] data32 lgdt 4(%eax) // CHECK: wbnoinvd