[X86] Apply the data32 mode switch in the Intel matcher (#212417)
In .code16, `data32 push 8` in Intel syntax assembled as `pushw $8` with the 66 prefix dropped, and `data32 push 0x1234` truncated the immediate to 16 bits. AT&T syntax gets both right. `ForcedDataPrefix` is set while parsing either syntax, but only `matchAndEmitATTInstruction` switched mode on it, so the Intel path took the operand size from the mode and never saw the prefix. Do the same switch in `matchAndEmitIntelInstruction`. The mode has to go back to 16-bit before the instruction is emitted, otherwise the 32-bit form is emitted without its 66 prefix. That function has several error returns partway through matching, so a scope guard covers those. Encodings after the change match both AT&T syntax and GNU as: ``` data32 push 8 [0x6a,0x08] -> [0x66,0x6a,0x08] data32 push 0x1234 [0x68,0x34,0x12] -> [0x66,0x68,0x34,0x12,0x00,0x00] ``` Fixes #156286
This commit is contained in:
parent
dc57785129
commit
bdddd3e720
2 changed files with 56 additions and 0 deletions
|
|
@ -4600,6 +4600,18 @@ bool X86AsmParser::matchAndEmitIntelInstruction(
|
|||
MCStreamer &Out, uint64_t &ErrorInfo, bool MatchingInlineAsm) {
|
||||
X86Operand &Op = static_cast<X86Operand &>(*Operands[0]);
|
||||
SMRange EmptyRange;
|
||||
// In 16-bit mode, if data32 is specified, temporarily switch to 32-bit mode
|
||||
// when matching the instruction. The mode must be restored before the
|
||||
// instruction is emitted, or the 32-bit form loses its 0x66 prefix.
|
||||
const bool ForcedData32 = ForcedDataPrefix == X86::Is32Bit;
|
||||
auto RestoreMode = [&] {
|
||||
if (ForcedData32) {
|
||||
SwitchMode(X86::Is16Bit);
|
||||
ForcedDataPrefix = 0;
|
||||
}
|
||||
};
|
||||
if (ForcedData32)
|
||||
SwitchMode(X86::Is32Bit);
|
||||
// Find one unsized memory operand, if present.
|
||||
X86Operand *UnsizedMemOp = nullptr;
|
||||
for (const auto &Op : Operands) {
|
||||
|
|
@ -4697,6 +4709,7 @@ bool X86AsmParser::matchAndEmitIntelInstruction(
|
|||
|
||||
// If it's a bad mnemonic, all results will be the same.
|
||||
if (Match.back() == Match_MnemonicFail) {
|
||||
RestoreMode();
|
||||
return Error(IDLoc, "invalid instruction mnemonic '" + Mnemonic + "'",
|
||||
Op.getLocRange(), MatchingInlineAsm);
|
||||
}
|
||||
|
|
@ -4721,6 +4734,9 @@ bool X86AsmParser::matchAndEmitIntelInstruction(
|
|||
/*Len=*/0, UnsizedMemOp->getMemFrontendSize());
|
||||
}
|
||||
|
||||
// Matching is done, so drop back to 16-bit before anything is emitted.
|
||||
RestoreMode();
|
||||
|
||||
// If exactly one matched, then we treat that as a successful match (and the
|
||||
// instruction will already have been filled in correctly, since the failing
|
||||
// matches won't have modified it).
|
||||
|
|
|
|||
40
llvm/test/MC/X86/intel-syntax-data32-16.s
Normal file
40
llvm/test/MC/X86/intel-syntax-data32-16.s
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// RUN: not llvm-mc -triple i386-unknown-unknown-code16 -x86-asm-syntax=intel --show-encoding %s 2> %t.err | FileCheck %s
|
||||
// RUN: FileCheck --check-prefix=ERR < %t.err %s
|
||||
|
||||
// A data32 prefix makes an unsized push of an immediate 32-bit, matching the
|
||||
// AT&T behaviour of the same instruction.
|
||||
|
||||
// CHECK: push 8
|
||||
// CHECK-SAME: encoding: [0x66,0x6a,0x08]
|
||||
data32 push 8
|
||||
|
||||
// CHECK: push 4660
|
||||
// CHECK-SAME: encoding: [0x66,0x68,0x34,0x12,0x00,0x00]
|
||||
data32 push 0x1234
|
||||
|
||||
// CHECK: push eax
|
||||
// CHECK-SAME: encoding: [0x66,0x50]
|
||||
data32 push eax
|
||||
|
||||
// Without the prefix the operand size still comes from the mode.
|
||||
|
||||
// CHECK: push 8
|
||||
// CHECK-SAME: encoding: [0x6a,0x08]
|
||||
push 8
|
||||
|
||||
// The prefix applies to one instruction only, so 16-bit mode has to be back in
|
||||
// effect for whatever follows.
|
||||
|
||||
// CHECK: push 4660
|
||||
// CHECK-SAME: encoding: [0x68,0x34,0x12]
|
||||
push 0x1234
|
||||
|
||||
// The same holds when the prefixed instruction fails to match, otherwise the
|
||||
// 32-bit mode used for matching leaks into the rest of the file.
|
||||
|
||||
// ERR: error: invalid instruction mnemonic 'nosuchinsn'
|
||||
data32 nosuchinsn
|
||||
|
||||
// CHECK: push 8
|
||||
// CHECK-SAME: encoding: [0x6a,0x08]
|
||||
push 8
|
||||
Loading…
Reference in a new issue