[PATCH v3 02/11] [x86] Add basic support for .code16
David Woodhouse
dwmw2 at infradead.org
Fri Dec 20 06:57:59 PST 2013
From: David Woodhouse <David.Woodhouse at intel.com>
This is not really expected to work right yet. Mostly because we will
still emit the OpSize (0x66) prefix in all the wrong places, along with
a number of other corner cases.
Review feedback suggested that the best approach was to enable this
incrementally with progressive test cases, rather than a series of
preparatory work followed by flipping the switch to actually accept
".code16" at the end.
---
lib/Target/X86/AsmParser/X86AsmParser.cpp | 43 +++-
lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp | 12 +-
lib/Target/X86/X86.td | 2 +
lib/Target/X86/X86InstrInfo.td | 7 +
lib/Target/X86/X86Subtarget.h | 9 +-
test/MC/X86/address-size.s | 8 +
test/MC/X86/x86-16.s | 259 +++++++++++++++++++++++
7 files changed, 329 insertions(+), 11 deletions(-)
create mode 100644 test/MC/X86/x86-16.s
diff --git a/lib/Target/X86/AsmParser/X86AsmParser.cpp b/lib/Target/X86/AsmParser/X86AsmParser.cpp
index ef363b8..01746fa 100644
--- a/lib/Target/X86/AsmParser/X86AsmParser.cpp
+++ b/lib/Target/X86/AsmParser/X86AsmParser.cpp
@@ -544,10 +544,18 @@ private:
// FIXME: Can tablegen auto-generate this?
return (STI.getFeatureBits() & X86::Mode64Bit) != 0;
}
- void SwitchMode() {
+ bool is16BitMode() const {
+ // FIXME: Can tablegen auto-generate this?
+ return (STI.getFeatureBits() & X86::Mode16Bit) != 0;
+ }
+ void SwitchMode64() {
unsigned FB = ComputeAvailableFeatures(STI.ToggleFeature(X86::Mode64Bit));
setAvailableFeatures(FB);
}
+ void SwitchMode16() {
+ unsigned FB = ComputeAvailableFeatures(STI.ToggleFeature(X86::Mode16Bit));
+ setAvailableFeatures(FB);
+ }
bool isParsingIntelSyntax() {
return getParser().getAssemblerDialect();
@@ -1033,7 +1041,8 @@ struct X86Operand : public MCParsedAsmOperand {
} // end anonymous namespace.
bool X86AsmParser::isSrcOp(X86Operand &Op) {
- unsigned basereg = is64BitMode() ? X86::RSI : X86::ESI;
+ unsigned basereg =
+ is64BitMode() ? X86::RSI : (is16BitMode() ? X86::SI : X86::ESI);
return (Op.isMem() &&
(Op.Mem.SegReg == 0 || Op.Mem.SegReg == X86::DS) &&
@@ -1043,7 +1052,8 @@ bool X86AsmParser::isSrcOp(X86Operand &Op) {
}
bool X86AsmParser::isDstOp(X86Operand &Op) {
- unsigned basereg = is64BitMode() ? X86::RDI : X86::EDI;
+ unsigned basereg =
+ is64BitMode() ? X86::RDI : (is16BitMode() ? X86::DI : X86::EDI);
return Op.isMem() &&
(Op.Mem.SegReg == 0 || Op.Mem.SegReg == X86::ES) &&
@@ -1193,7 +1203,8 @@ X86AsmParser::CreateMemForInlineAsm(unsigned SegReg, const MCExpr *Disp,
// operand to ensure proper matching. Just pick a GPR based on the size of
// a pointer.
if (!Info.IsVarDecl) {
- unsigned RegNo = is64BitMode() ? X86::RBX : X86::EBX;
+ unsigned RegNo =
+ is64BitMode() ? X86::RBX : (is16BitMode() ? X86::BX : X86::EBX);
return X86Operand::CreateReg(RegNo, Start, End, /*AddressOf=*/true,
SMLoc(), Identifier, Info.OpDecl);
}
@@ -1612,7 +1623,8 @@ X86Operand *X86AsmParser::ParseIntelOffsetOfOperator() {
// 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 : X86::EBX;
+ unsigned RegNo =
+ is64BitMode() ? X86::RBX : (is16BitMode() ? X86::BX : X86::EBX);
return X86Operand::CreateReg(RegNo, Start, End, /*GetAddress=*/true,
OffsetOfLoc, Identifier, Info.OpDecl);
}
@@ -2678,18 +2690,31 @@ bool X86AsmParser::ParseDirectiveWord(unsigned Size, SMLoc L) {
}
/// ParseDirectiveCode
-/// ::= .code32 | .code64
+/// ::= .code16 | .code32 | .code64
bool X86AsmParser::ParseDirectiveCode(StringRef IDVal, SMLoc L) {
- if (IDVal == ".code32") {
+ if (IDVal == ".code16") {
+ Parser.Lex();
+ if (!is16BitMode()) {
+ if (is64BitMode())
+ SwitchMode64();
+ SwitchMode16();
+ getParser().getStreamer().EmitAssemblerFlag(MCAF_Code16);
+ }
+ } else if (IDVal == ".code32") {
Parser.Lex();
if (is64BitMode()) {
- SwitchMode();
+ SwitchMode64();
+ getParser().getStreamer().EmitAssemblerFlag(MCAF_Code32);
+ } else if (is16BitMode()) {
+ SwitchMode16();
getParser().getStreamer().EmitAssemblerFlag(MCAF_Code32);
}
} else if (IDVal == ".code64") {
Parser.Lex();
if (!is64BitMode()) {
- SwitchMode();
+ if (is16BitMode())
+ SwitchMode16();
+ SwitchMode64();
getParser().getStreamer().EmitAssemblerFlag(MCAF_Code64);
}
} else {
diff --git a/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp b/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
index 0e48a35..876138e 100644
--- a/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
+++ b/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
@@ -49,7 +49,13 @@ public:
bool is32BitMode() const {
// FIXME: Can tablegen auto-generate this?
- return (STI.getFeatureBits() & X86::Mode64Bit) == 0;
+ return (STI.getFeatureBits() & X86::Mode64Bit) == 0 &&
+ (STI.getFeatureBits() & X86::Mode16Bit) == 0;
+ }
+
+ bool is16BitMode() const {
+ // FIXME: Can tablegen auto-generate this?
+ return (STI.getFeatureBits() & X86::Mode16Bit) != 0;
}
unsigned GetX86RegNum(const MCOperand &MO) const {
@@ -1158,6 +1164,9 @@ void X86MCCodeEmitter::EmitOpcodePrefix(uint64_t TSFlags, unsigned &CurByte,
} else if (is64BitMode()) {
assert(!Is16BitMemOperand(MI, MemOperand));
need_address_override = Is32BitMemOperand(MI, MemOperand);
+ } else if (is16BitMode()) {
+ assert(!Is64BitMemOperand(MI, MemOperand));
+ need_address_override = !Is16BitMemOperand(MI, MemOperand);
} else if (is32BitMode()) {
assert(!Is64BitMemOperand(MI, MemOperand));
need_address_override = Is16BitMemOperand(MI, MemOperand);
@@ -1169,6 +1178,7 @@ void X86MCCodeEmitter::EmitOpcodePrefix(uint64_t TSFlags, unsigned &CurByte,
EmitByte(0x67, CurByte, OS);
// Emit the operand size opcode prefix as needed.
+ // FIXME for is16BitMode().
if (TSFlags & X86II::OpSize)
EmitByte(0x66, CurByte, OS);
diff --git a/lib/Target/X86/X86.td b/lib/Target/X86/X86.td
index d55178e..7ec9468 100644
--- a/lib/Target/X86/X86.td
+++ b/lib/Target/X86/X86.td
@@ -22,6 +22,8 @@ include "llvm/Target/Target.td"
def Mode64Bit : SubtargetFeature<"64bit-mode", "In64BitMode", "true",
"64-bit mode (x86_64)">;
+def Mode16Bit : SubtargetFeature<"16bit-mode", "In16BitMode", "true",
+ "16-bit mode (i8086)">;
//===----------------------------------------------------------------------===//
// X86 Subtarget features
diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td
index f006b91..4fee939 100644
--- a/lib/Target/X86/X86InstrInfo.td
+++ b/lib/Target/X86/X86InstrInfo.td
@@ -696,6 +696,13 @@ def Not64BitMode : Predicate<"!Subtarget->is64Bit()">,
AssemblerPredicate<"!Mode64Bit", "Not 64-bit mode">;
def In64BitMode : Predicate<"Subtarget->is64Bit()">,
AssemblerPredicate<"Mode64Bit", "64-bit mode">;
+def In16BitMode : Predicate<"Subtarget->is16Bit()">,
+ AssemblerPredicate<"Mode16Bit", "16-bit mode">;
+def Not16BitMode : Predicate<"!Subtarget->is16Bit()">,
+ AssemblerPredicate<"!Mode16Bit", "Not 16-bit mode">;
+def In32BitMode : Predicate<"!Subtarget->is64Bit() && !Subtarget->is16Bit()">,
+ AssemblerPredicate<"!Mode64Bit,!Mode16Bit",
+ "32-bit mode">;
def IsWin64 : Predicate<"Subtarget->isTargetWin64()">;
def IsNaCl : Predicate<"Subtarget->isTargetNaCl()">;
def NotNaCl : Predicate<"!Subtarget->isTargetNaCl()">;
diff --git a/lib/Target/X86/X86Subtarget.h b/lib/Target/X86/X86Subtarget.h
index 93d251a..1578cea 100644
--- a/lib/Target/X86/X86Subtarget.h
+++ b/lib/Target/X86/X86Subtarget.h
@@ -205,9 +205,12 @@ private:
/// StackAlignOverride - Override the stack alignment.
unsigned StackAlignOverride;
- /// In64BitMode - True if compiling for 64-bit, false for 32-bit.
+ /// In64BitMode - True if compiling for 64-bit, false for 32-bit or 16-bit.
bool In64BitMode;
+ /// In16BitMode - True if compiling for 16-bit, false for 32-bit or 64-bit.
+ bool In16BitMode;
+
public:
/// This constructor initializes the data members to match that
/// of the specified triple.
@@ -244,6 +247,10 @@ public:
return In64BitMode;
}
+ bool is16Bit() const {
+ return In16BitMode;
+ }
+
/// Is this x86_64 with the ILP32 programming model (x32 ABI)?
bool isTarget64BitILP32() const {
return In64BitMode && (TargetTriple.getEnvironment() == Triple::GNUX32 ||
diff --git a/test/MC/X86/address-size.s b/test/MC/X86/address-size.s
index 936cd57..c9d04c4 100644
--- a/test/MC/X86/address-size.s
+++ b/test/MC/X86/address-size.s
@@ -17,3 +17,11 @@
// CHECK: encoding: [0x67,0xc7,0x00,0x78,0x56,0x34,0x12]
movw $0x1234, 0x5678(%bp)
// CHECK: encoding: [0x67,0x66,0xc7,0x86,0x78,0x56,0x34,0x12]
+
+ .code16
+ movb $0x0, (%si)
+// CHECK: encoding: [0xc6,0x04,0x00]
+ movb $0x0, (%esi)
+// CHECK: encoding: [0x67,0xc6,0x06,0x00]
+ movb $0x5a, (%di,%bp,1)
+// CHECK: encoding: [0xc6,0x03,0x5a]
diff --git a/test/MC/X86/x86-16.s b/test/MC/X86/x86-16.s
new file mode 100644
index 0000000..36f3b19
--- /dev/null
+++ b/test/MC/X86/x86-16.s
@@ -0,0 +1,259 @@
+// RUN: llvm-mc -triple i386-unknown-unknown --show-encoding %s | FileCheck %s
+
+ .code16
+
+ pause
+// CHECK: pause
+// CHECK: encoding: [0xf3,0x90]
+ sfence
+// CHECK: sfence
+// CHECK: encoding: [0x0f,0xae,0xf8]
+ lfence
+// CHECK: lfence
+// CHECK: encoding: [0x0f,0xae,0xe8]
+ mfence
+ stgi
+// CHECK: stgi
+// CHECK: encoding: [0x0f,0x01,0xdc]
+ clgi
+// CHECK: clgi
+// CHECK: encoding: [0x0f,0x01,0xdd]
+
+ rdtscp
+// CHECK: rdtscp
+// CHECK: encoding: [0x0f,0x01,0xf9]
+
+
+// CHECK: testb %bl, %cl # encoding: [0x84,0xcb]
+ testb %bl, %cl
+
+into
+// CHECK: into
+// CHECK: encoding: [0xce]
+int3
+// CHECK: int3
+// CHECK: encoding: [0xcc]
+int $4
+// CHECK: int $4
+// CHECK: encoding: [0xcd,0x04]
+int $255
+// CHECK: int $255
+// CHECK: encoding: [0xcd,0xff]
+
+// CHECK: fmul %st(0)
+// CHECK: encoding: [0xd8,0xc8]
+ fmul %st(0), %st
+
+// CHECK: fadd %st(0)
+// CHECK: encoding: [0xd8,0xc0]
+ fadd %st(0), %st
+
+// CHECK: fsub %st(0)
+// CHECK: encoding: [0xd8,0xe0]
+ fsub %st(0), %st
+
+// CHECK: fsubr %st(0)
+// CHECK: encoding: [0xd8,0xe8]
+ fsubr %st(0), %st
+
+// CHECK: fdivr %st(0)
+// CHECK: encoding: [0xd8,0xf8]
+ fdivr %st(0), %st
+
+// CHECK: fdiv %st(0)
+// CHECK: encoding: [0xd8,0xf0]
+ fdiv %st(0), %st
+
+// CHECK: wait
+// CHECK: encoding: [0x9b]
+ fwait
+
+
+ setc %bl
+ setnae %bl
+ setnb %bl
+ setnc %bl
+ setna %bl
+ setnbe %bl
+ setpe %bl
+ setpo %bl
+ setnge %bl
+ setnl %bl
+ setng %bl
+ setnle %bl
+
+ setneb %cl // CHECK: setne %cl
+ setcb %bl // CHECK: setb %bl
+ setnaeb %bl // CHECK: setb %bl
+
+
+// CHECK: lcalll $31438, $31438
+// CHECK: lcalll $31438, $31438
+// CHECK: ljmpl $31438, $31438
+// CHECK: ljmpl $31438, $31438
+
+calll $0x7ace,$0x7ace
+lcalll $0x7ace,$0x7ace
+jmpl $0x7ace,$0x7ace
+ljmpl $0x7ace,$0x7ace
+
+// CHECK: calll a
+ calll a
+
+// CHECK: incb %al # encoding: [0xfe,0xc0]
+ incb %al
+
+// CHECK: decb %al # encoding: [0xfe,0xc8]
+ decb %al
+
+// CHECK: pshufw $14, %mm4, %mm0 # encoding: [0x0f,0x70,0xc4,0x0e]
+pshufw $14, %mm4, %mm0
+
+// CHECK: pshufw $90, %mm4, %mm0 # encoding: [0x0f,0x70,0xc4,0x5a]
+pshufw $90, %mm4, %mm0
+
+// CHECK: aaa
+// CHECK: encoding: [0x37]
+ aaa
+
+// CHECK: aad $1
+// CHECK: encoding: [0xd5,0x01]
+ aad $1
+
+// CHECK: aad
+// CHECK: encoding: [0xd5,0x0a]
+ aad $0xA
+
+// CHECK: aad
+// CHECK: encoding: [0xd5,0x0a]
+ aad
+
+// CHECK: aam $2
+// CHECK: encoding: [0xd4,0x02]
+ aam $2
+
+// CHECK: aam
+// CHECK: encoding: [0xd4,0x0a]
+ aam $0xA
+
+// CHECK: aam
+// CHECK: encoding: [0xd4,0x0a]
+ aam
+
+// CHECK: aas
+// CHECK: encoding: [0x3f]
+ aas
+
+// CHECK: daa
+// CHECK: encoding: [0x27]
+ daa
+
+// CHECK: das
+// CHECK: encoding: [0x2f]
+ das
+
+// CHECK: arpl %bx, %bx
+// CHECK: encoding: [0x63,0xdb]
+ arpl %bx,%bx
+
+// CHECK: arpl %bx, 6(%ecx)
+// CHECK: encoding: [0x67,0x63,0x59,0x06]
+ arpl %bx,6(%ecx)
+
+// CHECK: fcompi %st(2)
+// CHECK: encoding: [0xdf,0xf2]
+ fcompi %st(2), %st
+
+// CHECK: fcompi %st(2)
+// CHECK: encoding: [0xdf,0xf2]
+ fcompi %st(2)
+
+// CHECK: fcompi
+// CHECK: encoding: [0xdf,0xf1]
+ fcompi
+
+// CHECK: fucompi %st(2)
+// CHECK: encoding: [0xdf,0xea]
+ fucompi %st(2),%st
+
+// CHECK: fucompi %st(2)
+// CHECK: encoding: [0xdf,0xea]
+ fucompi %st(2)
+
+// CHECK: fucompi
+// CHECK: encoding: [0xdf,0xe9]
+ fucompi
+
+// CHECK: wait
+// CHECK: encoding: [0x9b]
+ fclex
+
+// CHECK: fnclex
+// CHECK: encoding: [0xdb,0xe2]
+ fnclex
+
+// CHECK: ud2
+// CHECK: encoding: [0x0f,0x0b]
+ ud2
+
+// CHECK: ud2
+// CHECK: encoding: [0x0f,0x0b]
+ ud2a
+
+// CHECK: ud2b
+// CHECK: encoding: [0x0f,0xb9]
+ ud2b
+
+// CHECK: loope 0
+// CHECK: encoding: [0xe1,A]
+ loopz 0
+
+// CHECK: loopne 0
+// CHECK: encoding: [0xe0,A]
+ loopnz 0
+
+// CHECK: outsb # encoding: [0x6e]
+// CHECK: outsb
+// CHECK: outsb
+ outsb
+ outsb %ds:(%si), %dx
+ outsb (%si), %dx
+
+// CHECK: insb # encoding: [0x6c]
+// CHECK: insb
+ insb
+ insb %dx, %es:(%di)
+
+// CHECK: movsb # encoding: [0xa4]
+// CHECK: movsb
+// CHECK: movsb
+ movsb
+ movsb %ds:(%si), %es:(%di)
+ movsb (%si), %es:(%di)
+
+// CHECK: lodsb # encoding: [0xac]
+// CHECK: lodsb
+// CHECK: lodsb
+// CHECK: lodsb
+// CHECK: lodsb
+ lodsb
+ lodsb %ds:(%si), %al
+ lodsb (%si), %al
+ lods %ds:(%si), %al
+ lods (%si), %al
+
+// CHECK: stosb # encoding: [0xaa]
+// CHECK: stosb
+// CHECK: stosb
+ stosb
+ stosb %al, %es:(%di)
+ stos %al, %es:(%di)
+
+// CHECK: fsubp
+// CHECK: encoding: [0xde,0xe1]
+fsubp %st,%st(1)
+
+// CHECK: fsubp %st(2)
+// CHECK: encoding: [0xde,0xe2]
+fsubp %st, %st(2)
+
--
1.8.3.1
More information about the llvm-commits
mailing list