Newer
Older
//====- X86InstrSSE.td - Describe the X86 Instruction Set -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Evan Cheng and is distributed under the University
// of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file describes the X86 SSE instruction set, defining the instructions,
// and properties of the instructions which are needed for code generation,
// machine code emission, and analysis.
//
//===----------------------------------------------------------------------===//
Chris Lattner
committed
//===----------------------------------------------------------------------===//
// SSE specific DAG Nodes.
//===----------------------------------------------------------------------===//
def SDTX86FPShiftOp : SDTypeProfile<1, 2, [ SDTCisSameAs<0, 1>,
SDTCisFP<0>, SDTCisInt<2> ]>;
def X86loadp : SDNode<"X86ISD::LOAD_PACK", SDTLoad, [SDNPHasChain]>;
def X86loadu : SDNode<"X86ISD::LOAD_UA", SDTLoad, [SDNPHasChain]>;
def X86fmin : SDNode<"X86ISD::FMIN", SDTFPBinOp>;
def X86fmax : SDNode<"X86ISD::FMAX", SDTFPBinOp>;
def X86fand : SDNode<"X86ISD::FAND", SDTFPBinOp,
def X86for : SDNode<"X86ISD::FOR", SDTFPBinOp,
[SDNPCommutative, SDNPAssociative]>;
def X86fxor : SDNode<"X86ISD::FXOR", SDTFPBinOp,
def X86frsqrt : SDNode<"X86ISD::FRSQRT", SDTFPUnaryOp>;
def X86frcp : SDNode<"X86ISD::FRCP", SDTFPUnaryOp>;
def X86fsrl : SDNode<"X86ISD::FSRL", SDTX86FPShiftOp>;
def X86comi : SDNode<"X86ISD::COMI", SDTX86CmpTest,
[SDNPHasChain, SDNPOutFlag]>;
def X86ucomi : SDNode<"X86ISD::UCOMI", SDTX86CmpTest,
[SDNPHasChain, SDNPOutFlag]>;
def X86s2vec : SDNode<"X86ISD::S2VEC", SDTypeProfile<1, 1, []>, []>;
def X86pextrw : SDNode<"X86ISD::PEXTRW", SDTypeProfile<1, 2, []>, []>;
def X86pinsrw : SDNode<"X86ISD::PINSRW", SDTypeProfile<1, 3, []>, []>;
//===----------------------------------------------------------------------===//
// SSE 'Special' Instructions
//===----------------------------------------------------------------------===//
def IMPLICIT_DEF_VR128 : I<0, Pseudo, (outs VR128:$dst), (ins),
"#IMPLICIT_DEF $dst",
[(set VR128:$dst, (v4f32 (undef)))]>,
Requires<[HasSSE1]>;
def IMPLICIT_DEF_FR32 : I<0, Pseudo, (outs FR32:$dst), (ins),
"#IMPLICIT_DEF $dst",
[(set FR32:$dst, (undef))]>, Requires<[HasSSE2]>;
def IMPLICIT_DEF_FR64 : I<0, Pseudo, (outs FR64:$dst), (ins),
"#IMPLICIT_DEF $dst",
[(set FR64:$dst, (undef))]>, Requires<[HasSSE2]>;
Chris Lattner
committed
//===----------------------------------------------------------------------===//
// SSE Complex Patterns
//===----------------------------------------------------------------------===//
// These are 'extloads' from a scalar to the low element of a vector, zeroing
// the top elements. These are used for the SSE 'ss' and 'sd' instruction
// forms.
def sse_load_f32 : ComplexPattern<v4f32, 4, "SelectScalarSSELoad", [],
[SDNPHasChain]>;
def sse_load_f64 : ComplexPattern<v2f64, 4, "SelectScalarSSELoad", [],
[SDNPHasChain]>;
Chris Lattner
committed
def ssmem : Operand<v4f32> {
let PrintMethod = "printf32mem";
let MIOperandInfo = (ops ptr_rc, i8imm, ptr_rc, i32imm);
}
def sdmem : Operand<v2f64> {
let PrintMethod = "printf64mem";
let MIOperandInfo = (ops ptr_rc, i8imm, ptr_rc, i32imm);
}
//===----------------------------------------------------------------------===//
// SSE pattern fragments
//===----------------------------------------------------------------------===//
def X86loadpf32 : PatFrag<(ops node:$ptr), (f32 (X86loadp node:$ptr))>;
def X86loadpf64 : PatFrag<(ops node:$ptr), (f64 (X86loadp node:$ptr))>;
def loadv4f32 : PatFrag<(ops node:$ptr), (v4f32 (load node:$ptr))>;
def loadv2f64 : PatFrag<(ops node:$ptr), (v2f64 (load node:$ptr))>;
def loadv4i32 : PatFrag<(ops node:$ptr), (v4i32 (load node:$ptr))>;
def loadv2i64 : PatFrag<(ops node:$ptr), (v2i64 (load node:$ptr))>;
Dan Gohman
committed
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Like 'store', but always requires natural alignment.
def alignedstore : PatFrag<(ops node:$val, node:$ptr),
(st node:$val, node:$ptr), [{
if (StoreSDNode *ST = dyn_cast<StoreSDNode>(N))
return !ST->isTruncatingStore() &&
ST->getAddressingMode() == ISD::UNINDEXED &&
ST->getAlignment() * 8 >= MVT::getSizeInBits(ST->getStoredVT());
return false;
}]>;
// Like 'load', but always requires natural alignment.
def alignedload : PatFrag<(ops node:$ptr), (ld node:$ptr), [{
if (LoadSDNode *LD = dyn_cast<LoadSDNode>(N))
return LD->getExtensionType() == ISD::NON_EXTLOAD &&
LD->getAddressingMode() == ISD::UNINDEXED &&
LD->getAlignment() * 8 >= MVT::getSizeInBits(LD->getLoadedVT());
return false;
}]>;
def alignedloadv4f32 : PatFrag<(ops node:$ptr), (v4f32 (alignedload node:$ptr))>;
def alignedloadv2f64 : PatFrag<(ops node:$ptr), (v2f64 (alignedload node:$ptr))>;
def alignedloadv4i32 : PatFrag<(ops node:$ptr), (v4i32 (alignedload node:$ptr))>;
def alignedloadv2i64 : PatFrag<(ops node:$ptr), (v2i64 (alignedload node:$ptr))>;
// Like 'load', but uses special alignment checks suitable for use in
// memory operands in most SSE instructions, which are required to
// be naturally aligned on some targets but not on others.
// FIXME: Actually implement support for targets that don't require the
// alignment. This probably wants a subtarget predicate.
def memop : PatFrag<(ops node:$ptr), (ld node:$ptr), [{
if (LoadSDNode *LD = dyn_cast<LoadSDNode>(N))
return LD->getExtensionType() == ISD::NON_EXTLOAD &&
LD->getAddressingMode() == ISD::UNINDEXED &&
LD->getAlignment() * 8 >= MVT::getSizeInBits(LD->getLoadedVT());
return false;
}]>;
def memopv4f32 : PatFrag<(ops node:$ptr), (v4f32 (memop node:$ptr))>;
def memopv2f64 : PatFrag<(ops node:$ptr), (v2f64 (memop node:$ptr))>;
def memopv4i32 : PatFrag<(ops node:$ptr), (v4i32 (memop node:$ptr))>;
def memopv2i64 : PatFrag<(ops node:$ptr), (v2i64 (memop node:$ptr))>;
def bc_v4f32 : PatFrag<(ops node:$in), (v4f32 (bitconvert node:$in))>;
def bc_v2f64 : PatFrag<(ops node:$in), (v2f64 (bitconvert node:$in))>;
def bc_v16i8 : PatFrag<(ops node:$in), (v16i8 (bitconvert node:$in))>;
def bc_v8i16 : PatFrag<(ops node:$in), (v8i16 (bitconvert node:$in))>;
def bc_v4i32 : PatFrag<(ops node:$in), (v4i32 (bitconvert node:$in))>;
def bc_v2i64 : PatFrag<(ops node:$in), (v2i64 (bitconvert node:$in))>;
def fp32imm0 : PatLeaf<(f32 fpimm), [{
return N->isExactlyValue(+0.0);
}]>;
def PSxLDQ_imm : SDNodeXForm<imm, [{
// Transformation function: imm >> 3
return getI32Imm(N->getValue() >> 3);
}]>;
// SHUFFLE_get_shuf_imm xform function: convert vector_shuffle mask to PSHUF*,
// SHUFP* etc. imm.
def SHUFFLE_get_shuf_imm : SDNodeXForm<build_vector, [{
return getI8Imm(X86::getShuffleSHUFImmediate(N));
// SHUFFLE_get_pshufhw_imm xform function: convert vector_shuffle mask to
// PSHUFHW imm.
def SHUFFLE_get_pshufhw_imm : SDNodeXForm<build_vector, [{
return getI8Imm(X86::getShufflePSHUFHWImmediate(N));
}]>;
// SHUFFLE_get_pshuflw_imm xform function: convert vector_shuffle mask to
// PSHUFLW imm.
def SHUFFLE_get_pshuflw_imm : SDNodeXForm<build_vector, [{
return getI8Imm(X86::getShufflePSHUFLWImmediate(N));
}]>;
def SSE_splat_mask : PatLeaf<(build_vector), [{
return X86::isSplatMask(N);
}], SHUFFLE_get_shuf_imm>;
Evan Cheng
committed
def SSE_splat_lo_mask : PatLeaf<(build_vector), [{
return X86::isSplatLoMask(N);
def MOVHLPS_shuffle_mask : PatLeaf<(build_vector), [{
return X86::isMOVHLPSMask(N);
def MOVHLPS_v_undef_shuffle_mask : PatLeaf<(build_vector), [{
return X86::isMOVHLPS_v_undef_Mask(N);
}]>;
def MOVHP_shuffle_mask : PatLeaf<(build_vector), [{
return X86::isMOVHPMask(N);
}]>;
def MOVLP_shuffle_mask : PatLeaf<(build_vector), [{
return X86::isMOVLPMask(N);
}]>;
def MOVL_shuffle_mask : PatLeaf<(build_vector), [{
return X86::isMOVLMask(N);
def MOVSHDUP_shuffle_mask : PatLeaf<(build_vector), [{
return X86::isMOVSHDUPMask(N);
}]>;
def MOVSLDUP_shuffle_mask : PatLeaf<(build_vector), [{
return X86::isMOVSLDUPMask(N);
}]>;
def UNPCKL_shuffle_mask : PatLeaf<(build_vector), [{
return X86::isUNPCKLMask(N);
}]>;
def UNPCKH_shuffle_mask : PatLeaf<(build_vector), [{
return X86::isUNPCKHMask(N);
}]>;
def UNPCKL_v_undef_shuffle_mask : PatLeaf<(build_vector), [{
return X86::isUNPCKL_v_undef_Mask(N);
}]>;
def UNPCKH_v_undef_shuffle_mask : PatLeaf<(build_vector), [{
return X86::isUNPCKH_v_undef_Mask(N);
}]>;
def PSHUFD_shuffle_mask : PatLeaf<(build_vector), [{
}], SHUFFLE_get_shuf_imm>;
def PSHUFHW_shuffle_mask : PatLeaf<(build_vector), [{
return X86::isPSHUFHWMask(N);
}], SHUFFLE_get_pshufhw_imm>;
def PSHUFLW_shuffle_mask : PatLeaf<(build_vector), [{
return X86::isPSHUFLWMask(N);
}], SHUFFLE_get_pshuflw_imm>;
def SHUFP_unary_shuffle_mask : PatLeaf<(build_vector), [{
return X86::isPSHUFDMask(N);
}], SHUFFLE_get_shuf_imm>;
def SHUFP_shuffle_mask : PatLeaf<(build_vector), [{
return X86::isSHUFPMask(N);
}], SHUFFLE_get_shuf_imm>;
def PSHUFD_binary_shuffle_mask : PatLeaf<(build_vector), [{
return X86::isSHUFPMask(N);
//===----------------------------------------------------------------------===//
// SSE scalar FP Instructions
//===----------------------------------------------------------------------===//
// CMOV* - Used to implement the SSE SELECT DAG operation. Expanded by the
// scheduler into a branch sequence.
let usesCustomDAGSchedInserter = 1 in { // Expanded by the scheduler.
def CMOV_FR32 : I<0, Pseudo,
(outs FR32:$dst), (ins FR32:$t, FR32:$f, i8imm:$cond),
"#CMOV_FR32 PSEUDO!",
[(set FR32:$dst, (X86cmov FR32:$t, FR32:$f, imm:$cond))]>;
def CMOV_FR64 : I<0, Pseudo,
(outs FR64:$dst), (ins FR64:$t, FR64:$f, i8imm:$cond),
"#CMOV_FR64 PSEUDO!",
[(set FR64:$dst, (X86cmov FR64:$t, FR64:$f, imm:$cond))]>;
(outs VR128:$dst), (ins VR128:$t, VR128:$f, i8imm:$cond),
"#CMOV_V4F32 PSEUDO!",
[(set VR128:$dst,
(v4f32 (X86cmov VR128:$t, VR128:$f, imm:$cond)))]>;
def CMOV_V2F64 : I<0, Pseudo,
(outs VR128:$dst), (ins VR128:$t, VR128:$f, i8imm:$cond),
"#CMOV_V2F64 PSEUDO!",
[(set VR128:$dst,
(v2f64 (X86cmov VR128:$t, VR128:$f, imm:$cond)))]>;
def CMOV_V2I64 : I<0, Pseudo,
(outs VR128:$dst), (ins VR128:$t, VR128:$f, i8imm:$cond),
"#CMOV_V2I64 PSEUDO!",
[(set VR128:$dst,
(v2i64 (X86cmov VR128:$t, VR128:$f, imm:$cond)))]>;
}
//===----------------------------------------------------------------------===//
// SSE1 Instructions
//===----------------------------------------------------------------------===//
// SSE1 Instruction Templates:
//
// SSI - SSE1 instructions with XS prefix.
// PSI - SSE1 instructions with TB prefix.
// PSIi8 - SSE1 instructions with ImmT == Imm8 and TB prefix.
class SSI<bits<8> o, Format F, dag outs, dag ins, string asm, list<dag> pattern>
: I<o, F, outs, ins, asm, pattern>, XS, Requires<[HasSSE1]>;
class PSI<bits<8> o, Format F, dag outs, dag ins, string asm, list<dag> pattern>
: I<o, F, outs, ins, asm, pattern>, TB, Requires<[HasSSE1]>;
class PSIi8<bits<8> o, Format F, dag outs, dag ins, string asm,
list<dag> pattern>
: Ii8<o, F, outs, ins, asm, pattern>, TB, Requires<[HasSSE1]>;
// Move Instructions
def MOVSSrr : SSI<0x10, MRMSrcReg, (outs FR32:$dst), (ins FR32:$src),
"movss {$src, $dst|$dst, $src}", []>;
def MOVSSrm : SSI<0x10, MRMSrcMem, (outs FR32:$dst), (ins f32mem:$src),
"movss {$src, $dst|$dst, $src}",
[(set FR32:$dst, (loadf32 addr:$src))]>;
def MOVSSmr : SSI<0x11, MRMDestMem, (outs), (ins f32mem:$dst, FR32:$src),
"movss {$src, $dst|$dst, $src}",
[(store FR32:$src, addr:$dst)]>;
// Conversion instructions
def CVTTSS2SIrr : SSI<0x2C, MRMSrcReg, (outs GR32:$dst), (ins FR32:$src),
"cvttss2si {$src, $dst|$dst, $src}",
[(set GR32:$dst, (fp_to_sint FR32:$src))]>;
def CVTTSS2SIrm : SSI<0x2C, MRMSrcMem, (outs GR32:$dst), (ins f32mem:$src),
"cvttss2si {$src, $dst|$dst, $src}",
[(set GR32:$dst, (fp_to_sint (loadf32 addr:$src)))]>;
def CVTSI2SSrr : SSI<0x2A, MRMSrcReg, (outs FR32:$dst), (ins GR32:$src),
"cvtsi2ss {$src, $dst|$dst, $src}",
[(set FR32:$dst, (sint_to_fp GR32:$src))]>;
def CVTSI2SSrm : SSI<0x2A, MRMSrcMem, (outs FR32:$dst), (ins i32mem:$src),
"cvtsi2ss {$src, $dst|$dst, $src}",
[(set FR32:$dst, (sint_to_fp (loadi32 addr:$src)))]>;
// Match intrinsics which expect XMM operand(s).
def Int_CVTSS2SIrr : SSI<0x2D, MRMSrcReg, (outs GR32:$dst), (ins VR128:$src),
"cvtss2si {$src, $dst|$dst, $src}",
[(set GR32:$dst, (int_x86_sse_cvtss2si VR128:$src))]>;
def Int_CVTSS2SIrm : SSI<0x2D, MRMSrcMem, (outs GR32:$dst), (ins f32mem:$src),
"cvtss2si {$src, $dst|$dst, $src}",
[(set GR32:$dst, (int_x86_sse_cvtss2si
(load addr:$src)))]>;
// Aliases for intrinsics
def Int_CVTTSS2SIrr : SSI<0x2C, MRMSrcReg, (outs GR32:$dst), (ins VR128:$src),
"cvttss2si {$src, $dst|$dst, $src}",
[(set GR32:$dst,
(int_x86_sse_cvttss2si VR128:$src))]>;
def Int_CVTTSS2SIrm : SSI<0x2C, MRMSrcMem, (outs GR32:$dst), (ins f32mem:$src),
"cvttss2si {$src, $dst|$dst, $src}",
[(set GR32:$dst,
(int_x86_sse_cvttss2si(load addr:$src)))]>;
let isTwoAddress = 1 in {
def Int_CVTSI2SSrr : SSI<0x2A, MRMSrcReg,
(outs VR128:$dst), (ins VR128:$src1, GR32:$src2),
"cvtsi2ss {$src2, $dst|$dst, $src2}",
[(set VR128:$dst, (int_x86_sse_cvtsi2ss VR128:$src1,
GR32:$src2))]>;
def Int_CVTSI2SSrm : SSI<0x2A, MRMSrcMem,
(outs VR128:$dst), (ins VR128:$src1, i32mem:$src2),
"cvtsi2ss {$src2, $dst|$dst, $src2}",
[(set VR128:$dst, (int_x86_sse_cvtsi2ss VR128:$src1,
(loadi32 addr:$src2)))]>;
}
// Comparison instructions
let isTwoAddress = 1 in {
def CMPSSrr : SSI<0xC2, MRMSrcReg,
(outs FR32:$dst), (ins FR32:$src1, FR32:$src, SSECC:$cc),
"cmp${cc}ss {$src, $dst|$dst, $src}", []>;
def CMPSSrm : SSI<0xC2, MRMSrcMem,
(outs FR32:$dst), (ins FR32:$src1, f32mem:$src, SSECC:$cc),
"cmp${cc}ss {$src, $dst|$dst, $src}", []>;
}
def UCOMISSrr: PSI<0x2E, MRMSrcReg, (outs), (ins FR32:$src1, FR32:$src2),
"ucomiss {$src2, $src1|$src1, $src2}",
[(X86cmp FR32:$src1, FR32:$src2)]>;
def UCOMISSrm: PSI<0x2E, MRMSrcMem, (outs), (ins FR32:$src1, f32mem:$src2),
"ucomiss {$src2, $src1|$src1, $src2}",
[(X86cmp FR32:$src1, (loadf32 addr:$src2))]>;
// Aliases to match intrinsics which expect XMM operand(s).
let isTwoAddress = 1 in {
def Int_CMPSSrr : SSI<0xC2, MRMSrcReg,
(outs VR128:$dst), (ins VR128:$src1, VR128:$src, SSECC:$cc),
"cmp${cc}ss {$src, $dst|$dst, $src}",
[(set VR128:$dst, (int_x86_sse_cmp_ss VR128:$src1,
VR128:$src, imm:$cc))]>;
def Int_CMPSSrm : SSI<0xC2, MRMSrcMem,
(outs VR128:$dst), (ins VR128:$src1, f32mem:$src, SSECC:$cc),
"cmp${cc}ss {$src, $dst|$dst, $src}",
[(set VR128:$dst, (int_x86_sse_cmp_ss VR128:$src1,
(load addr:$src), imm:$cc))]>;
}
def Int_UCOMISSrr: PSI<0x2E, MRMSrcReg, (outs), (ins VR128:$src1, VR128:$src2),
"ucomiss {$src2, $src1|$src1, $src2}",
[(X86ucomi (v4f32 VR128:$src1), VR128:$src2)]>;
def Int_UCOMISSrm: PSI<0x2E, MRMSrcMem, (outs), (ins VR128:$src1, f128mem:$src2),
"ucomiss {$src2, $src1|$src1, $src2}",
[(X86ucomi (v4f32 VR128:$src1), (load addr:$src2))]>;
def Int_COMISSrr: PSI<0x2F, MRMSrcReg, (outs), (ins VR128:$src1, VR128:$src2),
"comiss {$src2, $src1|$src1, $src2}",
[(X86comi (v4f32 VR128:$src1), VR128:$src2)]>;
def Int_COMISSrm: PSI<0x2F, MRMSrcMem, (outs), (ins VR128:$src1, f128mem:$src2),
"comiss {$src2, $src1|$src1, $src2}",
[(X86comi (v4f32 VR128:$src1), (load addr:$src2))]>;
// Aliases of packed SSE1 instructions for scalar use. These all have names that
// start with 'Fs'.
// Alias instructions that map fld0 to pxor for sse.
def FsFLD0SS : I<0xEF, MRMInitReg, (outs FR32:$dst), (ins),
"pxor $dst, $dst", [(set FR32:$dst, fp32imm0)]>,
Requires<[HasSSE1]>, TB, OpSize;
// Alias instruction to do FR32 reg-to-reg copy using movaps. Upper bits are
// disregarded.
def FsMOVAPSrr : PSI<0x28, MRMSrcReg, (outs FR32:$dst), (ins FR32:$src),
"movaps {$src, $dst|$dst, $src}", []>;
// Alias instruction to load FR32 from f128mem using movaps. Upper bits are
// disregarded.
def FsMOVAPSrm : PSI<0x28, MRMSrcMem, (outs FR32:$dst), (ins f128mem:$src),
"movaps {$src, $dst|$dst, $src}",
[(set FR32:$dst, (X86loadpf32 addr:$src))]>;
// Alias bitwise logical operations using SSE logical ops on packed FP values.
let isTwoAddress = 1 in {
let isCommutable = 1 in {
def FsANDPSrr : PSI<0x54, MRMSrcReg, (outs FR32:$dst), (ins FR32:$src1, FR32:$src2),
"andps {$src2, $dst|$dst, $src2}",
[(set FR32:$dst, (X86fand FR32:$src1, FR32:$src2))]>;
def FsORPSrr : PSI<0x56, MRMSrcReg, (outs FR32:$dst), (ins FR32:$src1, FR32:$src2),
"orps {$src2, $dst|$dst, $src2}",
[(set FR32:$dst, (X86for FR32:$src1, FR32:$src2))]>;
def FsXORPSrr : PSI<0x57, MRMSrcReg, (outs FR32:$dst), (ins FR32:$src1, FR32:$src2),
"xorps {$src2, $dst|$dst, $src2}",
[(set FR32:$dst, (X86fxor FR32:$src1, FR32:$src2))]>;
}
def FsANDPSrm : PSI<0x54, MRMSrcMem, (outs FR32:$dst), (ins FR32:$src1, f128mem:$src2),
"andps {$src2, $dst|$dst, $src2}",
[(set FR32:$dst, (X86fand FR32:$src1,
(X86loadpf32 addr:$src2)))]>;
def FsORPSrm : PSI<0x56, MRMSrcMem, (outs FR32:$dst), (ins FR32:$src1, f128mem:$src2),
"orps {$src2, $dst|$dst, $src2}",
[(set FR32:$dst, (X86for FR32:$src1,
(X86loadpf32 addr:$src2)))]>;
def FsXORPSrm : PSI<0x57, MRMSrcMem, (outs FR32:$dst), (ins FR32:$src1, f128mem:$src2),
"xorps {$src2, $dst|$dst, $src2}",
[(set FR32:$dst, (X86fxor FR32:$src1,
(X86loadpf32 addr:$src2)))]>;
def FsANDNPSrr : PSI<0x55, MRMSrcReg,
(outs FR32:$dst), (ins FR32:$src1, FR32:$src2),
"andnps {$src2, $dst|$dst, $src2}", []>;
def FsANDNPSrm : PSI<0x55, MRMSrcMem,
(outs FR32:$dst), (ins FR32:$src1, f128mem:$src2),
"andnps {$src2, $dst|$dst, $src2}", []>;
}
/// basic_sse1_fp_binop_rm - SSE1 binops come in both scalar and vector forms.
///
/// In addition, we also have a special variant of the scalar form here to
/// represent the associated intrinsic operation. This form is unlike the
/// plain scalar form, in that it takes an entire vector (instead of a scalar)
/// and leaves the top elements undefined.
Chris Lattner
committed
///
/// These three forms can each be reg+reg or reg+mem, so there are a total of
/// six "instructions".
Chris Lattner
committed
///
let isTwoAddress = 1 in {
multiclass basic_sse1_fp_binop_rm<bits<8> opc, string OpcodeStr,
SDNode OpNode, Intrinsic F32Int,
bit Commutable = 0> {
Chris Lattner
committed
// Scalar operation, reg+reg.
def SSrr : SSI<opc, MRMSrcReg, (outs FR32:$dst), (ins FR32:$src1, FR32:$src2),
!strconcat(OpcodeStr, "ss {$src2, $dst|$dst, $src2}"),
[(set FR32:$dst, (OpNode FR32:$src1, FR32:$src2))]> {
let isCommutable = Commutable;
}
Chris Lattner
committed
// Scalar operation, reg+mem.
def SSrm : SSI<opc, MRMSrcMem, (outs FR32:$dst), (ins FR32:$src1, f32mem:$src2),
!strconcat(OpcodeStr, "ss {$src2, $dst|$dst, $src2}"),
Chris Lattner
committed
[(set FR32:$dst, (OpNode FR32:$src1, (load addr:$src2)))]>;
Chris Lattner
committed
// Vector operation, reg+reg.
def PSrr : PSI<opc, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src1, VR128:$src2),
!strconcat(OpcodeStr, "ps {$src2, $dst|$dst, $src2}"),
[(set VR128:$dst, (v4f32 (OpNode VR128:$src1, VR128:$src2)))]> {
let isCommutable = Commutable;
}
// Vector operation, reg+mem.
def PSrm : PSI<opc, MRMSrcMem, (outs VR128:$dst), (ins VR128:$src1, f128mem:$src2),
!strconcat(OpcodeStr, "ps {$src2, $dst|$dst, $src2}"),
Dan Gohman
committed
[(set VR128:$dst, (OpNode VR128:$src1, (memopv4f32 addr:$src2)))]>;
// Intrinsic operation, reg+reg.
def SSrr_Int : SSI<opc, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src1, VR128:$src2),
!strconcat(OpcodeStr, "ss {$src2, $dst|$dst, $src2}"),
Chris Lattner
committed
[(set VR128:$dst, (F32Int VR128:$src1, VR128:$src2))]> {
let isCommutable = Commutable;
}
// Intrinsic operation, reg+mem.
def SSrm_Int : SSI<opc, MRMSrcMem, (outs VR128:$dst), (ins VR128:$src1, ssmem:$src2),
!strconcat(OpcodeStr, "ss {$src2, $dst|$dst, $src2}"),
Chris Lattner
committed
[(set VR128:$dst, (F32Int VR128:$src1,
Chris Lattner
committed
sse_load_f32:$src2))]>;
// Arithmetic instructions
defm ADD : basic_sse1_fp_binop_rm<0x58, "add", fadd, int_x86_sse_add_ss, 1>;
defm MUL : basic_sse1_fp_binop_rm<0x59, "mul", fmul, int_x86_sse_mul_ss, 1>;
defm SUB : basic_sse1_fp_binop_rm<0x5C, "sub", fsub, int_x86_sse_sub_ss>;
defm DIV : basic_sse1_fp_binop_rm<0x5E, "div", fdiv, int_x86_sse_div_ss>;
/// sse1_fp_binop_rm - Other SSE1 binops
///
/// This multiclass is like basic_sse1_fp_binop_rm, with the addition of
/// instructions for a full-vector intrinsic form. Operations that map
/// onto C operators don't use this form since they just use the plain
/// vector form instead of having a separate vector intrinsic form.
///
/// This provides a total of eight "instructions".
///
let isTwoAddress = 1 in {
multiclass sse1_fp_binop_rm<bits<8> opc, string OpcodeStr,
SDNode OpNode,
Intrinsic F32Int,
Intrinsic V4F32Int,
bit Commutable = 0> {
// Scalar operation, reg+reg.
def SSrr : SSI<opc, MRMSrcReg, (outs FR32:$dst), (ins FR32:$src1, FR32:$src2),
!strconcat(OpcodeStr, "ss {$src2, $dst|$dst, $src2}"),
[(set FR32:$dst, (OpNode FR32:$src1, FR32:$src2))]> {
let isCommutable = Commutable;
}
// Scalar operation, reg+mem.
def SSrm : SSI<opc, MRMSrcMem, (outs FR32:$dst), (ins FR32:$src1, f32mem:$src2),
!strconcat(OpcodeStr, "ss {$src2, $dst|$dst, $src2}"),
[(set FR32:$dst, (OpNode FR32:$src1, (load addr:$src2)))]>;
// Vector operation, reg+reg.
def PSrr : PSI<opc, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src1, VR128:$src2),
!strconcat(OpcodeStr, "ps {$src2, $dst|$dst, $src2}"),
[(set VR128:$dst, (v4f32 (OpNode VR128:$src1, VR128:$src2)))]> {
let isCommutable = Commutable;
}
// Vector operation, reg+mem.
def PSrm : PSI<opc, MRMSrcMem, (outs VR128:$dst), (ins VR128:$src1, f128mem:$src2),
!strconcat(OpcodeStr, "ps {$src2, $dst|$dst, $src2}"),
Dan Gohman
committed
[(set VR128:$dst, (OpNode VR128:$src1, (memopv4f32 addr:$src2)))]>;
// Intrinsic operation, reg+reg.
def SSrr_Int : SSI<opc, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src1, VR128:$src2),
!strconcat(OpcodeStr, "ss {$src2, $dst|$dst, $src2}"),
[(set VR128:$dst, (F32Int VR128:$src1, VR128:$src2))]> {
let isCommutable = Commutable;
}
// Intrinsic operation, reg+mem.
def SSrm_Int : SSI<opc, MRMSrcMem, (outs VR128:$dst), (ins VR128:$src1, ssmem:$src2),
!strconcat(OpcodeStr, "ss {$src2, $dst|$dst, $src2}"),
[(set VR128:$dst, (F32Int VR128:$src1,
sse_load_f32:$src2))]>;
// Vector intrinsic operation, reg+reg.
def PSrr_Int : PSI<opc, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src1, VR128:$src2),
!strconcat(OpcodeStr, "ps {$src2, $dst|$dst, $src2}"),
[(set VR128:$dst, (V4F32Int VR128:$src1, VR128:$src2))]> {
let isCommutable = Commutable;
}
// Vector intrinsic operation, reg+mem.
def PSrm_Int : PSI<opc, MRMSrcMem, (outs VR128:$dst), (ins VR128:$src1, f32mem:$src2),
!strconcat(OpcodeStr, "ps {$src2, $dst|$dst, $src2}"),
[(set VR128:$dst, (V4F32Int VR128:$src1, (load addr:$src2)))]>;
}
}
defm MAX : sse1_fp_binop_rm<0x5F, "max", X86fmax,
int_x86_sse_max_ss, int_x86_sse_max_ps>;
defm MIN : sse1_fp_binop_rm<0x5D, "min", X86fmin,
int_x86_sse_min_ss, int_x86_sse_min_ps>;
//===----------------------------------------------------------------------===//
// SSE packed FP Instructions
// Move Instructions
def MOVAPSrr : PSI<0x28, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src),
"movaps {$src, $dst|$dst, $src}", []>;
def MOVAPSrm : PSI<0x28, MRMSrcMem, (outs VR128:$dst), (ins f128mem:$src),
"movaps {$src, $dst|$dst, $src}",
Dan Gohman
committed
[(set VR128:$dst, (alignedloadv4f32 addr:$src))]>;
def MOVAPSmr : PSI<0x29, MRMDestMem, (outs), (ins f128mem:$dst, VR128:$src),
"movaps {$src, $dst|$dst, $src}",
Dan Gohman
committed
[(alignedstore (v4f32 VR128:$src), addr:$dst)]>;
def MOVUPSrr : PSI<0x10, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src),
"movups {$src, $dst|$dst, $src}", []>;
def MOVUPSrm : PSI<0x10, MRMSrcMem, (outs VR128:$dst), (ins f128mem:$src),
"movups {$src, $dst|$dst, $src}",
Dan Gohman
committed
[(set VR128:$dst, (loadv4f32 addr:$src))]>;
def MOVUPSmr : PSI<0x11, MRMDestMem, (outs), (ins f128mem:$dst, VR128:$src),
"movups {$src, $dst|$dst, $src}",
Dan Gohman
committed
[(store (v4f32 VR128:$src), addr:$dst)]>;
// Intrinsic forms of MOVUPS load and store
def MOVUPSrm_Int : PSI<0x10, MRMSrcMem, (outs VR128:$dst), (ins f128mem:$src),
Dan Gohman
committed
"movups {$src, $dst|$dst, $src}",
[(set VR128:$dst, (int_x86_sse_loadu_ps addr:$src))]>;
def MOVUPSmr_Int : PSI<0x11, MRMDestMem, (outs), (ins f128mem:$dst, VR128:$src),
Dan Gohman
committed
"movups {$src, $dst|$dst, $src}",
[(int_x86_sse_storeu_ps addr:$dst, VR128:$src)]>;
let isTwoAddress = 1 in {
let AddedComplexity = 20 in {
def MOVLPSrm : PSI<0x12, MRMSrcMem,
(outs VR128:$dst), (ins VR128:$src1, f64mem:$src2),
"movlps {$src2, $dst|$dst, $src2}",
[(set VR128:$dst,
(v4f32 (vector_shuffle VR128:$src1,
(bc_v4f32 (v2f64 (scalar_to_vector (loadf64 addr:$src2)))),
MOVLP_shuffle_mask)))]>;
def MOVHPSrm : PSI<0x16, MRMSrcMem,
(outs VR128:$dst), (ins VR128:$src1, f64mem:$src2),
"movhps {$src2, $dst|$dst, $src2}",
[(set VR128:$dst,
(v4f32 (vector_shuffle VR128:$src1,
(bc_v4f32 (v2f64 (scalar_to_vector (loadf64 addr:$src2)))),
MOVHP_shuffle_mask)))]>;
} // AddedComplexity
} // isTwoAddress
def MOVLPSmr : PSI<0x13, MRMDestMem, (outs), (ins f64mem:$dst, VR128:$src),
"movlps {$src, $dst|$dst, $src}",
[(store (f64 (vector_extract (bc_v2f64 (v4f32 VR128:$src)),
(iPTR 0))), addr:$dst)]>;
// v2f64 extract element 1 is always custom lowered to unpack high to low
// and extract element 0 so the non-store version isn't too horrible.
def MOVHPSmr : PSI<0x17, MRMDestMem, (outs), (ins f64mem:$dst, VR128:$src),
"movhps {$src, $dst|$dst, $src}",
[(store (f64 (vector_extract
(v2f64 (vector_shuffle
(bc_v2f64 (v4f32 VR128:$src)), (undef),
UNPCKH_shuffle_mask)), (iPTR 0))),
addr:$dst)]>;
let isTwoAddress = 1 in {
let AddedComplexity = 15 in {
def MOVLHPSrr : PSI<0x16, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src1, VR128:$src2),
"movlhps {$src2, $dst|$dst, $src2}",
[(set VR128:$dst,
(v4f32 (vector_shuffle VR128:$src1, VR128:$src2,
MOVHP_shuffle_mask)))]>;
def MOVHLPSrr : PSI<0x12, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src1, VR128:$src2),
"movhlps {$src2, $dst|$dst, $src2}",
[(set VR128:$dst,
(v4f32 (vector_shuffle VR128:$src1, VR128:$src2,
MOVHLPS_shuffle_mask)))]>;
} // AddedComplexity
} // isTwoAddress
// Arithmetic
/// sse1_fp_unop_rm - SSE1 unops come in both scalar and vector forms.
///
/// In addition, we also have a special variant of the scalar form here to
/// represent the associated intrinsic operation. This form is unlike the
/// plain scalar form, in that it takes an entire vector (instead of a
/// scalar) and leaves the top elements undefined.
///
/// And, we have a special variant form for a full-vector intrinsic form.
///
/// These four forms can each have a reg or a mem operand, so there are a
/// total of eight "instructions".
///
multiclass sse1_fp_unop_rm<bits<8> opc, string OpcodeStr,
SDNode OpNode,
Intrinsic F32Int,
Intrinsic V4F32Int,
bit Commutable = 0> {
// Scalar operation, reg.
def SSr : SSI<opc, MRMSrcReg, (outs FR32:$dst), (ins FR32:$src),
!strconcat(OpcodeStr, "ss {$src, $dst|$dst, $src}"),
[(set FR32:$dst, (OpNode FR32:$src))]> {
let isCommutable = Commutable;
}
// Scalar operation, mem.
def SSm : SSI<opc, MRMSrcMem, (outs FR32:$dst), (ins f32mem:$src),
!strconcat(OpcodeStr, "ss {$src, $dst|$dst, $src}"),
[(set FR32:$dst, (OpNode (load addr:$src)))]>;
// Vector operation, reg.
def PSr : PSI<opc, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src),
!strconcat(OpcodeStr, "ps {$src, $dst|$dst, $src}"),
[(set VR128:$dst, (v4f32 (OpNode VR128:$src)))]> {
let isCommutable = Commutable;
}
// Vector operation, mem.
def PSm : PSI<opc, MRMSrcMem, (outs VR128:$dst), (ins f128mem:$src),
!strconcat(OpcodeStr, "ps {$src, $dst|$dst, $src}"),
Dan Gohman
committed
[(set VR128:$dst, (OpNode (memopv4f32 addr:$src)))]>;
// Intrinsic operation, reg.
def SSr_Int : SSI<opc, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src),
!strconcat(OpcodeStr, "ss {$src, $dst|$dst, $src}"),
[(set VR128:$dst, (F32Int VR128:$src))]> {
let isCommutable = Commutable;
}
// Intrinsic operation, mem.
def SSm_Int : SSI<opc, MRMSrcMem, (outs VR128:$dst), (ins ssmem:$src),
!strconcat(OpcodeStr, "ss {$src, $dst|$dst, $src}"),
[(set VR128:$dst, (F32Int sse_load_f32:$src))]>;
// Vector intrinsic operation, reg
def PSr_Int : PSI<opc, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src),
!strconcat(OpcodeStr, "ps {$src, $dst|$dst, $src}"),
[(set VR128:$dst, (V4F32Int VR128:$src))]> {
let isCommutable = Commutable;
}
// Vector intrinsic operation, mem
def PSm_Int : PSI<opc, MRMSrcMem, (outs VR128:$dst), (ins f32mem:$src),
!strconcat(OpcodeStr, "ps {$src, $dst|$dst, $src}"),
[(set VR128:$dst, (V4F32Int (load addr:$src)))]>;
}
// Square root.
defm SQRT : sse1_fp_unop_rm<0x51, "sqrt", fsqrt,
int_x86_sse_sqrt_ss, int_x86_sse_sqrt_ps>;
// Reciprocal approximations. Note that these typically require refinement
// in order to obtain suitable precision.
defm RSQRT : sse1_fp_unop_rm<0x52, "rsqrt", X86frsqrt,
int_x86_sse_rsqrt_ss, int_x86_sse_rsqrt_ps>;
defm RCP : sse1_fp_unop_rm<0x53, "rcp", X86frcp,
int_x86_sse_rcp_ss, int_x86_sse_rcp_ps>;
// Logical
let isTwoAddress = 1 in {
let isCommutable = 1 in {
def ANDPSrr : PSI<0x54, MRMSrcReg,
(outs VR128:$dst), (ins VR128:$src1, VR128:$src2),
"andps {$src2, $dst|$dst, $src2}",
[(set VR128:$dst, (v2i64
(and VR128:$src1, VR128:$src2)))]>;
def ORPSrr : PSI<0x56, MRMSrcReg,
(outs VR128:$dst), (ins VR128:$src1, VR128:$src2),
"orps {$src2, $dst|$dst, $src2}",
[(set VR128:$dst, (v2i64
(or VR128:$src1, VR128:$src2)))]>;
def XORPSrr : PSI<0x57, MRMSrcReg,
(outs VR128:$dst), (ins VR128:$src1, VR128:$src2),
"xorps {$src2, $dst|$dst, $src2}",
[(set VR128:$dst, (v2i64
(xor VR128:$src1, VR128:$src2)))]>;
}
def ANDPSrm : PSI<0x54, MRMSrcMem,
(outs VR128:$dst), (ins VR128:$src1, f128mem:$src2),
"andps {$src2, $dst|$dst, $src2}",
Evan Cheng
committed
[(set VR128:$dst, (and (bc_v2i64 (v4f32 VR128:$src1)),
(memopv2i64 addr:$src2)))]>;
def ORPSrm : PSI<0x56, MRMSrcMem,
(outs VR128:$dst), (ins VR128:$src1, f128mem:$src2),
"orps {$src2, $dst|$dst, $src2}",
Evan Cheng
committed
[(set VR128:$dst, (or (bc_v2i64 (v4f32 VR128:$src1)),
(memopv2i64 addr:$src2)))]>;
def XORPSrm : PSI<0x57, MRMSrcMem,
(outs VR128:$dst), (ins VR128:$src1, f128mem:$src2),
"xorps {$src2, $dst|$dst, $src2}",
Evan Cheng
committed
[(set VR128:$dst, (xor (bc_v2i64 (v4f32 VR128:$src1)),
(memopv2i64 addr:$src2)))]>;
def ANDNPSrr : PSI<0x55, MRMSrcReg,
(outs VR128:$dst), (ins VR128:$src1, VR128:$src2),
"andnps {$src2, $dst|$dst, $src2}",
[(set VR128:$dst,
(v2i64 (and (xor VR128:$src1,
(bc_v2i64 (v4i32 immAllOnesV))),
VR128:$src2)))]>;
def ANDNPSrm : PSI<0x55, MRMSrcMem,
(outs VR128:$dst), (ins VR128:$src1,f128mem:$src2),
"andnps {$src2, $dst|$dst, $src2}",
[(set VR128:$dst,
Evan Cheng
committed
(v2i64 (and (xor (bc_v2i64 (v4f32 VR128:$src1)),
(bc_v2i64 (v4i32 immAllOnesV))),
Evan Cheng
committed
(memopv2i64 addr:$src2))))]>;
}
let isTwoAddress = 1 in {
def CMPPSrri : PSIi8<0xC2, MRMSrcReg,
(outs VR128:$dst), (ins VR128:$src1, VR128:$src, SSECC:$cc),
"cmp${cc}ps {$src, $dst|$dst, $src}",
[(set VR128:$dst, (int_x86_sse_cmp_ps VR128:$src1,
VR128:$src, imm:$cc))]>;
def CMPPSrmi : PSIi8<0xC2, MRMSrcMem,
(outs VR128:$dst), (ins VR128:$src1, f128mem:$src, SSECC:$cc),
"cmp${cc}ps {$src, $dst|$dst, $src}",
[(set VR128:$dst, (int_x86_sse_cmp_ps VR128:$src1,
(load addr:$src), imm:$cc))]>;
}
// Shuffle and unpack instructions
let isTwoAddress = 1 in {
let isConvertibleToThreeAddress = 1 in // Convert to pshufd
def SHUFPSrri : PSIi8<0xC6, MRMSrcReg,
(outs VR128:$dst), (ins VR128:$src1,
VR128:$src2, i32i8imm:$src3),
"shufps {$src3, $src2, $dst|$dst, $src2, $src3}",
[(set VR128:$dst,
(v4f32 (vector_shuffle
VR128:$src1, VR128:$src2,
SHUFP_shuffle_mask:$src3)))]>;
def SHUFPSrmi : PSIi8<0xC6, MRMSrcMem,
(outs VR128:$dst), (ins VR128:$src1,
f128mem:$src2, i32i8imm:$src3),
"shufps {$src3, $src2, $dst|$dst, $src2, $src3}",
[(set VR128:$dst,
(v4f32 (vector_shuffle
VR128:$src1, (load addr:$src2),
SHUFP_shuffle_mask:$src3)))]>;
let AddedComplexity = 10 in {
def UNPCKHPSrr : PSI<0x15, MRMSrcReg,
(outs VR128:$dst), (ins VR128:$src1, VR128:$src2),
"unpckhps {$src2, $dst|$dst, $src2}",
[(set VR128:$dst,
(v4f32 (vector_shuffle
VR128:$src1, VR128:$src2,
UNPCKH_shuffle_mask)))]>;
def UNPCKHPSrm : PSI<0x15, MRMSrcMem,
(outs VR128:$dst), (ins VR128:$src1, f128mem:$src2),
"unpckhps {$src2, $dst|$dst, $src2}",
[(set VR128:$dst,
(v4f32 (vector_shuffle
VR128:$src1, (load addr:$src2),
UNPCKH_shuffle_mask)))]>;
def UNPCKLPSrr : PSI<0x14, MRMSrcReg,
(outs VR128:$dst), (ins VR128:$src1, VR128:$src2),
"unpcklps {$src2, $dst|$dst, $src2}",
[(set VR128:$dst,
(v4f32 (vector_shuffle
VR128:$src1, VR128:$src2,
UNPCKL_shuffle_mask)))]>;
def UNPCKLPSrm : PSI<0x14, MRMSrcMem,
(outs VR128:$dst), (ins VR128:$src1, f128mem:$src2),
"unpcklps {$src2, $dst|$dst, $src2}",
[(set VR128:$dst,
(v4f32 (vector_shuffle
VR128:$src1, (load addr:$src2),
UNPCKL_shuffle_mask)))]>;
} // AddedComplexity
} // isTwoAddress
// Mask creation
def MOVMSKPSrr : PSI<0x50, MRMSrcReg, (outs GR32:$dst), (ins VR128:$src),
"movmskps {$src, $dst|$dst, $src}",
[(set GR32:$dst, (int_x86_sse_movmsk_ps VR128:$src))]>;
def MOVMSKPDrr : PSI<0x50, MRMSrcReg, (outs GR32:$dst), (ins VR128:$src),
"movmskpd {$src, $dst|$dst, $src}",
[(set GR32:$dst, (int_x86_sse2_movmsk_pd VR128:$src))]>;
// Prefetching loads.
// TODO: no intrinsics for these?
def PREFETCHT0 : PSI<0x18, MRM1m, (outs), (ins i8mem:$src), "prefetcht0 $src", []>;
def PREFETCHT1 : PSI<0x18, MRM2m, (outs), (ins i8mem:$src), "prefetcht1 $src", []>;
def PREFETCHT2 : PSI<0x18, MRM3m, (outs), (ins i8mem:$src), "prefetcht2 $src", []>;
def PREFETCHNTA : PSI<0x18, MRM0m, (outs), (ins i8mem:$src), "prefetchnta $src", []>;
// Non-temporal stores
def MOVNTPSmr : PSI<0x2B, MRMDestMem, (outs), (ins i128mem:$dst, VR128:$src),
"movntps {$src, $dst|$dst, $src}",
[(int_x86_sse_movnt_ps addr:$dst, VR128:$src)]>;
// Load, store, and memory fence
def SFENCE : PSI<0xAE, MRM7m, (outs), (ins), "sfence", [(int_x86_sse_sfence)]>;
// MXCSR register
def LDMXCSR : PSI<0xAE, MRM2m, (outs), (ins i32mem:$src),
"ldmxcsr $src", [(int_x86_sse_ldmxcsr addr:$src)]>;
def STMXCSR : PSI<0xAE, MRM3m, (outs), (ins i32mem:$dst),
"stmxcsr $dst", [(int_x86_sse_stmxcsr addr:$dst)]>;
// Alias instructions that map zero vector to pxor / xorp* for sse.
// FIXME: remove when we can teach regalloc that xor reg, reg is ok.
let isReMaterializable = 1 in
def V_SET0 : PSI<0x57, MRMInitReg, (outs VR128:$dst), (ins),
"xorps $dst, $dst",
[(set VR128:$dst, (v4f32 immAllZerosV))]>;
// FR32 to 128-bit vector conversion.
def MOVSS2PSrr : SSI<0x10, MRMSrcReg, (outs VR128:$dst), (ins FR32:$src),
"movss {$src, $dst|$dst, $src}",
[(set VR128:$dst,
(v4f32 (scalar_to_vector FR32:$src)))]>;
def MOVSS2PSrm : SSI<0x10, MRMSrcMem, (outs VR128:$dst), (ins f32mem:$src),
"movss {$src, $dst|$dst, $src}",
[(set VR128:$dst,
(v4f32 (scalar_to_vector (loadf32 addr:$src))))]>;
// FIXME: may not be able to eliminate this movss with coalescing the src and
// dest register classes are different. We really want to write this pattern
// like this:
// def : Pat<(f32 (vector_extract (v4f32 VR128:$src), (iPTR 0))),
// (f32 FR32:$src)>;
def MOVPS2SSrr : SSI<0x10, MRMSrcReg, (outs FR32:$dst), (ins VR128:$src),
"movss {$src, $dst|$dst, $src}",
[(set FR32:$dst, (vector_extract (v4f32 VR128:$src),
(iPTR 0)))]>;
def MOVPS2SSmr : SSI<0x11, MRMDestMem, (outs), (ins f32mem:$dst, VR128:$src),
"movss {$src, $dst|$dst, $src}",
[(store (f32 (vector_extract (v4f32 VR128:$src),
(iPTR 0))), addr:$dst)]>;
// Move to lower bits of a VR128, leaving upper bits alone.
// Three operand (but two address) aliases.
let isTwoAddress = 1 in {
def MOVLSS2PSrr : SSI<0x10, MRMSrcReg,
(outs VR128:$dst), (ins VR128:$src1, FR32:$src2),
"movss {$src2, $dst|$dst, $src2}", []>;
let AddedComplexity = 15 in
def MOVLPSrr : SSI<0x10, MRMSrcReg,
(outs VR128:$dst), (ins VR128:$src1, VR128:$src2),
"movss {$src2, $dst|$dst, $src2}",
[(set VR128:$dst,
(v4f32 (vector_shuffle VR128:$src1, VR128:$src2,
MOVL_shuffle_mask)))]>;
}
// Move to lower bits of a VR128 and zeroing upper bits.
// Loading from memory automatically zeroing upper bits.
let AddedComplexity = 20 in
def MOVZSS2PSrm : SSI<0x10, MRMSrcMem, (outs VR128:$dst), (ins f32mem:$src),
"movss {$src, $dst|$dst, $src}",
[(set VR128:$dst, (v4f32 (vector_shuffle immAllZerosV,
(v4f32 (scalar_to_vector (loadf32 addr:$src))),
MOVL_shuffle_mask)))]>;
//===----------------------------------------------------------------------===//
// SSE2 Instructions
//===----------------------------------------------------------------------===//
// SSE2 Instruction Templates:
//
// SDI - SSE2 instructions with XD prefix.
// PDI - SSE2 instructions with TB and OpSize prefixes.
// PDIi8 - SSE2 instructions with ImmT == Imm8 and TB and OpSize prefixes.
class SDI<bits<8> o, Format F, dag outs, dag ins, string asm, list<dag> pattern>
: I<o, F, outs, ins, asm, pattern>, XD, Requires<[HasSSE2]>;
class PDI<bits<8> o, Format F, dag outs, dag ins, string asm, list<dag> pattern>
: I<o, F, outs, ins, asm, pattern>, TB, OpSize, Requires<[HasSSE2]>;
class PDIi8<bits<8> o, Format F, dag outs, dag ins, string asm,
list<dag> pattern>
: Ii8<o, F, outs, ins, asm, pattern>, TB, OpSize, Requires<[HasSSE2]>;
// Move Instructions
def MOVSDrr : SDI<0x10, MRMSrcReg, (outs FR64:$dst), (ins FR64:$src),
"movsd {$src, $dst|$dst, $src}", []>;
def MOVSDrm : SDI<0x10, MRMSrcMem, (outs FR64:$dst), (ins f64mem:$src),
"movsd {$src, $dst|$dst, $src}",
[(set FR64:$dst, (loadf64 addr:$src))]>;
def MOVSDmr : SDI<0x11, MRMDestMem, (outs), (ins f64mem:$dst, FR64:$src),
"movsd {$src, $dst|$dst, $src}",
[(store FR64:$src, addr:$dst)]>;
// Conversion instructions
def CVTTSD2SIrr : SDI<0x2C, MRMSrcReg, (outs GR32:$dst), (ins FR64:$src),
"cvttsd2si {$src, $dst|$dst, $src}",
[(set GR32:$dst, (fp_to_sint FR64:$src))]>;
def CVTTSD2SIrm : SDI<0x2C, MRMSrcMem, (outs GR32:$dst), (ins f64mem:$src),
"cvttsd2si {$src, $dst|$dst, $src}",
[(set GR32:$dst, (fp_to_sint (loadf64 addr:$src)))]>;
def CVTSD2SSrr : SDI<0x5A, MRMSrcReg, (outs FR32:$dst), (ins FR64:$src),
"cvtsd2ss {$src, $dst|$dst, $src}",
[(set FR32:$dst, (fround FR64:$src))]>;
def CVTSD2SSrm : SDI<0x5A, MRMSrcMem, (outs FR32:$dst), (ins f64mem:$src),
"cvtsd2ss {$src, $dst|$dst, $src}",
[(set FR32:$dst, (fround (loadf64 addr:$src)))]>;
def CVTSI2SDrr : SDI<0x2A, MRMSrcReg, (outs FR64:$dst), (ins GR32:$src),
"cvtsi2sd {$src, $dst|$dst, $src}",
[(set FR64:$dst, (sint_to_fp GR32:$src))]>;
def CVTSI2SDrm : SDI<0x2A, MRMSrcMem, (outs FR64:$dst), (ins i32mem:$src),
"cvtsi2sd {$src, $dst|$dst, $src}",
[(set FR64:$dst, (sint_to_fp (loadi32 addr:$src)))]>;
// SSE2 instructions with XS prefix
def CVTSS2SDrr : I<0x5A, MRMSrcReg, (outs FR64:$dst), (ins FR32:$src),
"cvtss2sd {$src, $dst|$dst, $src}",
[(set FR64:$dst, (fextend FR32:$src))]>, XS,
Requires<[HasSSE2]>;
def CVTSS2SDrm : I<0x5A, MRMSrcMem, (outs FR64:$dst), (ins f32mem:$src),