1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-24 03:33:20 +01:00

Implement support for the bizarre 3DNow! encoding (which is unlike anything

else in X86), and add support for pavgusb.  This is apparently the
only instruction (other than movsx) that is preventing ffmpeg from building
with clang.

If someone else is interested in banging out the rest of the 3DNow! 
instructions, it should be quite easy now.

llvm-svn: 115466
This commit is contained in:
Chris Lattner 2010-10-03 18:08:05 +00:00
parent 6284b3db58
commit 8174253484
6 changed files with 78 additions and 14 deletions

View File

@ -11,3 +11,34 @@
// floating point and also adds a few more random instructions for good measure. // 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.

View File

@ -109,6 +109,7 @@ class VEX_W { bit hasVEX_WPrefix = 1; }
class VEX_4V : VEX { bit hasVEX_4VPrefix = 1; } class VEX_4V : VEX { bit hasVEX_4VPrefix = 1; }
class VEX_I8IMM { bit hasVEX_i8ImmReg = 1; } class VEX_I8IMM { bit hasVEX_i8ImmReg = 1; }
class VEX_L { bit hasVEX_L = 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, class X86Inst<bits<8> opcod, Format f, ImmType i, dag outs, dag ins,
string AsmStr, Domain d = GenericDomain> 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 bit hasVEX_i8ImmReg = 0; // Does this inst requires the last source register
// to be encoded in a immediate field? // to be encoded in a immediate field?
bit hasVEX_L = 0; // Does this inst uses large (256-bit) registers? 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. // TSFlags layout should be kept in sync with X86InstrInfo.h.
let TSFlags{5-0} = FormBits; 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{34} = hasVEX_4VPrefix;
let TSFlags{35} = hasVEX_i8ImmReg; let TSFlags{35} = hasVEX_i8ImmReg;
let TSFlags{36} = hasVEX_L; let TSFlags{36} = hasVEX_L;
let TSFlags{37} = has3DNow0F0FOpcode;
} }
class I<bits<8> o, Format f, dag outs, dag ins, string asm, class I<bits<8> o, Format f, dag outs, dag ins, string asm,

View File

@ -449,28 +449,36 @@ namespace X86II {
OpcodeMask = 0xFF << OpcodeShift, OpcodeMask = 0xFF << OpcodeShift,
//===------------------------------------------------------------------===// //===------------------------------------------------------------------===//
// VEX - The opcode prefix used by AVX instructions /// VEX - The opcode prefix used by AVX instructions
VEX = 1U << 0, VEX = 1U << 0,
// VEX_W - Has a opcode specific functionality, but is used in the same /// VEX_W - Has a opcode specific functionality, but is used in the same
// way as REX_W is for regular SSE instructions. /// way as REX_W is for regular SSE instructions.
VEX_W = 1U << 1, VEX_W = 1U << 1,
// VEX_4V - Used to specify an additional AVX/SSE register. Several 2 /// VEX_4V - Used to specify an additional AVX/SSE register. Several 2
// address instructions in SSE are represented as 3 address ones in AVX /// address instructions in SSE are represented as 3 address ones in AVX
// and the additional register is encoded in VEX_VVVV prefix. /// and the additional register is encoded in VEX_VVVV prefix.
VEX_4V = 1U << 2, VEX_4V = 1U << 2,
// VEX_I8IMM - Specifies that the last register used in a AVX instruction, /// VEX_I8IMM - Specifies that the last register used in a AVX instruction,
// must be encoded in the i8 immediate field. This usually happens in /// must be encoded in the i8 immediate field. This usually happens in
// instructions with 4 operands. /// instructions with 4 operands.
VEX_I8IMM = 1U << 3, VEX_I8IMM = 1U << 3,
// VEX_L - Stands for a bit in the VEX opcode prefix meaning the current /// 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 /// instruction uses 256-bit wide registers. This is usually auto detected
// a VR256 register is used, but some AVX instructions also have this field /// if a VR256 register is used, but some AVX instructions also have this
// marked when using a f256 memory references. /// field marked when using a f256 memory references.
VEX_L = 1U << 4 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 // getBaseOpcodeFor - This function returns the "base" X86 opcode for the

View File

@ -349,6 +349,8 @@ def NoCMov : Predicate<"!Subtarget->hasCMov()">;
// no AVX version of the desired intructions is present, this is better for // 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) // incremental dev (without fallbacks it's easier to spot what's missing)
def HasMMX : Predicate<"Subtarget->hasMMX() && !Subtarget->hasAVX()">; 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 HasSSE1 : Predicate<"Subtarget->hasSSE1() && !Subtarget->hasAVX()">;
def HasSSE2 : Predicate<"Subtarget->hasSSE2() && !Subtarget->hasAVX()">; def HasSSE2 : Predicate<"Subtarget->hasSSE2() && !Subtarget->hasAVX()">;
def HasSSE3 : Predicate<"Subtarget->hasSSE3() && !Subtarget->hasAVX()">; def HasSSE3 : Predicate<"Subtarget->hasSSE3() && !Subtarget->hasAVX()">;

View File

@ -822,6 +822,7 @@ EncodeInstruction(const MCInst &MI, raw_ostream &OS,
if ((TSFlags >> 32) & X86II::VEX_4V) if ((TSFlags >> 32) & X86II::VEX_4V)
HasVEX_4V = true; HasVEX_4V = true;
// Determine where the memory operand starts, if present. // Determine where the memory operand starts, if present.
int MemoryOperand = X86II::getMemoryOperandNo(TSFlags); int MemoryOperand = X86II::getMemoryOperandNo(TSFlags);
if (MemoryOperand != -1) MemoryOperand += CurOp; if (MemoryOperand != -1) MemoryOperand += CurOp;
@ -831,7 +832,12 @@ EncodeInstruction(const MCInst &MI, raw_ostream &OS,
else else
EmitVEXOpcodePrefix(TSFlags, CurByte, MemoryOperand, MI, Desc, OS); EmitVEXOpcodePrefix(TSFlags, CurByte, MemoryOperand, MI, Desc, OS);
unsigned char BaseOpcode = X86II::getBaseOpcodeFor(TSFlags); unsigned char BaseOpcode = X86II::getBaseOpcodeFor(TSFlags);
if ((TSFlags >> 32) & X86II::Has3DNow0F0FOpcode)
BaseOpcode = 0x0F; // Weird 3DNow! encoding.
unsigned SrcRegNum = 0; unsigned SrcRegNum = 0;
switch (TSFlags & X86II::FormMask) { switch (TSFlags & X86II::FormMask) {
case X86II::MRMInitReg: 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 #ifndef NDEBUG
// FIXME: Verify. // FIXME: Verify.

11
test/MC/X86/3DNow.s Normal file
View File

@ -0,0 +1,11 @@
// RUN: llvm-mc -triple i386-unknown-unknown --show-encoding %s | FileCheck %s
// PR8283
// CHECK: pavgusb %mm2, %mm1 # encoding: [0x0f,0x0f,0xca,0xbf]
pavgusb %mm2, %mm1
// CHECK: pavgusb 9(%esi,%edx), %mm3 # encoding: [0x0f,0x0f,0x5c,0x16,0x09,0
pavgusb 9(%esi,%edx), %mm3