diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Target/X86/X86Instr3DNow.td | 31 | ||||
-rw-r--r-- | lib/Target/X86/X86InstrFormats.td | 3 | ||||
-rw-r--r-- | lib/Target/X86/X86InstrInfo.h | 36 | ||||
-rw-r--r-- | lib/Target/X86/X86InstrInfo.td | 2 | ||||
-rw-r--r-- | lib/Target/X86/X86MCCodeEmitter.cpp | 9 |
5 files changed, 67 insertions, 14 deletions
diff --git a/lib/Target/X86/X86Instr3DNow.td b/lib/Target/X86/X86Instr3DNow.td index 7615f845a4..9efa2a6cd3 100644 --- a/lib/Target/X86/X86Instr3DNow.td +++ b/lib/Target/X86/X86Instr3DNow.td @@ -11,3 +11,34 @@ // floating point and also adds a few more random instructions for good measure. // //===----------------------------------------------------------------------===// + +// FIXME: We don't support any intrinsics for these instructions yet. + +class I3DNow<bits<8> o, Format F, dag outs, dag ins, string asm, + list<dag> pattern> + : I<o, F, outs, ins, asm, pattern>, TB, Requires<[Has3DNow]>, + Has3DNow0F0FOpcode { + // FIXME: The disassembler doesn't support 3DNow! yet. + let isAsmParserOnly = 1; +} + + +let Constraints = "$src1 = $dst" in { + // MMXI_binop_rm_int - Simple MMX binary operator based on intrinsic. + // When this is cleaned up, remove the FIXME from X86RecognizableInstr.cpp. + multiclass I3DNow_binop_rm<bits<8> opc, string Mnemonic> { + def rr : I3DNow<opc, MRMSrcReg, (outs VR64:$dst), + (ins VR64:$src1, VR64:$src2), + !strconcat(Mnemonic, "\t{$src2, $dst|$dst, $src2}"), []>; + def rm : I3DNow<opc, MRMSrcMem, (outs VR64:$dst), + (ins VR64:$src1, i64mem:$src2), + !strconcat(Mnemonic, "\t{$src2, $dst|$dst, $src2}"), []>; + } +} + +defm PAVGUSB : I3DNow_binop_rm<0xBF, "pavgusb">; + + + + +// TODO: Add support for the rest of the 3DNow! and "3DNowA" instructions. diff --git a/lib/Target/X86/X86InstrFormats.td b/lib/Target/X86/X86InstrFormats.td index 2e4f4cafcc..ce85e3a49d 100644 --- a/lib/Target/X86/X86InstrFormats.td +++ b/lib/Target/X86/X86InstrFormats.td @@ -109,6 +109,7 @@ class VEX_W { bit hasVEX_WPrefix = 1; } class VEX_4V : VEX { bit hasVEX_4VPrefix = 1; } class VEX_I8IMM { bit hasVEX_i8ImmReg = 1; } class VEX_L { bit hasVEX_L = 1; } +class Has3DNow0F0FOpcode { bit has3DNow0F0FOpcode = 1; } class X86Inst<bits<8> opcod, Format f, ImmType i, dag outs, dag ins, string AsmStr, Domain d = GenericDomain> @@ -142,6 +143,7 @@ class X86Inst<bits<8> opcod, Format f, ImmType i, dag outs, dag ins, bit hasVEX_i8ImmReg = 0; // Does this inst requires the last source register // to be encoded in a immediate field? bit hasVEX_L = 0; // Does this inst uses large (256-bit) registers? + bit has3DNow0F0FOpcode =0;// Wacky 3dNow! encoding? // TSFlags layout should be kept in sync with X86InstrInfo.h. let TSFlags{5-0} = FormBits; @@ -160,6 +162,7 @@ class X86Inst<bits<8> opcod, Format f, ImmType i, dag outs, dag ins, let TSFlags{34} = hasVEX_4VPrefix; let TSFlags{35} = hasVEX_i8ImmReg; let TSFlags{36} = hasVEX_L; + let TSFlags{37} = has3DNow0F0FOpcode; } class I<bits<8> o, Format f, dag outs, dag ins, string asm, diff --git a/lib/Target/X86/X86InstrInfo.h b/lib/Target/X86/X86InstrInfo.h index 2e7e063637..b58984fce6 100644 --- a/lib/Target/X86/X86InstrInfo.h +++ b/lib/Target/X86/X86InstrInfo.h @@ -449,28 +449,36 @@ namespace X86II { OpcodeMask = 0xFF << OpcodeShift, //===------------------------------------------------------------------===// - // VEX - The opcode prefix used by AVX instructions + /// VEX - The opcode prefix used by AVX instructions VEX = 1U << 0, - // VEX_W - Has a opcode specific functionality, but is used in the same - // way as REX_W is for regular SSE instructions. + /// VEX_W - Has a opcode specific functionality, but is used in the same + /// way as REX_W is for regular SSE instructions. VEX_W = 1U << 1, - // VEX_4V - Used to specify an additional AVX/SSE register. Several 2 - // address instructions in SSE are represented as 3 address ones in AVX - // and the additional register is encoded in VEX_VVVV prefix. + /// VEX_4V - Used to specify an additional AVX/SSE register. Several 2 + /// address instructions in SSE are represented as 3 address ones in AVX + /// and the additional register is encoded in VEX_VVVV prefix. VEX_4V = 1U << 2, - // VEX_I8IMM - Specifies that the last register used in a AVX instruction, - // must be encoded in the i8 immediate field. This usually happens in - // instructions with 4 operands. + /// VEX_I8IMM - Specifies that the last register used in a AVX instruction, + /// must be encoded in the i8 immediate field. This usually happens in + /// instructions with 4 operands. VEX_I8IMM = 1U << 3, - // VEX_L - Stands for a bit in the VEX opcode prefix meaning the current - // instruction uses 256-bit wide registers. This is usually auto detected if - // a VR256 register is used, but some AVX instructions also have this field - // marked when using a f256 memory references. - VEX_L = 1U << 4 + /// VEX_L - Stands for a bit in the VEX opcode prefix meaning the current + /// instruction uses 256-bit wide registers. This is usually auto detected + /// if a VR256 register is used, but some AVX instructions also have this + /// field marked when using a f256 memory references. + VEX_L = 1U << 4, + + /// Has3DNow0F0FOpcode - This flag indicates that the instruction uses the + /// wacky 0x0F 0x0F prefix for 3DNow! instructions. The manual documents + /// this as having a 0x0F prefix with a 0x0F opcode, and each instruction + /// storing a classifier in the imm8 field. To simplify our implementation, + /// we handle this by storeing the classifier in the opcode field and using + /// this flag to indicate that the encoder should do the wacky 3DNow! thing. + Has3DNow0F0FOpcode = 1U << 5 }; // getBaseOpcodeFor - This function returns the "base" X86 opcode for the diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index cfe7fed066..3835ddc7b1 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -349,6 +349,8 @@ def NoCMov : Predicate<"!Subtarget->hasCMov()">; // no AVX version of the desired intructions is present, this is better for // incremental dev (without fallbacks it's easier to spot what's missing) def HasMMX : Predicate<"Subtarget->hasMMX() && !Subtarget->hasAVX()">; +def Has3DNow : Predicate<"Subtarget->has3DNow()">; +def Has3DNowA : Predicate<"Subtarget->has3DNowA()">; def HasSSE1 : Predicate<"Subtarget->hasSSE1() && !Subtarget->hasAVX()">; def HasSSE2 : Predicate<"Subtarget->hasSSE2() && !Subtarget->hasAVX()">; def HasSSE3 : Predicate<"Subtarget->hasSSE3() && !Subtarget->hasAVX()">; diff --git a/lib/Target/X86/X86MCCodeEmitter.cpp b/lib/Target/X86/X86MCCodeEmitter.cpp index cdc8a1d431..d5cab49c0d 100644 --- a/lib/Target/X86/X86MCCodeEmitter.cpp +++ b/lib/Target/X86/X86MCCodeEmitter.cpp @@ -822,6 +822,7 @@ EncodeInstruction(const MCInst &MI, raw_ostream &OS, if ((TSFlags >> 32) & X86II::VEX_4V) HasVEX_4V = true; + // Determine where the memory operand starts, if present. int MemoryOperand = X86II::getMemoryOperandNo(TSFlags); if (MemoryOperand != -1) MemoryOperand += CurOp; @@ -831,7 +832,12 @@ EncodeInstruction(const MCInst &MI, raw_ostream &OS, else EmitVEXOpcodePrefix(TSFlags, CurByte, MemoryOperand, MI, Desc, OS); + unsigned char BaseOpcode = X86II::getBaseOpcodeFor(TSFlags); + + if ((TSFlags >> 32) & X86II::Has3DNow0F0FOpcode) + BaseOpcode = 0x0F; // Weird 3DNow! encoding. + unsigned SrcRegNum = 0; switch (TSFlags & X86II::FormMask) { case X86II::MRMInitReg: @@ -998,6 +1004,9 @@ EncodeInstruction(const MCInst &MI, raw_ostream &OS, } } + if ((TSFlags >> 32) & X86II::Has3DNow0F0FOpcode) + EmitByte(X86II::getBaseOpcodeFor(TSFlags), CurByte, OS); + #ifndef NDEBUG // FIXME: Verify. |