From: Fangrui Song Date: Tue, 6 Oct 2020 15:26:12 +0000 (-0700) Subject: [X86] .code16: temporarily set Mode32Bit when matching an instruction with the data32... X-Git-Tag: llvmorg-13-init~9986 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=43c7dc52f12973b306910a161bcf150d70d33504;p=platform%2Fupstream%2Fllvm.git [X86] .code16: temporarily set Mode32Bit when matching an instruction with the data32 prefix PR47632 This allows MC to match `data32 ...` as one instruction instead of two (data32 without insn + insn). The compatibility with GNU as improves: `data32 ljmp` will be matched as ljmpl. `data32 lgdt 4(%eax)` will be matched as `lgdtl` (prefixes: 0x67 0x66, instead of 0x66 0x67). GNU as supports many other `data32 *w` as `*l`. We currently just hard code `data32 callw` and `data32 ljmpw`. Generalizing the suffix replacement is tricky and requires a think about the "bwlq" appending suffix rules in MatchAndEmitATTInstruction. Reviewed By: craig.topper Differential Revision: https://reviews.llvm.org/D88772 --- diff --git a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp index 1f594c5..8af1148 100644 --- a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -78,6 +78,7 @@ static const char OpPrecedence[] = { class X86AsmParser : public MCTargetAsmParser { ParseInstructionInfo *InstInfo; bool Code16GCC; + unsigned ForcedDataPrefix = 0; enum VEXEncoding { VEXEncoding_Default, @@ -3085,13 +3086,18 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, 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 @@ bool X86AsmParser::MatchAndEmitATTInstruction(SMLoc IDLoc, unsigned &Opcode, 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 index 638e972..bd5b62d 100644 --- 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 index 277d8a0..9f8c6397 100644 --- a/llvm/test/MC/X86/x86-16.s +++ b/llvm/test/MC/X86/x86-16.s @@ -553,6 +553,11 @@ ljmp $0x7ace,$0x7ace 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 @@ lretl // 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