diff --git a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp index a8908d4b710e6..5cb170c5af384 100644 --- a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -3563,8 +3563,34 @@ bool X86AsmParser::parseInstruction(ParseInstructionInfo &Info, StringRef Name, PatchedName = Name; // Hacks to handle 'data16' and 'data32' - if (PatchedName == "data16" && is16BitMode()) { - return Error(NameLoc, "redundant data16 prefix"); + if (PatchedName == "data16") { + if (is16BitMode()) + return Error(NameLoc, "redundant data16 prefix"); + if (getLexer().isNot(AsmToken::EndOfStatement)) { + StringRef Next = Parser.getTok().getString(); + getLexer().Lex(); + // data16 effectively changes the instruction suffix. + // TODO Generalize. + if (Next == "call") + Next = "callw"; + if (Next == "ljmp") + Next = "ljmpw"; + if (Next == "retf") + Next = "retfw"; + if (Next == "lgdt") { + if (is64BitMode()) { + // Use the special lgdtq variant with OpSize16 flag. + Next = "lgdtq16"; + } else { + Next = "lgdtw"; + } + } + + Name = Next; + PatchedName = Name; + ForcedDataPrefix = X86::Is16Bit; + IsPrefix = false; + } } if (PatchedName == "data32") { if (is32BitMode()) @@ -3579,9 +3605,9 @@ bool X86AsmParser::parseInstruction(ParseInstructionInfo &Info, StringRef Name, getLexer().Lex(); // data32 effectively changes the instruction suffix. // TODO Generalize. - if (Next == "callw") + if (Next == "call") Next = "calll"; - if (Next == "ljmpw") + if (Next == "ljmp") Next = "ljmpl"; Name = Next; @@ -4585,14 +4611,26 @@ bool X86AsmParser::matchAndEmitIntelInstruction( if (X86Op->isImm()) { // If it's not a constant fall through and let remainder take care of it. const auto *CE = dyn_cast(X86Op->getImm()); - unsigned Size = getPointerWidth(); + // Determine the size. Prioritize the ForcedDataPrefix flag if it was set + // by a 'data32' prefix. Otherwise, fall back to the pointer width of the + // current mode. + unsigned Size = (ForcedDataPrefix == X86::Is32Bit) ? 32 + : (ForcedDataPrefix == X86::Is16Bit) ? 16 + : getPointerWidth(); + ForcedDataPrefix = 0; if (CE && (isIntN(Size, CE->getValue()) || isUIntN(Size, CE->getValue()))) { SmallString<16> Tmp; Tmp += Base; - Tmp += (is64BitMode()) - ? "q" - : (is32BitMode()) ? "l" : (is16BitMode()) ? "w" : " "; + // Append the suffix corresponding to the determined size. + if (Size == 64) + Tmp += "q"; + else if (Size == 32) + Tmp += "l"; + else if (Size == 16) + Tmp += "w"; + else + Tmp += " "; Op.setTokenValue(Tmp); // Do match in ATT mode to allow explicit suffix usage. Match.push_back(MatchInstruction(Operands, Inst, ErrorInfo, diff --git a/llvm/lib/Target/X86/X86InstrAsmAlias.td b/llvm/lib/Target/X86/X86InstrAsmAlias.td index 5a4c3f61672b3..14840873c55a9 100644 --- a/llvm/lib/Target/X86/X86InstrAsmAlias.td +++ b/llvm/lib/Target/X86/X86InstrAsmAlias.td @@ -249,6 +249,12 @@ defm : CMPCCXADD_Aliases<"g", 15>; def : MnemonicAlias<"call", "callw", "att">, Requires<[In16BitMode]>; def : MnemonicAlias<"call", "calll", "att">, Requires<[In32BitMode]>; def : MnemonicAlias<"call", "callq", "att">, Requires<[In64BitMode]>; +def : MnemonicAlias<"call", "callw", "intel">, Requires<[In16BitMode]>; +def : MnemonicAlias<"call", "calll", "intel">, Requires<[In32BitMode]>; +def : MnemonicAlias<"call", "callq", "intel">, Requires<[In64BitMode]>; + +def : MnemonicAlias<"ljmp", "ljmpw", "intel">, Requires<[In16BitMode]>; +def : MnemonicAlias<"ljmp", "ljmpl", "intel">, Requires<[In32BitMode]>; def : MnemonicAlias<"cbw", "cbtw", "att">; def : MnemonicAlias<"cwde", "cwtl", "att">; @@ -260,6 +266,9 @@ def : MnemonicAlias<"cqo", "cqto", "att">; // In 64-bit mode lret maps to lretl; it is not ambiguous with lretq. def : MnemonicAlias<"lret", "lretw", "att">, Requires<[In16BitMode]>; def : MnemonicAlias<"lret", "lretl", "att">, Requires<[Not16BitMode]>; +def : InstAlias<"lgdtw\t$src", (LGDT16m opaquemem:$src), 0>, Requires<[Not64BitMode]>; +def : InstAlias<"lgdtq16\t$src", (LGDT64m_16 opaquemem:$src), 0>, Requires<[In64BitMode]>; +def : InstAlias<"retfw", (LRET16), 0>; def : MnemonicAlias<"leavel", "leave", "att">, Requires<[Not64BitMode]>; def : MnemonicAlias<"leaveq", "leave", "att">, Requires<[In64BitMode]>; @@ -665,6 +674,11 @@ def : InstAlias<"jmpw\t$seg, $off", (FARJMP16i i16imm:$off, i16imm:$seg)>, Req def : InstAlias<"calll\t$seg, $off", (FARCALL32i i32imm:$off, i16imm:$seg)>, Requires<[Not64BitMode]>; def : InstAlias<"jmpl\t$seg, $off", (FARJMP32i i32imm:$off, i16imm:$seg)>, Requires<[Not64BitMode]>; +// Near call aliases for data16/data32 prefix support +def : InstAlias<"callw\t$dst", (CALLpcrel16 i16imm_brtarget:$dst)>; +def : InstAlias<"calll\t$dst", (CALLpcrel32 i32imm_brtarget:$dst)>, Requires<[Not64BitMode]>; +def : InstAlias<"callq\t$dst", (CALL64pcrel32 i64i32imm_brtarget:$dst)>, Requires<[In64BitMode]>; + // Match 'movq , ' as an alias for movabsq. def : InstAlias<"mov{q}\t{$imm, $reg|$reg, $imm}", (MOV64ri GR64:$reg, i64imm:$imm), 0>; @@ -723,6 +737,8 @@ def : InstAlias<"shrd{l}\t{$reg, $mem|$mem, $reg}", (SHRD32mrCL i32mem:$mem, GR3 def : InstAlias<"shrd{q}\t{$reg, $mem|$mem, $reg}", (SHRD64mrCL i64mem:$mem, GR64:$reg), 0>; // test: We accept "testX , " and "testX , " as synonyms. +def : InstAlias<"ljmpw\t$seg, $off", (FARJMP16i i16imm:$off, i16imm:$seg)>, Requires<[Not64BitMode]>; +def : InstAlias<"ljmpl\t$seg, $off", (FARJMP32i i32imm:$off, i16imm:$seg)>, Requires<[Not64BitMode]>; def : InstAlias<"test{b}\t{$mem, $val|$val, $mem}", (TEST8mr i8mem :$mem, GR8 :$val), 0>; def : InstAlias<"test{w}\t{$mem, $val|$val, $mem}", diff --git a/llvm/lib/Target/X86/X86InstrControl.td b/llvm/lib/Target/X86/X86InstrControl.td index e8527cd73abb5..c104a771b3ccf 100644 --- a/llvm/lib/Target/X86/X86InstrControl.td +++ b/llvm/lib/Target/X86/X86InstrControl.td @@ -166,16 +166,16 @@ let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in { Requires<[In64BitMode]>, Sched<[WriteJumpLd]>, NOTRACK; } - let Predicates = [Not64BitMode], AsmVariantName = "att" in { + let Predicates = [Not64BitMode], AsmVariantName = "att" in def FARJMP32i : Iseg32<0xEA, RawFrmImm16, (outs), (ins i32imm:$off, i16imm:$seg), "ljmp{l}\t$seg, $off", []>, OpSize32, Sched<[WriteJump]>; + let AsmVariantName = "att" in def FARJMP16i : Iseg16<0xEA, RawFrmImm16, (outs), (ins i16imm:$off, i16imm:$seg), "ljmp{w}\t$seg, $off", []>, OpSize16, Sched<[WriteJump]>; - } let mayLoad = 1 in { def FARJMP64m : RI<0xFF, MRM5m, (outs), (ins opaquemem:$dst), "ljmp{q}\t{*}$dst", []>, Sched<[WriteJump]>, Requires<[In64BitMode]>; @@ -214,11 +214,6 @@ let isCall = 1 in (outs), (ins i32imm_brtarget:$dst), "call{l}\t$dst", []>, OpSize32, Requires<[Not64BitMode]>, Sched<[WriteJump]>; - let hasSideEffects = 0 in - def CALLpcrel16 : Ii16PCRel<0xE8, RawFrm, - (outs), (ins i16imm_brtarget:$dst), - "call{w}\t$dst", []>, OpSize16, - Requires<[Not64BitMode]>, Sched<[WriteJump]>; def CALL16r : I<0xFF, MRM2r, (outs), (ins GR16:$dst), "call{w}\t{*}$dst", [(X86call GR16:$dst)]>, OpSize16, Requires<[Not64BitMode]>, Sched<[WriteJump]>; @@ -329,6 +324,11 @@ let isCall = 1, Uses = [RSP, SSP], SchedRW = [WriteJump] in { (outs), (ins i64i32imm_brtarget:$dst), "call{q}\t$dst", []>, OpSize32, Requires<[In64BitMode]>; + let hasSideEffects = 0 in + def CALLpcrel16 : Ii16PCRel<0xE8, RawFrm, + (outs), (ins i16imm_brtarget:$dst), + "call{w}\t$dst", []>, OpSize16, + Sched<[WriteJump]>; def CALL64r : I<0xFF, MRM2r, (outs), (ins GR64:$dst), "call{q}\t{*}$dst", [(X86call GR64:$dst)]>, Requires<[In64BitMode,NotUseIndirectThunkCalls,ImportCallOptimizationDisabled]>; diff --git a/llvm/lib/Target/X86/X86InstrSystem.td b/llvm/lib/Target/X86/X86InstrSystem.td index eb0b5a43afdf9..0fe6d854f7637 100644 --- a/llvm/lib/Target/X86/X86InstrSystem.td +++ b/llvm/lib/Target/X86/X86InstrSystem.td @@ -427,6 +427,9 @@ def LGDT32m : I<0x01, MRM2m, (outs), (ins opaquemem:$src), "lgdt{l|d}\t$src", []>, OpSize32, TB, Requires<[Not64BitMode]>; def LGDT64m : I<0x01, MRM2m, (outs), (ins opaquemem:$src), "lgdt{q}\t$src", []>, TB, Requires<[In64BitMode]>; +// Special variant with data16 prefix (OpSize16) for 64-bit mode +def LGDT64m_16 : I<0x01, MRM2m, (outs), (ins opaquemem:$src), + "lgdt{q}\t$src", []>, TB, OpSize16, Requires<[In64BitMode]>; def LIDT16m : I<0x01, MRM3m, (outs), (ins opaquemem:$src), "lidtw\t$src", []>, TB, OpSize16, Requires<[Not64BitMode]>; def LIDT32m : I<0x01, MRM3m, (outs), (ins opaquemem:$src), diff --git a/llvm/test/MC/X86/data-prefix-fail.s b/llvm/test/MC/X86/data-prefix-fail.s index 3088864fc909b..6bce55f2f4ac3 100644 --- a/llvm/test/MC/X86/data-prefix-fail.s +++ b/llvm/test/MC/X86/data-prefix-fail.s @@ -11,20 +11,12 @@ // X86-16-SAME: encoding: [0x66,0x0f,0x01,0x16,0x00,0x00] data32 lgdt 0 -// X86-64: data16 -// X86-64: encoding: [0x66] -// X86-64: lgdtq 0 -// X86-64: encoding: [0x0f,0x01,0x14,0x25,0x00,0x00,0x00,0x00] -// X86-32: data16 -// X86-32: encoding: [0x66] -// X86-32: lgdtl 0 -// X86-32: encoding: [0x0f,0x01,0x15,0x00,0x00,0x00,0x00] +// X86-64: encoding: [0x66,0x0f,0x01,0x14,0x25,0x00,0x00,0x00,0x00] +// X86-32: encoding: [0x66,0x0f,0x01,0x15,0x00,0x00,0x00,0x00] // ERR16: error: redundant data16 prefix data16 lgdt 0 -// X86-64: data16 # encoding: [0x66] -// X86-64-NEXT: callq 0 # encoding: [0xe8,A,A,A,A] -// X86-32: data16 # encoding: [0x66] -// X86-32-NEXT: calll 0 # encoding: [0xe8,A,A,A,A] +// X86-64: callw 0 # encoding: [0x66,0xe8,A,A] +// X86-32: callw 0 # encoding: [0x66,0xe8,A,A] // ERR16: {{.*}}.s:[[#@LINE+1]]:1: error: redundant data16 prefix data16 call 0 diff --git a/llvm/test/MC/X86/intel-syntax-32.s b/llvm/test/MC/X86/intel-syntax-32.s index a503a256ce213..bcf56e79290ea 100644 --- a/llvm/test/MC/X86/intel-syntax-32.s +++ b/llvm/test/MC/X86/intel-syntax-32.s @@ -1,6 +1,35 @@ -// RUN: llvm-mc -triple i686-unknown-unknown -x86-asm-syntax=intel %s | FileCheck %s +// RUN: llvm-mc -triple i686-unknown-unknown -x86-asm-syntax=intel --show-encoding %s | FileCheck %s // CHECK: leaw (%bp,%si), %ax +// CHECK: encoding: [0x67,0x66,0x8d,0x02] lea ax, [bp+si] // CHECK: leaw (%bp,%si), %ax +// CHECK: encoding: [0x67,0x66,0x8d,0x02] lea ax, [si+bp] + +// CHECK: encoding: [0x66,0x6a,0x08] + data16 push 8 + +// CHECK: encoding: [0x6a,0x08] + push 8 + +// CHECK: encoding: [0x66,0xcb] + data16 retf + +// CHECK: encoding: [0xcb] + retf + +// CHECK: encoding: [0x66,0x9a,0xcd,0xab,0xce,0x7a] + data16 call 0x7ace, 0xabcd + +// CHECK: encoding: [0x9a,0xcd,0xab,0x00,0x00,0xce,0x7a] + call 0x7ace, 0xabcd + +// CHECK: encoding: [0xe8,A,A,A,A] + call a + +// CHECK: encoding: [0x66,0xea,0xcd,0xab,0xce,0x7a] + data16 ljmp 0x7ace, 0xabcd + +// CHECK: encoding: [0xea,0xcd,0xab,0x00,0x00,0xce,0x7a] + ljmp 0x7ace, 0xabcd diff --git a/llvm/test/MC/X86/x86-16-intel.s b/llvm/test/MC/X86/x86-16-intel.s new file mode 100644 index 0000000000000..77ae4ae217218 --- /dev/null +++ b/llvm/test/MC/X86/x86-16-intel.s @@ -0,0 +1,13 @@ +// RUN: llvm-mc -triple i386-unknown-unknown-code16 --x86-asm-syntax=intel --show-encoding %s | FileCheck %s + +// CHECK: pushl $8 +// CHECK: encoding: [0x66,0x6a,0x08] + data32 push 8 + +// CHECK: pushw $8 +// CHECK: encoding: [0x6a,0x08] + push 8 + +// CHECK: lretl +// CHECK: encoding: [0x66,0xcb] + data32 retf diff --git a/llvm/test/MC/X86/x86-16.s b/llvm/test/MC/X86/x86-16.s index b0a4bda56fcbf..b4e116ab1a0fb 100644 --- a/llvm/test/MC/X86/x86-16.s +++ b/llvm/test/MC/X86/x86-16.s @@ -1060,3 +1060,15 @@ xresldtrk // CHECK: encoding: [0x66,0x8b,0x1e,A,A] // CHECK: fixup A - offset: 3, value: nearer, kind: FK_Data_2 movl nearer, %ebx + +// CHECK: pushl $8 +// CHECK: encoding: [0x66,0x6a,0x08] +data32 push $8 + +// CHECK: pushl $8 +// CHECK: encoding: [0x66,0x6a,0x08] +pushl $8 + +// CHECK: pushw $8 +// CHECK: encoding: [0x6a,0x08] +push $8 diff --git a/llvm/test/MC/X86/x86-32.s b/llvm/test/MC/X86/x86-32.s index 8bfcf82c0cf75..779a913356b84 100644 --- a/llvm/test/MC/X86/x86-32.s +++ b/llvm/test/MC/X86/x86-32.s @@ -1101,10 +1101,7 @@ lretw // CHECK: encoding: [0x66] data16 -// CHECK: data16 -// CHECK: encoding: [0x66] -// CHECK: lgdtl 4(%eax) -// CHECK: encoding: [0x0f,0x01,0x50,0x04] +// CHECK: encoding: [0x66,0x0f,0x01,0x50,0x04] data16 lgdt 4(%eax) // CHECK: rdpid %eax diff --git a/llvm/test/MC/X86/x86-64.s b/llvm/test/MC/X86/x86-64.s index 911f4674bd2cc..a03fa00e55f7e 100644 --- a/llvm/test/MC/X86/x86-64.s +++ b/llvm/test/MC/X86/x86-64.s @@ -1081,10 +1081,7 @@ movq %mm5, %rbx // CHECK: movq %mm5, %rbx # encoding: [0x48,0x0f,0x7e,0xeb] rex64 // CHECK: rex64 # encoding: [0x48] data16 // CHECK: data16 # encoding: [0x66] -// CHECK: data16 -// CHECK: encoding: [0x66] -// CHECK: lgdtq 4(%rax) -// CHECK: encoding: [0x0f,0x01,0x50,0x04] +// CHECK: encoding: [0x66,0x0f,0x01,0x50,0x04] data16 lgdt 4(%rax) // PR8855