[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