[x86] Add basic support for .code16
authorCraig Topper <craig.topper@gmail.com>
Mon, 6 Jan 2014 04:55:54 +0000 (04:55 +0000)
committerCraig Topper <craig.topper@gmail.com>
Mon, 6 Jan 2014 04:55:54 +0000 (04:55 +0000)
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. Those will all be fixed in the subsequent
commits.

Patch from David Woodhouse.

llvm-svn: 198584

llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp
llvm/lib/Target/X86/X86.td
llvm/lib/Target/X86/X86InstrInfo.td
llvm/lib/Target/X86/X86Subtarget.cpp
llvm/lib/Target/X86/X86Subtarget.h
llvm/test/MC/X86/address-size.s
llvm/test/MC/X86/x86-16.s [new file with mode: 0644]

index 0f8e9f7..86ba185 100644 (file)
@@ -544,9 +544,21 @@ private:
     // FIXME: Can tablegen auto-generate this?
     return (STI.getFeatureBits() & X86::Mode64Bit) != 0;
   }
-  void SwitchMode() {
-    unsigned FB = ComputeAvailableFeatures(STI.ToggleFeature(X86::Mode64Bit));
+  bool is32BitMode() const {
+    // FIXME: Can tablegen auto-generate this?
+    return (STI.getFeatureBits() & X86::Mode32Bit) != 0;
+  }
+  bool is16BitMode() const {
+    // FIXME: Can tablegen auto-generate this?
+    return (STI.getFeatureBits() & X86::Mode16Bit) != 0;
+  }
+  void SwitchMode(uint64_t mode) {
+    uint64_t oldMode = STI.getFeatureBits() &
+        (X86::Mode64Bit | X86::Mode32Bit | X86::Mode16Bit);
+    unsigned FB = ComputeAvailableFeatures(STI.ToggleFeature(oldMode | mode));
     setAvailableFeatures(FB);
+    assert(mode == (STI.getFeatureBits() &
+                    (X86::Mode64Bit | X86::Mode32Bit | X86::Mode16Bit)));
   }
 
   bool isParsingIntelSyntax() {
@@ -1033,7 +1045,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 : (is32BitMode() ? X86::ESI : X86::SI);
 
   return (Op.isMem() &&
     (Op.Mem.SegReg == 0 || Op.Mem.SegReg == X86::DS) &&
@@ -1043,7 +1056,8 @@ bool X86AsmParser::isSrcOp(X86Operand &Op) {
 }
 
 bool X86AsmParser::isDstOp(X86Operand &Op) {
-  unsigned basereg = is64BitMode() ? X86::RDI : X86::EDI;
+  unsigned basereg =
+      is64BitMode() ? X86::RDI : (is32BitMode() ? X86::EDI : X86::DI);
 
   return Op.isMem() &&
     (Op.Mem.SegReg == 0 || Op.Mem.SegReg == X86::ES) &&
@@ -1193,7 +1207,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 : (is32BitMode() ? X86::EBX : X86::BX);
       return X86Operand::CreateReg(RegNo, Start, End, /*AddressOf=*/true,
                                    SMLoc(), Identifier, Info.OpDecl);
     }
@@ -1612,7 +1627,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 : (is32BitMode() ? X86::EBX : X86::BX);
   return X86Operand::CreateReg(RegNo, Start, End, /*GetAddress=*/true,
                                OffsetOfLoc, Identifier, Info.OpDecl);
 }
@@ -2679,18 +2695,24 @@ 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()) {
+      SwitchMode(X86::Mode16Bit);
+      getParser().getStreamer().EmitAssemblerFlag(MCAF_Code16);
+    }
+  } else  if (IDVal == ".code32") {
     Parser.Lex();
-    if (is64BitMode()) {
-      SwitchMode();
+    if (!is32BitMode()) {
+      SwitchMode(X86::Mode32Bit);
       getParser().getStreamer().EmitAssemblerFlag(MCAF_Code32);
     }
   } else if (IDVal == ".code64") {
     Parser.Lex();
     if (!is64BitMode()) {
-      SwitchMode();
+      SwitchMode(X86::Mode64Bit);
       getParser().getStreamer().EmitAssemblerFlag(MCAF_Code64);
     }
   } else {
index 293541a..51b90b1 100644 (file)
@@ -49,7 +49,12 @@ public:
 
   bool is32BitMode() const {
     // FIXME: Can tablegen auto-generate this?
-    return (STI.getFeatureBits() & X86::Mode64Bit) == 0;
+    return (STI.getFeatureBits() & X86::Mode32Bit) != 0;
+  }
+
+  bool is16BitMode() const {
+    // FIXME: Can tablegen auto-generate this?
+    return (STI.getFeatureBits() & X86::Mode16Bit) != 0;
   }
 
   unsigned GetX86RegNum(const MCOperand &MO) const {
@@ -1177,13 +1182,16 @@ void X86MCCodeEmitter::EmitOpcodePrefix(uint64_t TSFlags, unsigned &CurByte,
     assert(!Is64BitMemOperand(MI, MemOperand));
     need_address_override = Is16BitMemOperand(MI, MemOperand);
   } else {
-    need_address_override = false;
+    assert(is16BitMode());
+    assert(!Is64BitMemOperand(MI, MemOperand));
+    need_address_override = !Is16BitMemOperand(MI, MemOperand);
   }
 
   if (need_address_override)
     EmitByte(0x67, CurByte, OS);
 
   // Emit the operand size opcode prefix as needed.
+  // FIXME for is16BitMode().
   if (TSFlags & X86II::OpSize)
     EmitByte(0x66, CurByte, OS);
 
index 403e50d..09803f3 100644 (file)
@@ -47,9 +47,9 @@ std::string X86_MC::ParseX86Triple(StringRef TT) {
   Triple TheTriple(TT);
   std::string FS;
   if (TheTriple.getArch() == Triple::x86_64)
-    FS = "+64bit-mode";
+    FS = "+64bit-mode,-32bit-mode,-16bit-mode";
   else
-    FS = "-64bit-mode";
+    FS = "-64bit-mode,+32bit-mode,-16bit-mode";
   return FS;
 }
 
index d55178e..e755fae 100644 (file)
@@ -22,6 +22,10 @@ include "llvm/Target/Target.td"
 
 def Mode64Bit : SubtargetFeature<"64bit-mode", "In64BitMode", "true",
                                   "64-bit mode (x86_64)">;
+def Mode32Bit : SubtargetFeature<"32bit-mode", "In32BitMode", "true",
+                                  "32-bit mode (80386)">;
+def Mode16Bit : SubtargetFeature<"16bit-mode", "In16BitMode", "true",
+                                  "16-bit mode (i8086)">;
 
 //===----------------------------------------------------------------------===//
 // X86 Subtarget features
index 707a313..9642a89 100644 (file)
@@ -700,6 +700,12 @@ 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->is32Bit()">,
+                             AssemblerPredicate<"Mode32Bit", "32-bit mode">;
 def IsWin64      : Predicate<"Subtarget->isTargetWin64()">;
 def IsNaCl       : Predicate<"Subtarget->isTargetNaCl()">;
 def NotNaCl      : Predicate<"!Subtarget->isTargetNaCl()">;
index 597fccb..5ee986c 100644 (file)
@@ -482,6 +482,12 @@ void X86Subtarget::resetSubtargetFeatures(StringRef CPU, StringRef FS) {
   // target data structure which is shared with MC code emitter, etc.
   if (In64BitMode)
     ToggleFeature(X86::Mode64Bit);
+  else if (In32BitMode)
+    ToggleFeature(X86::Mode32Bit);
+  else if (In16BitMode)
+    ToggleFeature(X86::Mode16Bit);
+  else
+    llvm_unreachable("Not 16-bit, 32-bit or 64-bit mode!");
 
   DEBUG(dbgs() << "Subtarget features: SSELevel " << X86SSELevel
                << ", 3DNowLevel " << X863DNowLevel
@@ -551,7 +557,9 @@ X86Subtarget::X86Subtarget(const std::string &TT, const std::string &CPU,
   , PICStyle(PICStyles::None)
   , TargetTriple(TT)
   , StackAlignOverride(StackAlignOverride)
-  , In64BitMode(is64Bit) {
+  , In64BitMode(is64Bit)
+  , In32BitMode(!is64Bit)
+  , In16BitMode(false) {
   initializeEnvironment();
   resetSubtargetFeatures(CPU, FS);
 }
index 93d251a..f39389e 100644 (file)
@@ -205,9 +205,15 @@ 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 16-bit or 32-bit.
   bool In64BitMode;
 
+  /// In32BitMode - True if compiling for 32-bit, false for 16-bit or 64-bit.
+  bool In32BitMode;
+
+  /// 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 +250,14 @@ public:
     return In64BitMode;
   }
 
+  bool is32Bit() const {
+    return In32BitMode;
+  }
+
+  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 ||
index 936cd57..c9d04c4 100644 (file)
 // 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/llvm/test/MC/X86/x86-16.s b/llvm/test/MC/X86/x86-16.s
new file mode 100644 (file)
index 0000000..36f3b19
--- /dev/null
@@ -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)
+