diff --git a/lib/Target/X86/AsmParser/X86AsmParser.cpp b/lib/Target/X86/AsmParser/X86AsmParser.cpp index 0f8e9f7b4ad..86ba1858190 100644 --- a/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ b/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -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 (is64BitMode()) { - SwitchMode(); + if (!is16BitMode()) { + SwitchMode(X86::Mode16Bit); + getParser().getStreamer().EmitAssemblerFlag(MCAF_Code16); + } + } else if (IDVal == ".code32") { + Parser.Lex(); + 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 { diff --git a/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp b/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp index 293541a8438..51b90b1c497 100644 --- a/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp +++ b/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp @@ -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); diff --git a/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp b/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp index 403e50dbf8a..09803f372f5 100644 --- a/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp +++ b/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp @@ -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; } diff --git a/lib/Target/X86/X86.td b/lib/Target/X86/X86.td index d55178ea12d..e755faeb171 100644 --- a/lib/Target/X86/X86.td +++ b/lib/Target/X86/X86.td @@ -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 diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index 707a313f14b..9642a8926d5 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -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()">; diff --git a/lib/Target/X86/X86Subtarget.cpp b/lib/Target/X86/X86Subtarget.cpp index 597fccb9fdb..5ee986c9a82 100644 --- a/lib/Target/X86/X86Subtarget.cpp +++ b/lib/Target/X86/X86Subtarget.cpp @@ -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); } diff --git a/lib/Target/X86/X86Subtarget.h b/lib/Target/X86/X86Subtarget.h index 93d251a6794..f39389e08c6 100644 --- a/lib/Target/X86/X86Subtarget.h +++ b/lib/Target/X86/X86Subtarget.h @@ -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 || diff --git a/test/MC/X86/address-size.s b/test/MC/X86/address-size.s index 936cd579db2..c9d04c4af3f 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 00000000000..36f3b1922f8 --- /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) +